aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Internal
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Internal')
-rw-r--r--source/ShiftUI/Internal/ApplicationHandler.cs78
-rw-r--r--source/ShiftUI/Internal/ArrangedElementCollection.cs173
-rw-r--r--source/ShiftUI/Internal/AsyncMethodData.cs41
-rw-r--r--source/ShiftUI/Internal/AsyncMethodResult.cs108
-rw-r--r--source/ShiftUI/Internal/AutoCompleteSource.cs44
-rw-r--r--source/ShiftUI/Internal/AutoCompleteStringCollection.cs203
-rw-r--r--source/ShiftUI/Internal/BaseCollection.cs99
-rw-r--r--source/ShiftUI/Internal/Binding.cs578
-rw-r--r--source/ShiftUI/Internal/BindingCompleteContext.cs37
-rw-r--r--source/ShiftUI/Internal/BindingContext.cs257
-rw-r--r--source/ShiftUI/Internal/BindingManagerBase.cs204
-rw-r--r--source/ShiftUI/Internal/BindingMemberInfo.cs107
-rw-r--r--source/ShiftUI/Internal/BindingsCollection.cs136
-rw-r--r--source/ShiftUI/Internal/BootMode.cs39
-rw-r--r--source/ShiftUI/Internal/BoundsSpecified.cs43
-rw-r--r--source/ShiftUI/Internal/ButtonBase.cs747
-rw-r--r--source/ShiftUI/Internal/ButtonRenderer.cs153
-rw-r--r--source/ShiftUI/Internal/CheckBoxRenderer.cs194
-rw-r--r--source/ShiftUI/Internal/Clipboard.cs433
-rw-r--r--source/ShiftUI/Internal/Consts.cs0
-rw-r--r--source/ShiftUI/Internal/ContextMenuStrip.cs80
-rw-r--r--source/ShiftUI/Internal/ControlBindingsCollection.cs204
-rw-r--r--source/ShiftUI/Internal/ControlEventArgs.cs49
-rw-r--r--source/ShiftUI/Internal/ControlEventHandler.cs32
-rw-r--r--source/ShiftUI/Internal/ControlHandler.cs229
-rw-r--r--source/ShiftUI/Internal/ControlPaint.cs495
-rw-r--r--source/ShiftUI/Internal/CurrencyManager.cs453
-rw-r--r--source/ShiftUI/Internal/Cursor.cs245
-rw-r--r--source/ShiftUI/Internal/CursorConverter.cs126
-rw-r--r--source/ShiftUI/Internal/Cursors.cs365
-rw-r--r--source/ShiftUI/Internal/DataObject.cs485
-rw-r--r--source/ShiftUI/Internal/Day.cs39
-rw-r--r--source/ShiftUI/Internal/DebugHelper.cs257
-rw-r--r--source/ShiftUI/Internal/DefaultLayout.cs290
-rw-r--r--source/ShiftUI/Internal/Dnd.cs371
-rw-r--r--source/ShiftUI/Internal/DockingAttribute.cs74
-rw-r--r--source/ShiftUI/Internal/DockingBehavior.cs38
-rw-r--r--source/ShiftUI/Internal/DrawToolTipEventArgs.cs113
-rw-r--r--source/ShiftUI/Internal/DrawToolTipEventHandler.cs31
-rw-r--r--source/ShiftUI/Internal/Enums.cs108
-rw-r--r--source/ShiftUI/Internal/EventHandler.cs184
-rw-r--r--source/ShiftUI/Internal/EventHandlerBase.cs40
-rw-r--r--source/ShiftUI/Internal/FixedSizeTextBox.cs47
-rw-r--r--source/ShiftUI/Internal/FlowLayout.cs589
-rw-r--r--source/ShiftUI/Internal/FlowLayoutSettings.cs111
-rw-r--r--source/ShiftUI/Internal/GetChildAtPointSkip.cs41
-rw-r--r--source/ShiftUI/Internal/GridItem.cs114
-rw-r--r--source/ShiftUI/Internal/GridItemType.cs38
-rw-r--r--source/ShiftUI/Internal/GroupBoxRenderer.cs157
-rw-r--r--source/ShiftUI/Internal/HIObjectHandler.cs57
-rw-r--r--source/ShiftUI/Internal/HScrollProperties.cs33
-rw-r--r--source/ShiftUI/Internal/Hwnd.cs910
-rw-r--r--source/ShiftUI/Internal/IBindableComponent.cs34
-rw-r--r--source/ShiftUI/Internal/IBounds.cs40
-rw-r--r--source/ShiftUI/Internal/IButtonControl.cs40
-rw-r--r--source/ShiftUI/Internal/ICommandExecutor.cs34
-rw-r--r--source/ShiftUI/Internal/IComponentEditorPageSite.cs34
-rw-r--r--source/ShiftUI/Internal/IContainerControl.cs39
-rw-r--r--source/ShiftUI/Internal/ICurrencyManagerProvider.cs32
-rw-r--r--source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs35
-rw-r--r--source/ShiftUI/Internal/IDataGridEditingService.cs36
-rw-r--r--source/ShiftUI/Internal/IDataGridViewEditingCell.cs41
-rw-r--r--source/ShiftUI/Internal/IDataGridViewEditingControl.cs53
-rw-r--r--source/ShiftUI/Internal/IDataObject.cs54
-rw-r--r--source/ShiftUI/Internal/IDropTarget.cs36
-rw-r--r--source/ShiftUI/Internal/IEventHandler.cs33
-rw-r--r--source/ShiftUI/Internal/IFeatureSupport.cs38
-rw-r--r--source/ShiftUI/Internal/IFileReaderService.cs37
-rw-r--r--source/ShiftUI/Internal/IKeyFilter.cs32
-rw-r--r--source/ShiftUI/Internal/IMessageFilter.cs34
-rw-r--r--source/ShiftUI/Internal/IToolStripData.cs41
-rw-r--r--source/ShiftUI/Internal/IWin32Window.cs44
-rw-r--r--source/ShiftUI/Internal/IWindowTarget.cs34
-rw-r--r--source/ShiftUI/Internal/ImageIndexConverter.cs102
-rw-r--r--source/ShiftUI/Internal/ImageKeyConverter.cs97
-rw-r--r--source/ShiftUI/Internal/ImageList.cs1073
-rw-r--r--source/ShiftUI/Internal/ImageListConverter.cs44
-rw-r--r--source/ShiftUI/Internal/ImageListStreamer.cs338
-rw-r--r--source/ShiftUI/Internal/InternalWindowManager.cs1211
-rw-r--r--source/ShiftUI/Internal/KeyboardHandler.cs329
-rw-r--r--source/ShiftUI/Internal/KeysConverter.cs139
-rw-r--r--source/ShiftUI/Internal/LayoutEngine.cs43
-rw-r--r--source/ShiftUI/Internal/LayoutSettings.cs40
-rw-r--r--source/ShiftUI/Internal/Line.cs811
-rw-r--r--source/ShiftUI/Internal/LineTag.cs618
-rw-r--r--source/ShiftUI/Internal/ListBindingConverter.cs60
-rw-r--r--source/ShiftUI/Internal/ListBindingHelper.cs189
-rw-r--r--source/ShiftUI/Internal/MONO-NOTES28
-rw-r--r--source/ShiftUI/Internal/MONO-TODO112
-rw-r--r--source/ShiftUI/Internal/MWFCategoryAttribute.cs50
-rw-r--r--source/ShiftUI/Internal/MWFDescriptionAttribute.cs51
-rw-r--r--source/ShiftUI/Internal/MainMenu.cs216
-rw-r--r--source/ShiftUI/Internal/MdiClient.cs1003
-rw-r--r--source/ShiftUI/Internal/MdiControlStrip.cs207
-rw-r--r--source/ShiftUI/Internal/MdiLayout.cs36
-rw-r--r--source/ShiftUI/Internal/MdiWindowManager.cs624
-rw-r--r--source/ShiftUI/Internal/Message.cs118
-rw-r--r--source/ShiftUI/Internal/MethodInvoker.cs31
-rw-r--r--source/ShiftUI/Internal/MouseHandler.cs228
-rw-r--r--source/ShiftUI/Internal/NativeWindow.cs324
-rw-r--r--source/ShiftUI/Internal/OpacityConverter.cs74
-rw-r--r--source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs112
-rw-r--r--source/ShiftUI/Internal/OwnerDrawPropertyBag.cs101
-rw-r--r--source/ShiftUI/Internal/Padding.cs170
-rw-r--r--source/ShiftUI/Internal/PaddingConverter.cs125
-rw-r--r--source/ShiftUI/Internal/PaintEventArgs.cs98
-rw-r--r--source/ShiftUI/Internal/PaintEventHandler.cs33
-rw-r--r--source/ShiftUI/Internal/Pasteboard.cs106
-rw-r--r--source/ShiftUI/Internal/PopupEventArgs.cs71
-rw-r--r--source/ShiftUI/Internal/PopupEventHandler.cs32
-rw-r--r--source/ShiftUI/Internal/PreProcessControlState.cs38
-rw-r--r--source/ShiftUI/Internal/ProfessionalColorTable.cs654
-rw-r--r--source/ShiftUI/Internal/PropertyManager.cs166
-rw-r--r--source/ShiftUI/Internal/PropertySort.cs40
-rw-r--r--source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs66
-rw-r--r--source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs33
-rw-r--r--source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs66
-rw-r--r--source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs31
-rw-r--r--source/ShiftUI/Internal/RadioButtonRenderer.cs182
-rw-r--r--source/ShiftUI/Internal/RelatedCurrencyManager.cs54
-rw-r--r--source/ShiftUI/Internal/RelatedImageListAttribute.cs48
-rw-r--r--source/ShiftUI/Internal/RelatedPropertyManager.cs67
-rw-r--r--source/ShiftUI/Internal/RichTextBoxFinds.cs39
-rw-r--r--source/ShiftUI/Internal/RichTextBoxScrollBars.cs39
-rw-r--r--source/ShiftUI/Internal/SUI_NOTES.txt3
-rw-r--r--source/ShiftUI/Internal/Screen.cs221
-rw-r--r--source/ShiftUI/Internal/ScrollProperties.cs97
-rw-r--r--source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs65
-rw-r--r--source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs31
-rw-r--r--source/ShiftUI/Internal/SelectionRangeConverter.cs110
-rw-r--r--source/ShiftUI/Internal/Splitter.cs707
-rw-r--r--source/ShiftUI/Internal/Structs.cs157
-rw-r--r--source/ShiftUI/Internal/SystemInformation.cs611
-rw-r--r--source/ShiftUI/Internal/SystemParameter.cs49
-rw-r--r--source/ShiftUI/Internal/TableLayout.cs603
-rw-r--r--source/ShiftUI/Internal/TableLayoutSettings.cs362
-rw-r--r--source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs233
-rw-r--r--source/ShiftUI/Internal/TextBoxTextRenderer.cs131
-rw-r--r--source/ShiftUI/Internal/TextControl.cs4613
-rw-r--r--source/ShiftUI/Internal/TextFormatFlags.cs62
-rw-r--r--source/ShiftUI/Internal/TextRenderer.cs527
-rw-r--r--source/ShiftUI/Internal/Theme.cs1063
-rw-r--r--source/ShiftUI/Internal/Timer.cs170
-rw-r--r--source/ShiftUI/Internal/ToolBarAppearance.cs40
-rw-r--r--source/ShiftUI/Internal/ToolBarButtonStyle.cs41
-rw-r--r--source/ShiftUI/Internal/ToolBarTextAlign.cs39
-rw-r--r--source/ShiftUI/Internal/ToolTip.cs1004
-rw-r--r--source/ShiftUI/Internal/ToolTipIcon.cs39
-rw-r--r--source/ShiftUI/Internal/ToolWindowManager.cs47
-rw-r--r--source/ShiftUI/Internal/TreeNodeCollection.cs611
-rw-r--r--source/ShiftUI/Internal/TreeNodeConverter.cs55
-rw-r--r--source/ShiftUI/Internal/TreeViewHitTestInfo.cs51
-rw-r--r--source/ShiftUI/Internal/TreeViewImageIndexConverter.cs89
-rw-r--r--source/ShiftUI/Internal/TreeViewImageKeyConverter.cs51
-rw-r--r--source/ShiftUI/Internal/VScrollProperties.cs33
-rw-r--r--source/ShiftUI/Internal/Win32DnD.cs1081
-rw-r--r--source/ShiftUI/Internal/WindowHandler.cs235
-rw-r--r--source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs94
-rw-r--r--source/ShiftUI/Internal/X11Atoms.cs329
-rw-r--r--source/ShiftUI/Internal/X11Clipboard.cs105
-rw-r--r--source/ShiftUI/Internal/X11DesktopColors.cs298
-rw-r--r--source/ShiftUI/Internal/X11Display.cs2693
-rw-r--r--source/ShiftUI/Internal/X11Dnd.cs1421
-rw-r--r--source/ShiftUI/Internal/X11Exception.cs87
-rw-r--r--source/ShiftUI/Internal/X11Hwnd.cs1750
-rw-r--r--source/ShiftUI/Internal/X11Keyboard.cs1478
-rw-r--r--source/ShiftUI/Internal/X11RootHwnd.cs87
-rw-r--r--source/ShiftUI/Internal/X11Structs.cs1824
-rw-r--r--source/ShiftUI/Internal/X11ThreadQueue.cs502
-rw-r--r--source/ShiftUI/Internal/XEventQueue.cs261
-rw-r--r--source/ShiftUI/Internal/Xlib.cs350
-rw-r--r--source/ShiftUI/Internal/XplatUI.cs1235
-rw-r--r--source/ShiftUI/Internal/XplatUICarbon.cs2432
-rw-r--r--source/ShiftUI/Internal/XplatUICosmos.cs2916
-rw-r--r--source/ShiftUI/Internal/XplatUIDriver.cs532
-rw-r--r--source/ShiftUI/Internal/XplatUIStructs.cs1042
-rw-r--r--source/ShiftUI/Internal/XplatUIWin32.cs3751
-rw-r--r--source/ShiftUI/Internal/XplatUIX11-new.cs1079
-rw-r--r--source/ShiftUI/Internal/XplatUIX11.cs7687
-rw-r--r--source/ShiftUI/Internal/XplatUIX11GTK.cs4634
180 files changed, 71265 insertions, 0 deletions
diff --git a/source/ShiftUI/Internal/ApplicationHandler.cs b/source/ShiftUI/Internal/ApplicationHandler.cs
new file mode 100644
index 0000000..df7d3d6
--- /dev/null
+++ b/source/ShiftUI/Internal/ApplicationHandler.cs
@@ -0,0 +1,78 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+
+namespace ShiftUI.CarbonInternal {
+ internal class ApplicationHandler : EventHandlerBase, IEventHandler {
+ internal const uint kEventAppActivated = 1;
+ internal const uint kEventAppDeactivated = 2;
+ internal const uint kEventAppQuit = 3;
+ internal const uint kEventAppLaunchNotification = 4;
+ internal const uint kEventAppLaunched = 5;
+ internal const uint kEventAppTerminated = 6;
+ internal const uint kEventAppFrontSwitched = 7;
+ internal const uint kEventAppFocusMenuBar = 8;
+ internal const uint kEventAppFocusNextDocumentWindow = 9;
+ internal const uint kEventAppFocusNextFloatingWindow = 10;
+ internal const uint kEventAppFocusToolbar = 11;
+ internal const uint kEventAppFocusDrawer = 12;
+ internal const uint kEventAppGetDockTileMenu = 20;
+ internal const uint kEventAppIsEventInInstantMouser = 104;
+ internal const uint kEventAppHidden = 107;
+ internal const uint kEventAppShown = 108;
+ internal const uint kEventAppSystemUIModeChanged = 109;
+ internal const uint kEventAppAvailableWindowBoundsChanged = 110;
+ internal const uint kEventAppActiveWindowChanged = 111;
+
+ internal ApplicationHandler (XplatUICarbon driver) : base (driver) {}
+
+ public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
+ switch (kind) {
+ case kEventAppActivated: {
+ foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows)
+ if (!XplatUICarbon.IsWindowVisible (utility_window))
+ XplatUICarbon.ShowWindow (utility_window);
+ break;
+ }
+ case kEventAppDeactivated: {
+ if (XplatUICarbon.FocusWindow != IntPtr.Zero) {
+ Driver.SendMessage (XplatUICarbon.FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
+ }
+ if (XplatUICarbon.Grab.Hwnd != IntPtr.Zero) {
+ Driver.SendMessage (Hwnd.ObjectFromHandle (XplatUICarbon.Grab.Hwnd).Handle, Msg.WM_LBUTTONDOWN, (IntPtr)MsgButtons.MK_LBUTTON, (IntPtr) (Driver.MousePosition.X << 16 | Driver.MousePosition.Y));
+ }
+ foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows)
+ if (XplatUICarbon.IsWindowVisible (utility_window))
+ XplatUICarbon.HideWindow (utility_window);
+ break;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/ArrangedElementCollection.cs b/source/ShiftUI/Internal/ArrangedElementCollection.cs
new file mode 100644
index 0000000..61f5e52
--- /dev/null
+++ b/source/ShiftUI/Internal/ArrangedElementCollection.cs
@@ -0,0 +1,173 @@
+//
+// ArrangedElementCollection.cs
+//
+// 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) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System.Collections;
+using System;
+
+namespace ShiftUI.Layout
+{
+ public class ArrangedElementCollection : IList, ICollection, IEnumerable
+ {
+ internal ArrayList list;
+
+ internal ArrangedElementCollection ()
+ {
+ this.list = new ArrayList ();
+ }
+
+ #region Public Properties
+ public virtual int Count { get { return list.Count; } }
+ public virtual bool IsReadOnly { get { return list.IsReadOnly; } }
+ #endregion
+
+ #region Public Methods
+ public void CopyTo (Array array, int index)
+ {
+ list.CopyTo (array, index);
+ }
+
+ public override bool Equals (object obj)
+ {
+ if (obj is ArrangedElementCollection && this == obj)
+ return (true);
+ else
+ return (false);
+ }
+
+ public virtual IEnumerator GetEnumerator ()
+ {
+ return list.GetEnumerator ();
+ }
+
+ public override int GetHashCode ()
+ {
+ return base.GetHashCode ();
+ }
+ #endregion
+
+ #region IList Members
+ int IList.Add (object value)
+ {
+ return Add (value);
+ }
+
+ internal int Add (object value)
+ {
+ return list.Add (value);
+ }
+
+ void IList.Clear ()
+ {
+ Clear ();
+ }
+
+ internal void Clear ()
+ {
+ list.Clear ();
+ }
+
+ bool IList.Contains (object value)
+ {
+ return Contains (value);
+ }
+
+ internal bool Contains (object value)
+ {
+ return list.Contains (value);
+ }
+
+ int IList.IndexOf (object value)
+ {
+ return IndexOf (value);
+ }
+
+ internal int IndexOf (object value)
+ {
+ return list.IndexOf (value);
+ }
+
+ void IList.Insert (int index, object value)
+ {
+ throw new NotSupportedException ();
+ }
+
+ internal void Insert (int index, object value)
+ {
+ list.Insert (index, value);
+ }
+
+ bool IList.IsFixedSize {
+ get { return this.IsFixedSize; }
+ }
+
+ internal bool IsFixedSize {
+ get { return list.IsFixedSize; }
+ }
+
+ void IList.Remove (object value)
+ {
+ Remove (value);
+ }
+
+ internal void Remove (object value)
+ {
+ list.Remove (value);
+ }
+
+ void IList.RemoveAt (int index)
+ {
+ list.RemoveAt (index);
+ }
+
+ internal void InternalRemoveAt (int index)
+ {
+ list.RemoveAt (index);
+ }
+
+ object IList.this[int index] {
+ get { return this[index]; }
+ set { this[index] = value; }
+ }
+
+ internal object this[int index] {
+ get { return list[index]; }
+ set { list[index] = value; }
+ }
+ #endregion
+
+ #region ICollection Members
+ bool ICollection.IsSynchronized {
+ get { return list.IsSynchronized; }
+ }
+
+ object ICollection.SyncRoot {
+ get { return list.IsSynchronized; }
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/AsyncMethodData.cs b/source/ShiftUI/Internal/AsyncMethodData.cs
new file mode 100644
index 0000000..707ce62
--- /dev/null
+++ b/source/ShiftUI/Internal/AsyncMethodData.cs
@@ -0,0 +1,41 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.Threading;
+
+
+namespace ShiftUI {
+
+ internal class AsyncMethodData {
+ public IntPtr Handle;
+ public Delegate Method;
+ public object [] Args;
+ public AsyncMethodResult Result;
+ public ExecutionContext Context;
+ public SynchronizationContext SyncContext;
+ }
+
+}
diff --git a/source/ShiftUI/Internal/AsyncMethodResult.cs b/source/ShiftUI/Internal/AsyncMethodResult.cs
new file mode 100644
index 0000000..48c480d
--- /dev/null
+++ b/source/ShiftUI/Internal/AsyncMethodResult.cs
@@ -0,0 +1,108 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.Threading;
+
+namespace ShiftUI {
+
+ internal class AsyncMethodResult : IAsyncResult {
+
+ private ManualResetEvent handle;
+ private object state;
+ private bool completed;
+ private object return_value;
+ private Exception exception;
+
+ public AsyncMethodResult ()
+ {
+ handle = new ManualResetEvent (false);
+ }
+
+ public virtual WaitHandle AsyncWaitHandle {
+ get {
+ lock (this) {
+ return handle;
+ }
+ }
+ }
+
+ public object AsyncState {
+ get { return state; }
+ set { state = value; }
+ }
+
+ public bool CompletedSynchronously {
+ get { return false; }
+ }
+
+ public bool IsCompleted {
+ get {
+ lock (this) {
+ return completed;
+ }
+ }
+ }
+
+ public object EndInvoke ()
+ {
+ lock (this) {
+ if (completed) {
+ if (exception == null)
+ return return_value;
+ else
+ throw exception;
+ }
+ }
+ handle.WaitOne ();
+
+ if (exception != null)
+ throw exception;
+
+ return return_value;
+ }
+
+ public void Complete (object result)
+ {
+ lock (this) {
+ completed = true;
+ return_value = result;
+ handle.Set ();
+ }
+ }
+
+ public void CompleteWithException (Exception ex)
+ {
+ lock (this) {
+ completed = true;
+ exception = ex;
+ handle.Set ();
+ }
+ }
+ }
+
+}
+
+
diff --git a/source/ShiftUI/Internal/AutoCompleteSource.cs b/source/ShiftUI/Internal/AutoCompleteSource.cs
new file mode 100644
index 0000000..ab2fc6a
--- /dev/null
+++ b/source/ShiftUI/Internal/AutoCompleteSource.cs
@@ -0,0 +1,44 @@
+//
+// AutoCompleteSource.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+namespace ShiftUI
+{
+ public enum AutoCompleteSource
+ {
+ FileSystem = 1,
+ HistoryList = 2,
+ RecentlyUsedList = 4,
+ AllUrl = 6,
+ AllSystemSources = 7,
+ FileSystemDirectories = 32,
+ CustomSource = 64,
+ None = 128,
+ ListItems = 256
+ }
+}
diff --git a/source/ShiftUI/Internal/AutoCompleteStringCollection.cs b/source/ShiftUI/Internal/AutoCompleteStringCollection.cs
new file mode 100644
index 0000000..2142d47
--- /dev/null
+++ b/source/ShiftUI/Internal/AutoCompleteStringCollection.cs
@@ -0,0 +1,203 @@
+//
+// AutoCompleteStringCollection.cs
+//
+// 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) 2006 Daniel Nauck
+//
+// Author:
+// Daniel Nauck (dna(at)mono-project(dot)de)
+
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Reflection;
+
+namespace ShiftUI
+{
+ public class AutoCompleteStringCollection : IList, ICollection, IEnumerable
+ {
+ private ArrayList list = null;
+
+ public AutoCompleteStringCollection ()
+ {
+ list = new ArrayList ();
+ }
+
+ public event CollectionChangeEventHandler CollectionChanged;
+
+ protected void OnCollectionChanged (CollectionChangeEventArgs e)
+ {
+ if(CollectionChanged == null)
+ return;
+
+ CollectionChanged (this, e);
+ }
+
+ #region IEnumerable Members
+
+ public IEnumerator GetEnumerator ()
+ {
+ return list.GetEnumerator ();
+ }
+
+ #endregion
+
+ #region ICollection Members
+
+ void ICollection.CopyTo (Array array, int index)
+ {
+ list.CopyTo (array, index);
+ }
+
+ public void CopyTo (string[] array, int index)
+ {
+ list.CopyTo (array, index);
+ }
+
+ public int Count
+ {
+ get { return list.Count; }
+ }
+
+ public bool IsSynchronized
+ {
+ get { return false; }
+ }
+
+ public object SyncRoot
+ {
+ get { return this; }
+ }
+
+ #endregion
+
+ #region IList Members
+
+ int IList.Add (object value)
+ {
+ return Add ((string)value);
+ }
+
+ public int Add (string value)
+ {
+ int index = list.Add (value);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
+ return index;
+ }
+
+ public void AddRange (string[] value)
+ {
+ if (value == null)
+ throw new ArgumentNullException ("value", "Argument cannot be null!");
+
+ list.AddRange (value);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
+ }
+
+ public void Clear ()
+ {
+ list.Clear ();
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
+ }
+
+ bool IList.Contains (object value)
+ {
+ return Contains ((string)value);
+ }
+
+ public bool Contains (string value)
+ {
+ return list.Contains (value);
+ }
+
+ int IList.IndexOf (object value)
+ {
+ return IndexOf ((string)value);
+ }
+
+ public int IndexOf (string value)
+ {
+ return list.IndexOf (value);
+ }
+
+ void IList.Insert (int index, object value)
+ {
+ Insert (index, (string)value);
+ }
+
+ public void Insert (int index, string value)
+ {
+ list.Insert (index, value);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
+ }
+
+ bool IList.IsFixedSize
+ {
+ get { return false; }
+ }
+
+ bool IList.IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ void IList.Remove (object value)
+ {
+ Remove((string)value);
+ }
+
+ public void Remove (string value)
+ {
+ list.Remove (value);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, value));
+ }
+
+ public void RemoveAt (int index)
+ {
+ string value = this[index];
+ list.RemoveAt (index);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, value));
+ }
+
+ object IList.this[int index]
+ {
+ get { return this[index]; }
+ set { this[index] = (string)value; }
+ }
+
+ public string this[int index]
+ {
+ get { return (string)list[index]; }
+ set {
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list[index]));
+ list[index] = value;
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
+ }
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/BaseCollection.cs b/source/ShiftUI/Internal/BaseCollection.cs
new file mode 100644
index 0000000..91b3661
--- /dev/null
+++ b/source/ShiftUI/Internal/BaseCollection.cs
@@ -0,0 +1,99 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+
+// COMPLETE
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+
+namespace ShiftUI {
+ public class BaseCollection : MarshalByRefObject, ICollection, IEnumerable {
+ internal ArrayList list;
+
+ #region Public Constructors
+ public BaseCollection ()
+ {
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ [Browsable(false)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ public virtual int Count {
+ get {
+ return List.Count;
+ }
+ }
+
+ [Browsable(false)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ public bool IsReadOnly {
+ get {
+ return false;
+ }
+ }
+
+ [Browsable(false)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ public bool IsSynchronized {
+ get {
+ return false;
+ }
+ }
+
+ [Browsable(false)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ public object SyncRoot {
+ get {
+ return this;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Protected Instance Properties
+ protected virtual ArrayList List {
+ get {
+ if (list == null)
+ list = new ArrayList ();
+ return list;
+ }
+ }
+ #endregion // Protected Instance Properties
+
+ #region Public Instance Methods
+ public void CopyTo (Array ar, int index)
+ {
+ List.CopyTo (ar, index);
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return List.GetEnumerator ();
+ }
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/Binding.cs b/source/ShiftUI/Internal/Binding.cs
new file mode 100644
index 0000000..7b6ccc7
--- /dev/null
+++ b/source/ShiftUI/Internal/Binding.cs
@@ -0,0 +1,578 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+// Jackson Harper [email protected]
+//
+
+
+using System.ComponentModel;
+using System;
+
+namespace ShiftUI {
+
+ [TypeConverter (typeof (ListBindingConverter))]
+ public class Binding {
+
+ private string property_name;
+ private object data_source;
+ private string data_member;
+
+ private bool is_binding;
+ private bool checked_isnull;
+
+ private BindingMemberInfo binding_member_info;
+ private IBindableComponent control;
+
+ private BindingManagerBase manager;
+ private PropertyDescriptor control_property;
+ private PropertyDescriptor is_null_desc;
+
+ private object data;
+ private Type data_type;
+
+ private DataSourceUpdateMode datasource_update_mode;
+ private ControlUpdateMode control_update_mode;
+ private object datasource_null_value = Convert.DBNull;
+ private object null_value;
+ private IFormatProvider format_info;
+ private string format_string;
+ private bool formatting_enabled;
+ #region Public Constructors
+ public Binding (string propertyName, object dataSource, string dataMember)
+ : this (propertyName, dataSource, dataMember, false, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, null, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo)
+ {
+ property_name = propertyName;
+ data_source = dataSource;
+ data_member = dataMember;
+ binding_member_info = new BindingMemberInfo (dataMember);
+ datasource_update_mode = dataSourceUpdateMode;
+ null_value = nullValue;
+ format_string = formatString;
+ format_info = formatInfo;
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ [DefaultValue (null)]
+ public IBindableComponent BindableComponent {
+ get {
+ return control;
+ }
+ }
+
+ public BindingManagerBase BindingManagerBase {
+ get {
+ return manager;
+ }
+ }
+
+ public BindingMemberInfo BindingMemberInfo {
+ get {
+ return binding_member_info;
+ }
+ }
+
+ [DefaultValue (null)]
+ public Widget Widget {
+ get {
+ return control as Widget;
+ }
+ }
+
+ [DefaultValue (ControlUpdateMode.OnPropertyChanged)]
+ public ControlUpdateMode ControlUpdateMode {
+ get {
+ return control_update_mode;
+ }
+ set {
+ control_update_mode = value;
+ }
+ }
+
+ public object DataSource {
+ get {
+ return data_source;
+ }
+ }
+
+ [DefaultValue (DataSourceUpdateMode.OnValidation)]
+ public DataSourceUpdateMode DataSourceUpdateMode {
+ get {
+ return datasource_update_mode;
+ }
+ set {
+ datasource_update_mode = value;
+ }
+ }
+
+ public object DataSourceNullValue {
+ get {
+ return datasource_null_value;
+ }
+ set {
+ datasource_null_value = value;
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool FormattingEnabled {
+ get {
+ return formatting_enabled;
+ }
+ set {
+ if (formatting_enabled == value)
+ return;
+
+ formatting_enabled = value;
+ PushData ();
+ }
+ }
+
+ [DefaultValue (null)]
+ public IFormatProvider FormatInfo {
+ get {
+ return format_info;
+ }
+ set {
+ if (value == format_info)
+ return;
+
+ format_info = value;
+ if (formatting_enabled)
+ PushData ();
+ }
+ }
+
+ public string FormatString {
+ get {
+ return format_string;
+ }
+ set {
+ if (value == null)
+ value = String.Empty;
+ if (value == format_string)
+ return;
+
+ format_string = value;
+ if (formatting_enabled)
+ PushData ();
+ }
+ }
+
+ public bool IsBinding {
+ get {
+ if (manager == null || manager.IsSuspended)
+ return false;
+
+ return is_binding;
+ }
+ }
+
+ public object NullValue {
+ get {
+ return null_value;
+ }
+ set {
+ if (value == null_value)
+ return;
+
+ null_value = value;
+ if (formatting_enabled)
+ PushData ();
+ }
+ }
+
+ [DefaultValue ("")]
+ public string PropertyName {
+ get {
+ return property_name;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ public void ReadValue ()
+ {
+ PushData (true);
+ }
+
+ public void WriteValue ()
+ {
+ PullData (true);
+ }
+
+ #region Protected Instance Methods
+ protected virtual void OnBindingComplete (BindingCompleteEventArgs e)
+ {
+ if (BindingComplete != null)
+ BindingComplete (this, e);
+ }
+
+ protected virtual void OnFormat (ConvertEventArgs cevent)
+ {
+ if (Format!=null)
+ Format (this, cevent);
+ }
+
+ protected virtual void OnParse (ConvertEventArgs cevent)
+ {
+ if (Parse!=null)
+ Parse (this, cevent);
+ }
+ #endregion // Protected Instance Methods
+
+ internal string DataMember {
+ get { return data_member; }
+ }
+
+ internal void SetWidget (IBindableComponent control)
+ {
+ if (control == this.control)
+ return;
+
+ control_property = TypeDescriptor.GetProperties (control).Find (property_name, true);
+
+ if (control_property == null)
+ throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' on target control."));
+ if (control_property.IsReadOnly)
+ throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' because it is read only."));
+
+ data_type = control_property.PropertyType; // Getting the PropertyType is kinda slow and it should never change, so it is cached
+
+ Widget ctrl = control as Widget;
+ if (ctrl != null) {
+ ctrl.Validating += new CancelEventHandler (ControlValidatingHandler);
+ if (!ctrl.IsHandleCreated)
+ ctrl.HandleCreated += new EventHandler (ControlCreatedHandler);
+ }
+
+ EventDescriptor prop_changed_event = GetPropertyChangedEvent (control, property_name);
+ if (prop_changed_event != null)
+ prop_changed_event.AddEventHandler (control, new EventHandler (ControlPropertyChangedHandler));
+ this.control = control;
+ UpdateIsBinding ();
+ }
+
+ internal void Check ()
+ {
+ if (control == null || control.BindingContext == null)
+ return;
+
+ if (manager == null) {
+ manager = control.BindingContext [data_source, binding_member_info.BindingPath];
+
+ if (manager.Position > -1 && binding_member_info.BindingField != String.Empty &&
+ TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true) == null)
+ throw new ArgumentException ("Cannot bind to property '" + binding_member_info.BindingField + "' on DataSource.",
+ "dataMember");
+
+ manager.AddBinding (this);
+ manager.PositionChanged += new EventHandler (PositionChangedHandler);
+
+ if (manager is PropertyManager) { // Match .net, which only watchs simple objects
+ EventDescriptor prop_changed_event = GetPropertyChangedEvent (manager.Current, binding_member_info.BindingField);
+ if (prop_changed_event != null)
+ prop_changed_event.AddEventHandler (manager.Current, new EventHandler (SourcePropertyChangedHandler));
+ }
+ }
+
+ if (manager.Position == -1)
+ return;
+
+ if (!checked_isnull) {
+ is_null_desc = TypeDescriptor.GetProperties (manager.Current).Find (property_name + "IsNull", false);
+ checked_isnull = true;
+ }
+
+ PushData ();
+ }
+
+ internal bool PullData ()
+ {
+ return PullData (false);
+ }
+
+ // Return false ONLY in case of error - and return true even in cases
+ // where no update was possible
+ bool PullData (bool force)
+ {
+ if (IsBinding == false || manager.Current == null)
+ return true;
+ if (!force && datasource_update_mode == DataSourceUpdateMode.Never)
+ return true;
+
+ data = control_property.GetValue (control);
+ if (data == null)
+ data = datasource_null_value;
+
+ try {
+ SetPropertyValue (data);
+ } catch (Exception e) {
+ if (formatting_enabled) {
+ FireBindingComplete (BindingCompleteContext.DataSourceUpdate, e, e.Message);
+ return false;
+ }
+ throw e;
+ }
+
+ if (formatting_enabled)
+ FireBindingComplete (BindingCompleteContext.DataSourceUpdate, null, null);
+ return true;
+ }
+
+ internal void PushData ()
+ {
+ PushData (false);
+ }
+
+ void PushData (bool force)
+ {
+ if (manager == null || manager.IsSuspended || manager.Count == 0 || manager.Position == -1)
+ return;
+ if (!force && control_update_mode == ControlUpdateMode.Never)
+ return;
+
+ if (is_null_desc != null) {
+ bool is_null = (bool) is_null_desc.GetValue (manager.Current);
+ if (is_null) {
+ data = Convert.DBNull;
+ return;
+ }
+ }
+
+ PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
+ if (pd == null) {
+ data = manager.Current;
+ } else {
+ data = pd.GetValue (manager.Current);
+ }
+
+ if ((data == null || data == DBNull.Value) && null_value != null)
+ data = null_value;
+
+ try {
+ data = FormatData (data);
+ SetControlValue (data);
+ } catch (Exception e) {
+ if (formatting_enabled) {
+ FireBindingComplete (BindingCompleteContext.ControlUpdate, e, e.Message);
+ return;
+ }
+ throw e;
+ }
+
+ if (formatting_enabled)
+ FireBindingComplete (BindingCompleteContext.ControlUpdate, null, null);
+ }
+
+ internal void UpdateIsBinding ()
+ {
+ is_binding = false;
+ if (control == null || (control is Widget && !((Widget)control).IsHandleCreated))
+ return;
+
+ is_binding = true;
+ PushData ();
+ }
+
+ private void SetControlValue (object data)
+ {
+ control_property.SetValue (control, data);
+ }
+
+ private void SetPropertyValue (object data)
+ {
+ PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
+ if (pd.IsReadOnly)
+ return;
+ data = ParseData (data, pd.PropertyType);
+ pd.SetValue (manager.Current, data);
+ }
+
+ private void ControlValidatingHandler (object sender, CancelEventArgs e)
+ {
+ if (datasource_update_mode != DataSourceUpdateMode.OnValidation)
+ return;
+
+ bool ok = true;
+ // If the data doesn't seem to be valid (it can't be converted,
+ // is the wrong type, etc, we reset to the old data value.
+ // If Formatting is enabled, no exception is fired, but we get a false value
+ try {
+ ok = PullData ();
+ } catch {
+ ok = false;
+ }
+
+ e.Cancel = !ok;
+ }
+
+ private void ControlCreatedHandler (object o, EventArgs args)
+ {
+ UpdateIsBinding ();
+ }
+
+ private void PositionChangedHandler (object sender, EventArgs e)
+ {
+ Check ();
+ PushData ();
+ }
+
+ EventDescriptor GetPropertyChangedEvent (object o, string property_name)
+ {
+ if (o == null || property_name == null || property_name.Length == 0)
+ return null;
+
+ string event_name = property_name + "Changed";
+ Type event_handler_type = typeof (EventHandler);
+
+ EventDescriptor prop_changed_event = null;
+ foreach (EventDescriptor event_desc in TypeDescriptor.GetEvents (o)) {
+ if (event_desc.Name == event_name && event_desc.EventType == event_handler_type) {
+ prop_changed_event = event_desc;
+ break;
+ }
+ }
+
+ return prop_changed_event;
+ }
+
+ void SourcePropertyChangedHandler (object o, EventArgs args)
+ {
+ PushData ();
+ }
+
+ void ControlPropertyChangedHandler (object o, EventArgs args)
+ {
+ if (datasource_update_mode != DataSourceUpdateMode.OnPropertyChanged)
+ return;
+
+ PullData ();
+ }
+
+ private object ParseData (object data, Type data_type)
+ {
+ ConvertEventArgs e = new ConvertEventArgs (data, data_type);
+
+ OnParse (e);
+ if (data_type.IsInstanceOfType (e.Value))
+ return e.Value;
+ if (e.Value == Convert.DBNull)
+ return e.Value;
+ if (e.Value == null) {
+ bool nullable = data_type.IsGenericType && !data_type.ContainsGenericParameters &&
+ data_type.GetGenericTypeDefinition () == typeof (Nullable<>);
+ return data_type.IsValueType && !nullable ? Convert.DBNull : null;
+ }
+
+ return ConvertData (e.Value, data_type);
+ }
+
+ private object FormatData (object data)
+ {
+ ConvertEventArgs e = new ConvertEventArgs (data, data_type);
+
+ OnFormat (e);
+ if (data_type.IsInstanceOfType (e.Value))
+ return e.Value;
+
+ if (formatting_enabled) {
+ if ((e.Value == null || e.Value == Convert.DBNull) && null_value != null)
+ return null_value;
+
+ if (e.Value is IFormattable && data_type == typeof (string)) {
+ IFormattable formattable = (IFormattable) e.Value;
+ return formattable.ToString (format_string, format_info);
+ }
+ }
+
+ if (e.Value == null && data_type == typeof (object))
+ return Convert.DBNull;
+
+ return ConvertData (data, data_type);
+ }
+
+ private object ConvertData (object data, Type data_type)
+ {
+ if (data == null)
+ return null;
+
+ TypeConverter converter = TypeDescriptor.GetConverter (data.GetType ());
+ if (converter != null && converter.CanConvertTo (data_type))
+ return converter.ConvertTo (data, data_type);
+
+ converter = TypeDescriptor.GetConverter (data_type);
+ if (converter != null && converter.CanConvertFrom (data.GetType()))
+ return converter.ConvertFrom (data);
+
+ if (data is IConvertible) {
+ object res = Convert.ChangeType (data, data_type);
+ if (data_type.IsInstanceOfType (res))
+ return res;
+ }
+
+ return null;
+ }
+ void FireBindingComplete (BindingCompleteContext context, Exception exc, string error_message)
+ {
+ BindingCompleteEventArgs args = new BindingCompleteEventArgs (this,
+ exc == null ? BindingCompleteState.Success : BindingCompleteState.Exception,
+ context);
+ if (exc != null) {
+ args.SetException (exc);
+ args.SetErrorText (error_message);
+ }
+
+ OnBindingComplete (args);
+ }
+
+ #region Events
+ public event ConvertEventHandler Format;
+ public event ConvertEventHandler Parse;
+ public event BindingCompleteEventHandler BindingComplete;
+ #endregion // Events
+ }
+}
diff --git a/source/ShiftUI/Internal/BindingCompleteContext.cs b/source/ShiftUI/Internal/BindingCompleteContext.cs
new file mode 100644
index 0000000..44d7347
--- /dev/null
+++ b/source/ShiftUI/Internal/BindingCompleteContext.cs
@@ -0,0 +1,37 @@
+//
+// BindingCompleteContext.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+namespace ShiftUI
+{
+ public enum BindingCompleteContext
+ {
+ ControlUpdate = 0,
+ DataSourceUpdate = 1
+ }
+}
diff --git a/source/ShiftUI/Internal/BindingContext.cs b/source/ShiftUI/Internal/BindingContext.cs
new file mode 100644
index 0000000..fbf461a
--- /dev/null
+++ b/source/ShiftUI/Internal/BindingContext.cs
@@ -0,0 +1,257 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+// Jackson Harper [email protected]
+
+
+using System.Data;
+using System.Collections;
+using System.Globalization;
+using System.ComponentModel;
+using System;
+
+namespace ShiftUI {
+
+ [DefaultEvent("CollectionChanged")]
+ public class BindingContext : ICollection, IEnumerable {
+
+ private Hashtable managers;
+ private EventHandler onCollectionChangedHandler;
+
+ private class HashKey {
+ public object source;
+ public string member;
+
+ public HashKey (object source, string member)
+ {
+ this.source = source;
+ this.member = member;
+ }
+
+ public override int GetHashCode ()
+ {
+ return source.GetHashCode() ^ member.GetHashCode ();
+ }
+
+ public override bool Equals (object o)
+ {
+ HashKey hk = o as HashKey;
+ if (hk == null)
+ return false;
+ return hk.source == source && hk.member == member;
+ }
+ }
+
+ public BindingContext ()
+ {
+ managers = new Hashtable ();
+ onCollectionChangedHandler = null;
+ }
+
+ public bool IsReadOnly {
+ get { return false; }
+ }
+
+ public BindingManagerBase this [object dataSource] {
+ get { return this [dataSource, String.Empty]; }
+ }
+
+ public BindingManagerBase this [object dataSource, string dataMember] {
+ get {
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+ if (dataMember == null)
+ dataMember = String.Empty;
+
+ ICurrencyManagerProvider cm_provider = dataSource as ICurrencyManagerProvider;
+ if (cm_provider != null) {
+ if (dataMember.Length == 0)
+ return cm_provider.CurrencyManager;
+
+ return cm_provider.GetRelatedCurrencyManager (dataMember);
+ }
+
+ HashKey key = new HashKey (dataSource, dataMember);
+ BindingManagerBase res = managers [key] as BindingManagerBase;
+
+ if (res != null)
+ return res;
+
+ res = CreateBindingManager (dataSource, dataMember);
+ if (res == null)
+ return null;
+ managers [key] = res;
+ return res;
+ }
+ }
+
+ private BindingManagerBase CreateBindingManager (object data_source, string data_member)
+ {
+ if (data_member == "") {
+ if (IsListType (data_source.GetType ()))
+ return new CurrencyManager (data_source);
+ else
+ return new PropertyManager (data_source);
+ }
+ else {
+ BindingMemberInfo info = new BindingMemberInfo (data_member);
+
+ BindingManagerBase parent_manager = this[data_source, info.BindingPath];
+
+ PropertyDescriptor pd = parent_manager == null ? null : parent_manager.GetItemProperties ().Find (info.BindingField, true);
+
+ if (pd == null)
+ throw new ArgumentException (String.Format ("Cannot create a child list for field {0}.", info.BindingField));
+
+ if (IsListType (pd.PropertyType))
+ return new RelatedCurrencyManager (parent_manager, pd);
+ else
+ return new RelatedPropertyManager (parent_manager, info.BindingField);
+ }
+ }
+
+ bool IsListType (Type t)
+ {
+ return (typeof (IList).IsAssignableFrom (t)
+ || typeof (IListSource).IsAssignableFrom (t));
+ }
+
+ #region Public Instance Methods
+ public bool Contains(object dataSource)
+ {
+ return Contains (dataSource, String.Empty);
+ }
+
+ public bool Contains (object dataSource, string dataMember)
+ {
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+ if (dataMember == null)
+ dataMember = String.Empty;
+
+ HashKey key = new HashKey (dataSource, dataMember);
+ return managers [key] != null;
+ }
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+
+ protected internal void Add (object dataSource, BindingManagerBase listManager)
+ {
+ AddCore (dataSource, listManager);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataSource));
+ }
+
+ protected virtual void AddCore (object dataSource, BindingManagerBase listManager)
+ {
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+ if (listManager == null)
+ throw new ArgumentNullException ("listManager");
+
+ HashKey key = new HashKey (dataSource, String.Empty);
+ managers [key] = listManager;
+ }
+
+ protected internal void Clear ()
+ {
+ ClearCore();
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
+ }
+
+ protected virtual void ClearCore ()
+ {
+ managers.Clear ();
+ }
+
+ protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
+ {
+ if (onCollectionChangedHandler != null) {
+ onCollectionChangedHandler (this, ccevent);
+ }
+ }
+
+ protected internal void Remove (object dataSource)
+ {
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+
+ RemoveCore (dataSource);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataSource));
+ }
+
+ protected virtual void RemoveCore (object dataSource)
+ {
+ HashKey[] keys = new HashKey [managers.Keys.Count];
+ managers.Keys.CopyTo (keys, 0);
+
+ for (int i = 0; i < keys.Length; i ++) {
+ if (keys[i].source == dataSource)
+ managers.Remove (keys[i]);
+ }
+ }
+
+ [MonoTODO ("Stub, does nothing")]
+ public static void UpdateBinding (BindingContext newBindingContext, Binding binding)
+ {
+ }
+
+ #endregion // Protected Instance Methods
+
+ #region Events
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public event CollectionChangeEventHandler CollectionChanged {
+ add { throw new NotImplementedException (); }
+ remove { /* nothing to do here.. */ }
+ }
+ #endregion // Events
+
+ #region ICollection Interfaces
+ void ICollection.CopyTo (Array ar, int index)
+ {
+ managers.CopyTo (ar, index);
+ }
+
+ int ICollection.Count {
+ get { return managers.Count; }
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false; }
+ }
+
+ object ICollection.SyncRoot {
+ get { return null; }
+ }
+
+ #endregion // ICollection Interfaces
+
+ #region IEnumerable Interfaces
+ [MonoInternalNote ("our enumerator is slightly different. in MS's implementation the Values are WeakReferences to the managers.")]
+ IEnumerator IEnumerable.GetEnumerator() {
+ return managers.GetEnumerator ();
+ }
+ #endregion // IEnumerable Interfaces
+ }
+}
diff --git a/source/ShiftUI/Internal/BindingManagerBase.cs b/source/ShiftUI/Internal/BindingManagerBase.cs
new file mode 100644
index 0000000..c2b0392
--- /dev/null
+++ b/source/ShiftUI/Internal/BindingManagerBase.cs
@@ -0,0 +1,204 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+// Jackson Harper [email protected]
+//
+
+
+// NOT COMPLETE
+
+using System.ComponentModel;
+using System.Collections;
+using System;
+
+namespace ShiftUI
+{
+ public abstract class BindingManagerBase
+ {
+ private BindingsCollection bindings;
+ internal bool transfering_data; /* true if we're pushing or pulling data */
+
+ #region Public Constructors
+ public BindingManagerBase()
+ {
+ }
+ #endregion // Public Constructors
+
+ #region Protected Instance Fields
+ protected EventHandler onCurrentChangedHandler;
+ protected EventHandler onPositionChangedHandler;
+ internal EventHandler onCurrentItemChangedHandler;
+ #endregion // Protected Instance Fields
+
+ #region Public Instance Properties
+ public BindingsCollection Bindings {
+ get {
+ if (bindings == null) {
+ bindings = new BindingsCollection ();
+ }
+ return bindings;
+ }
+ }
+
+ public abstract int Count {
+ get;
+ }
+
+ public abstract object Current {
+ get;
+ }
+
+ public bool IsBindingSuspended {
+ get {
+ return IsSuspended;
+ }
+ }
+
+ public abstract int Position {
+ get; set;
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Instance Methods
+ public abstract void AddNew();
+
+ public abstract void CancelCurrentEdit();
+
+ public abstract void EndCurrentEdit();
+
+ public virtual PropertyDescriptorCollection GetItemProperties()
+ {
+ return GetItemPropertiesInternal ();
+ }
+
+ internal virtual PropertyDescriptorCollection GetItemPropertiesInternal ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public abstract void RemoveAt(int index);
+
+ public abstract void ResumeBinding();
+
+ public abstract void SuspendBinding();
+ #endregion // Public Instance Methods
+
+ internal virtual bool IsSuspended {
+ get {
+ return false;
+ }
+ }
+
+ #region Protected Instance Methods
+ [MonoTODO ("Not implemented, will throw NotImplementedException")]
+ protected internal virtual PropertyDescriptorCollection GetItemProperties (ArrayList dataSources, ArrayList listAccessors)
+ {
+ throw new NotImplementedException();
+ }
+
+ [MonoTODO ("Not implemented, will throw NotImplementedException")]
+ protected virtual PropertyDescriptorCollection GetItemProperties (Type listType, int offset, ArrayList dataSources, ArrayList listAccessors)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected internal abstract string GetListName (ArrayList listAccessors);
+
+ protected internal abstract void OnCurrentChanged (EventArgs e);
+
+ protected void PullData()
+ {
+ try {
+ if (!transfering_data) {
+ transfering_data = true;
+ UpdateIsBinding ();
+ }
+ foreach (Binding binding in Bindings) {
+ binding.PullData ();
+ }
+ } finally {
+ transfering_data = false;
+ }
+ }
+
+ protected void PushData()
+ {
+ try {
+ if (!transfering_data) {
+ transfering_data = true;
+ UpdateIsBinding ();
+ }
+ foreach (Binding binding in Bindings) {
+ binding.PushData ();
+ }
+ } finally {
+ transfering_data = false;
+ }
+ }
+
+
+ protected void OnBindingComplete (BindingCompleteEventArgs args)
+ {
+ if (BindingComplete != null)
+ BindingComplete (this, args);
+ }
+
+ protected abstract void OnCurrentItemChanged (EventArgs e);
+
+ protected void OnDataError (Exception e)
+ {
+ if (DataError != null)
+ DataError (this, new BindingManagerDataErrorEventArgs (e));
+ }
+
+ protected abstract void UpdateIsBinding();
+ #endregion // Protected Instance Methods
+
+ internal void AddBinding (Binding binding)
+ {
+ if (Bindings.Contains (binding))
+ return;
+ Bindings.Add (binding);
+ }
+
+ #region Events
+ public event EventHandler CurrentChanged {
+ add { onCurrentChangedHandler += value; }
+ remove { onCurrentChangedHandler -= value; }
+ }
+
+ public event EventHandler PositionChanged {
+ add { onPositionChangedHandler += value; }
+ remove { onPositionChangedHandler -= value; }
+ }
+
+ public event EventHandler CurrentItemChanged {
+ add { onCurrentItemChangedHandler += value; }
+ remove { onCurrentItemChangedHandler -= value; }
+ }
+
+ public event BindingCompleteEventHandler BindingComplete;
+ public event BindingManagerDataErrorEventHandler DataError;
+ #endregion // Events
+ }
+}
diff --git a/source/ShiftUI/Internal/BindingMemberInfo.cs b/source/ShiftUI/Internal/BindingMemberInfo.cs
new file mode 100644
index 0000000..3f7ae11
--- /dev/null
+++ b/source/ShiftUI/Internal/BindingMemberInfo.cs
@@ -0,0 +1,107 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+
+// COMPLETE
+using System;
+
+namespace ShiftUI {
+ public struct BindingMemberInfo {
+ private string data_member;
+ private string data_field;
+ private string data_path;
+
+ #region Public Constructors
+ public BindingMemberInfo(string dataMember) {
+ int i;
+
+ if (dataMember!=null) {
+ this.data_member=dataMember;
+ } else {
+ this.data_member=String.Empty;
+ }
+
+ // Break out our components
+ i=data_member.LastIndexOf('.');
+ if (i!=-1) {
+ data_field=data_member.Substring(i+1);
+ data_path=data_member.Substring(0, i);
+ } else {
+ data_field=data_member;
+ data_path=String.Empty;
+ }
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ public string BindingField {
+ get {
+ return this.data_field;
+ }
+ }
+
+ public string BindingMember {
+ get {
+ return this.data_member;
+ }
+ }
+
+ public string BindingPath {
+ get {
+ return this.data_path;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Instance Methods
+ public override bool Equals(object otherObject) {
+ if (otherObject is BindingMemberInfo) {
+ return ((this.data_field == ((BindingMemberInfo)otherObject).data_field) &&
+ (this.data_path == ((BindingMemberInfo)otherObject).data_path) &&
+ (this.data_member == ((BindingMemberInfo)otherObject).data_member));
+ } else {
+ return false;
+ }
+ }
+
+ public override int GetHashCode() {
+ return this.data_member.GetHashCode();
+ }
+ #endregion // Public Instance Methods
+
+ #region Public Static Methods
+ public static bool operator == (BindingMemberInfo a, BindingMemberInfo b)
+ {
+ return (a.Equals (b));
+ }
+
+ public static bool operator != (BindingMemberInfo a, BindingMemberInfo b)
+ {
+ return !(a.Equals (b));
+ }
+ #endregion // Public Static Methods
+
+ }
+}
diff --git a/source/ShiftUI/Internal/BindingsCollection.cs b/source/ShiftUI/Internal/BindingsCollection.cs
new file mode 100644
index 0000000..11f4fe9
--- /dev/null
+++ b/source/ShiftUI/Internal/BindingsCollection.cs
@@ -0,0 +1,136 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+// Jackson Harper [email protected]
+//
+
+
+// COMPLETE
+
+using System.Collections;
+using System.ComponentModel;
+
+namespace ShiftUI {
+ [DefaultEvent("CollectionChanged")]
+ public class BindingsCollection : BaseCollection {
+
+#region Public Constructors
+ internal BindingsCollection ()
+ {
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ public override int Count {
+ get {
+ return base.Count;
+ }
+ }
+
+ public Binding this[int index] {
+ get {
+ return (Binding)(base.List[index]);
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Protected Instance Properties
+ protected override ArrayList List {
+ get {
+ return base.List;
+ }
+ }
+ #endregion // Protected Instance Properties
+
+ #region Protected Instance Methods
+ protected internal void Add(Binding binding) {
+ AddCore(binding);
+ }
+
+ protected virtual void AddCore (Binding dataBinding)
+ {
+ CollectionChangeEventArgs args = new CollectionChangeEventArgs (CollectionChangeAction.Add, dataBinding);
+ OnCollectionChanging (args);
+ base.List.Add(dataBinding);
+ OnCollectionChanged (args);
+ }
+
+ protected internal void Clear() {
+ ClearCore();
+ }
+
+ protected virtual void ClearCore()
+ {
+ CollectionChangeEventArgs args = new CollectionChangeEventArgs(CollectionChangeAction.Refresh, null);
+ OnCollectionChanging (args);
+ base.List.Clear();
+ OnCollectionChanged (args);
+ }
+
+ protected virtual void OnCollectionChanged(System.ComponentModel.CollectionChangeEventArgs ccevent) {
+ if (CollectionChanged!=null) CollectionChanged(this, ccevent);
+ }
+
+ protected virtual void OnCollectionChanging (CollectionChangeEventArgs e)
+ {
+ if (CollectionChanging != null)
+ CollectionChanging (this, e);
+ }
+
+ protected internal void Remove(Binding binding) {
+ RemoveCore(binding);
+ }
+
+ protected internal void RemoveAt(int index) {
+ base.List.RemoveAt(index);
+ OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, base.List));
+ }
+
+ protected virtual void RemoveCore(Binding dataBinding)
+ {
+ CollectionChangeEventArgs args = new CollectionChangeEventArgs(CollectionChangeAction.Remove, dataBinding);
+ OnCollectionChanging (args);
+ base.List.Remove(dataBinding);
+ OnCollectionChanged (args);
+ }
+
+ protected internal bool ShouldSerializeMyAll() {
+ if (this.Count>0) {
+ return(true);
+ } else {
+ return(false);
+ }
+ }
+ #endregion // Public Instance Methods
+
+ internal bool Contains (Binding binding)
+ {
+ return List.Contains (binding);
+ }
+
+ #region Events
+ public event CollectionChangeEventHandler CollectionChanged;
+ public event CollectionChangeEventHandler CollectionChanging;
+ #endregion // Events
+ }
+}
diff --git a/source/ShiftUI/Internal/BootMode.cs b/source/ShiftUI/Internal/BootMode.cs
new file mode 100644
index 0000000..495d678
--- /dev/null
+++ b/source/ShiftUI/Internal/BootMode.cs
@@ -0,0 +1,39 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+//
+
+//COMPLETE
+
+
+namespace ShiftUI
+{
+
+ public enum BootMode
+ {
+ Normal = 0,
+ FailSafe = 1,
+ FailSafeWithNetwork = 2
+ }
+}
+
diff --git a/source/ShiftUI/Internal/BoundsSpecified.cs b/source/ShiftUI/Internal/BoundsSpecified.cs
new file mode 100644
index 0000000..7acc040
--- /dev/null
+++ b/source/ShiftUI/Internal/BoundsSpecified.cs
@@ -0,0 +1,43 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+// COMPLETE
+using System;
+
+namespace ShiftUI
+{
+ [Flags]
+ public enum BoundsSpecified
+ {
+ None = 0x00000000,
+ X = 0x00000001,
+ Y = 0x00000002,
+ Location = 0x00000003,
+ Width = 0x00000004,
+ Height = 0x00000008,
+ Size = 0x0000000c,
+ All = 0x0000000f
+ }
+}
diff --git a/source/ShiftUI/Internal/ButtonBase.cs b/source/ShiftUI/Internal/ButtonBase.cs
new file mode 100644
index 0000000..7f8c894
--- /dev/null
+++ b/source/ShiftUI/Internal/ButtonBase.cs
@@ -0,0 +1,747 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Drawing;
+using System.Drawing.Text;
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI {
+ [ClassInterface (ClassInterfaceType.AutoDispatch)]
+ [ComVisible (true)]
+ //[Designer ("ShiftUI.Design.ButtonBaseDesigner, " + Consts.AssemblySystem_Design,
+ //"System.ComponentModel.Design.IDesigner")]
+ public abstract class ButtonBase : Widget
+ {
+ #region Local Variables
+ private FlatStyle flat_style;
+ private int image_index;
+ internal Image image;
+ internal ImageList image_list;
+ private ContentAlignment image_alignment;
+ internal ContentAlignment text_alignment;
+ private bool is_default;
+ internal bool is_pressed;
+// private bool enter_state;
+ internal StringFormat text_format;
+ internal bool paint_as_acceptbutton;
+
+ // Properties are 2.0, but variables used in 1.1 for common drawing code
+ private bool auto_ellipsis;
+ private FlatButtonAppearance flat_button_appearance;
+ private string image_key;
+ private TextImageRelation text_image_relation;
+ private TextFormatFlags text_format_flags;
+ private bool use_mnemonic;
+ private bool use_visual_style_back_color;
+ #endregion // Local Variables
+
+ #region Public Constructors
+ protected ButtonBase() : base()
+ {
+ flat_style = FlatStyle.Standard;
+ flat_button_appearance = new FlatButtonAppearance (this);
+ this.image_key = string.Empty;
+ this.text_image_relation = TextImageRelation.Overlay;
+ this.use_mnemonic = true;
+ use_visual_style_back_color = true;
+ image_index = -1;
+ image = null;
+ image_list = null;
+ image_alignment = ContentAlignment.MiddleCenter;
+ ImeMode = ImeMode.Disable;
+ text_alignment = ContentAlignment.MiddleCenter;
+ is_default = false;
+ is_pressed = false;
+ text_format = new StringFormat();
+ text_format.Alignment = StringAlignment.Center;
+ text_format.LineAlignment = StringAlignment.Center;
+ text_format.HotkeyPrefix = HotkeyPrefix.Show;
+ text_format.FormatFlags |= StringFormatFlags.LineLimit;
+
+ text_format_flags = TextFormatFlags.HorizontalCenter;
+ text_format_flags |= TextFormatFlags.VerticalCenter;
+ text_format_flags |= TextFormatFlags.TextBoxControl;
+
+ SetStyle (Widgetstyles.ResizeRedraw |
+ Widgetstyles.Opaque |
+ Widgetstyles.UserMouse |
+ Widgetstyles.SupportsTransparentBackColor |
+ Widgetstyles.CacheText |
+ Widgetstyles.OptimizedDoubleBuffer, true);
+ SetStyle (Widgetstyles.StandardClick, false);
+ }
+ #endregion // Public Constructors
+
+ #region Public Properties
+ [Browsable (true)]
+ [DefaultValue (false)]
+ //[EditorBrowsable (EditorBrowsableState.Always)]
+ [MWFCategory("Behavior")]
+ public bool AutoEllipsis {
+ get { return this.auto_ellipsis; }
+ set
+ {
+ if (this.auto_ellipsis != value) {
+ this.auto_ellipsis = value;
+
+ if (this.auto_ellipsis) {
+ text_format_flags |= TextFormatFlags.EndEllipsis;
+ text_format_flags &= ~TextFormatFlags.WordBreak;
+ } else {
+ text_format_flags &= ~TextFormatFlags.EndEllipsis;
+ text_format_flags |= TextFormatFlags.WordBreak;
+ }
+
+ if (Parent != null)
+ Parent.PerformLayout (this, "AutoEllipsis");
+ this.Invalidate ();
+ }
+ }
+ }
+
+ [Browsable (true)]
+ //[EditorBrowsable (EditorBrowsableState.Always)]
+ //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
+ [MWFCategory("Layout")]
+ public override bool AutoSize {
+ get { return base.AutoSize; }
+ set { base.AutoSize = value; }
+ }
+
+ public override Color BackColor {
+ get { return base.BackColor; }
+ set { base.BackColor = value; }
+ }
+
+ //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
+ [Browsable (true)]
+ [MWFCategory("Appearance")]
+ public FlatButtonAppearance FlatAppearance {
+ get { return flat_button_appearance; }
+ }
+
+ [Localizable(true)]
+ [DefaultValue(FlatStyle.Standard)]
+ [MWFDescription("Determines look of button"), MWFCategory("Appearance")]
+ public FlatStyle FlatStyle {
+ get { return flat_style; }
+ set {
+ if (flat_style != value) {
+ flat_style = value;
+
+ if (Parent != null)
+ Parent.PerformLayout (this, "FlatStyle");
+ Invalidate();
+ }
+ }
+ }
+
+ [Localizable(true)]
+ [MWFDescription("Sets image to be displayed on button face"), MWFCategory("Appearance")]
+ public Image Image {
+ get {
+ if (this.image != null)
+ return this.image;
+
+ if (this.image_index >= 0)
+ if (this.image_list != null)
+ return this.image_list.Images[this.image_index];
+
+ if (!string.IsNullOrEmpty (this.image_key))
+ if (this.image_list != null)
+ return this.image_list.Images[this.image_key];
+ return null;
+ }
+ set {
+ if (this.image != value) {
+ this.image = value;
+ this.image_index = -1;
+ this.image_key = string.Empty;
+ this.image_list = null;
+
+ if (this.AutoSize && this.Parent != null)
+ this.Parent.PerformLayout (this, "Image");
+
+ Invalidate ();
+ }
+ }
+ }
+
+ internal bool ShouldSerializeImage ()
+ {
+ return this.Image != null;
+ }
+
+ [Localizable(true)]
+ [DefaultValue(ContentAlignment.MiddleCenter)]
+ [MWFDescription("Sets the alignment of the image to be displayed on button face"), MWFCategory("Appearance")]
+ public ContentAlignment ImageAlign {
+ get { return image_alignment; }
+ set {
+ if (image_alignment != value) {
+ image_alignment = value;
+ Invalidate ();
+ }
+ }
+ }
+
+ [Localizable(true)]
+ [DefaultValue(-1)]
+ //[Editor("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
+ [TypeConverter(typeof(ImageIndexConverter))]
+ [MWFDescription("Index of image to display, if ImageList is used for button face images"), MWFCategory("Appearance")]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ public int ImageIndex {
+ get {
+ if (image_list == null)
+ return -1;
+
+ return image_index;
+ }
+ set {
+ if (this.image_index != value) {
+ this.image_index = value;
+ this.image = null;
+ this.image_key = string.Empty;
+ Invalidate ();
+ }
+ }
+ }
+
+ [Localizable (true)]
+ [DefaultValue ("")]
+ //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ [TypeConverter (typeof (ImageKeyConverter))]
+ [MWFCategory("Appearance")]
+ public string ImageKey {
+ get { return this.image_key; }
+ set {
+ if (this.image_key != value) {
+ this.image = null;
+ this.image_index = -1;
+ this.image_key = value;
+ this.Invalidate ();
+ }
+ }
+ }
+
+ [DefaultValue(null)]
+ [MWFDescription("ImageList used for ImageIndex"), MWFCategory("Appearance")]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ public ImageList ImageList {
+ get { return image_list; }
+ set {
+ if (image_list != value) {
+ image_list = value;
+
+ if (value != null && image != null)
+ image = null;
+
+ Invalidate ();
+ }
+ }
+ }
+
+ [Browsable(false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new ImeMode ImeMode {
+ get { return base.ImeMode; }
+ set { base.ImeMode = value; }
+ }
+
+ [SettingsBindable (true)]
+ //[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
+ //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
+ public override string Text {
+ get { return base.Text; }
+ set { base.Text = value; }
+ }
+
+ [Localizable(true)]
+ [DefaultValue(ContentAlignment.MiddleCenter)]
+ [MWFDescription("Alignment for button text"), MWFCategory("Appearance")]
+ public virtual ContentAlignment TextAlign {
+ get { return text_alignment; }
+ set {
+ if (text_alignment != value) {
+ text_alignment = value;
+
+ text_format_flags &= ~TextFormatFlags.Bottom;
+ text_format_flags &= ~TextFormatFlags.Top;
+ text_format_flags &= ~TextFormatFlags.Left;
+ text_format_flags &= ~TextFormatFlags.Right;
+ text_format_flags &= ~TextFormatFlags.HorizontalCenter;
+ text_format_flags &= ~TextFormatFlags.VerticalCenter;
+
+ switch (text_alignment) {
+ case ContentAlignment.TopLeft:
+ text_format.Alignment=StringAlignment.Near;
+ text_format.LineAlignment=StringAlignment.Near;
+ break;
+
+ case ContentAlignment.TopCenter:
+ text_format.Alignment=StringAlignment.Center;
+ text_format.LineAlignment=StringAlignment.Near;
+ text_format_flags |= TextFormatFlags.HorizontalCenter;
+ break;
+
+ case ContentAlignment.TopRight:
+ text_format.Alignment=StringAlignment.Far;
+ text_format.LineAlignment=StringAlignment.Near;
+ text_format_flags |= TextFormatFlags.Right;
+ break;
+
+ case ContentAlignment.MiddleLeft:
+ text_format.Alignment=StringAlignment.Near;
+ text_format.LineAlignment=StringAlignment.Center;
+ text_format_flags |= TextFormatFlags.VerticalCenter;
+ break;
+
+ case ContentAlignment.MiddleCenter:
+ text_format.Alignment=StringAlignment.Center;
+ text_format.LineAlignment=StringAlignment.Center;
+ text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
+ break;
+
+ case ContentAlignment.MiddleRight:
+ text_format.Alignment=StringAlignment.Far;
+ text_format.LineAlignment=StringAlignment.Center;
+ text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
+ break;
+
+ case ContentAlignment.BottomLeft:
+ text_format.Alignment=StringAlignment.Near;
+ text_format.LineAlignment=StringAlignment.Far;
+ text_format_flags |= TextFormatFlags.Bottom;
+ break;
+
+ case ContentAlignment.BottomCenter:
+ text_format.Alignment=StringAlignment.Center;
+ text_format.LineAlignment=StringAlignment.Far;
+ text_format_flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.Bottom;
+ break;
+
+ case ContentAlignment.BottomRight:
+ text_format.Alignment=StringAlignment.Far;
+ text_format.LineAlignment=StringAlignment.Far;
+ text_format_flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
+ break;
+ }
+
+ Invalidate();
+ }
+ }
+ }
+
+ [Localizable (true)]
+ [DefaultValue (TextImageRelation.Overlay)]
+ [MWFCategory("Appearance")]
+ public TextImageRelation TextImageRelation {
+ get { return this.text_image_relation; }
+ set {
+ if (!Enum.IsDefined (typeof (TextImageRelation), value))
+ throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextImageRelation", value));
+
+ if (this.text_image_relation != value) {
+ this.text_image_relation = value;
+
+ if (this.AutoSize && this.Parent != null)
+ this.Parent.PerformLayout (this, "TextImageRelation");
+
+ this.Invalidate ();
+ }
+ }
+ }
+
+ [DefaultValue (false)]
+ [MWFCategory("Behavior")]
+ public bool UseCompatibleTextRendering {
+ get { return use_compatible_text_rendering; }
+ set {
+ if (use_compatible_text_rendering != value) {
+ use_compatible_text_rendering = value;
+ if (Parent != null)
+ Parent.PerformLayout (this, "UseCompatibleTextRendering");
+ Invalidate ();
+ }
+ }
+ }
+
+ [DefaultValue (true)]
+ [MWFCategory("Appearance")]
+ public bool UseMnemonic {
+ get { return this.use_mnemonic; }
+ set {
+ if (this.use_mnemonic != value) {
+ this.use_mnemonic = value;
+
+ if (this.use_mnemonic)
+ text_format_flags &= ~TextFormatFlags.NoPrefix;
+ else
+ text_format_flags |= TextFormatFlags.NoPrefix;
+
+ this.Invalidate ();
+ }
+ }
+ }
+
+ [MWFCategory("Appearance")]
+ public bool UseVisualStyleBackColor {
+ get { return use_visual_style_back_color; }
+ set {
+ if (use_visual_style_back_color != value) {
+ use_visual_style_back_color = value;
+ Invalidate ();
+ }
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Protected Properties
+ protected override CreateParams CreateParams {
+ get { return base.CreateParams; }
+ }
+
+ protected override ImeMode DefaultImeMode {
+ get { return ImeMode.Disable; }
+ }
+
+ protected override Size DefaultSize {
+ get { return ThemeEngine.Current.ButtonBaseDefaultSize; }
+ }
+
+ protected internal bool IsDefault {
+ get { return is_default; }
+ set {
+ if (is_default != value) {
+ is_default = value;
+ Invalidate ();
+ }
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Methods
+ // The base calls into GetPreferredSizeCore, which we will override in our subclasses
+ public override Size GetPreferredSize (Size proposedSize)
+ {
+ return base.GetPreferredSize (proposedSize);
+ }
+ #endregion
+
+ #region Protected Methods
+ protected override AccessibleObject CreateAccessibilityInstance ()
+ {
+ return new ButtonBaseAccessibleObject (this);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ base.Dispose (disposing);
+ }
+
+ protected override void OnEnabledChanged (EventArgs e)
+ {
+ base.OnEnabledChanged (e);
+ }
+
+ protected override void OnGotFocus (EventArgs e)
+ {
+ Invalidate ();
+ base.OnGotFocus (e);
+ }
+
+ protected override void OnKeyDown (KeyEventArgs kevent)
+ {
+ if (kevent.KeyData == Keys.Space) {
+ is_pressed = true;
+ Invalidate ();
+ kevent.Handled = true;
+ }
+
+ base.OnKeyDown (kevent);
+ }
+
+ protected override void OnKeyUp (KeyEventArgs kevent)
+ {
+ if (kevent.KeyData == Keys.Space) {
+ is_pressed = false;
+ Invalidate ();
+ OnClick (EventArgs.Empty);
+ kevent.Handled = true;
+ }
+
+ base.OnKeyUp (kevent);
+ }
+
+ protected override void OnLostFocus (EventArgs e)
+ {
+ Invalidate ();
+ base.OnLostFocus (e);
+ }
+
+ protected override void OnMouseDown (MouseEventArgs mevent)
+ {
+ if ((mevent.Button & MouseButtons.Left) != 0) {
+ is_pressed = true;
+ Invalidate ();
+ }
+
+ base.OnMouseDown (mevent);
+ }
+
+ protected override void OnMouseEnter (EventArgs eventargs)
+ {
+ is_entered = true;
+ Invalidate ();
+ base.OnMouseEnter (eventargs);
+ }
+
+ protected override void OnMouseLeave (EventArgs eventargs)
+ {
+ is_entered = false;
+ Invalidate ();
+ base.OnMouseLeave (eventargs);
+ }
+
+ protected override void OnMouseMove (MouseEventArgs mevent) {
+ bool inside = false;
+ bool redraw = false;
+
+ if (ClientRectangle.Contains (mevent.Location))
+ inside = true;
+
+ // If the button was pressed and we leave, release the button press and vice versa
+ if ((mevent.Button & MouseButtons.Left) != 0) {
+ if (this.Capture && (inside != is_pressed)) {
+ is_pressed = inside;
+ redraw = true;
+ }
+ }
+
+ if (is_entered != inside) {
+ is_entered = inside;
+ redraw = true;
+ }
+
+ if (redraw)
+ Invalidate ();
+
+ base.OnMouseMove (mevent);
+ }
+
+ protected override void OnMouseUp (MouseEventArgs mevent)
+ {
+ if (this.Capture && ((mevent.Button & MouseButtons.Left) != 0)) {
+ this.Capture = false;
+
+ if (is_pressed) {
+ is_pressed = false;
+ Invalidate ();
+ } else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
+ Invalidate ();
+ }
+
+ if (ClientRectangle.Contains (mevent.Location))
+ if (!ValidationFailed) {
+ OnClick (EventArgs.Empty);
+ OnMouseClick (mevent);
+ }
+ }
+
+ base.OnMouseUp (mevent);
+ }
+
+ protected override void OnPaint (PaintEventArgs pevent)
+ {
+ Draw (pevent);
+ base.OnPaint (pevent);
+ }
+
+ protected override void OnParentChanged (EventArgs e)
+ {
+ base.OnParentChanged (e);
+ }
+
+ protected override void OnTextChanged (EventArgs e)
+ {
+ Invalidate ();
+ base.OnTextChanged (e);
+ }
+
+ protected override void OnVisibleChanged (EventArgs e)
+ {
+ if (!Visible) {
+ is_pressed = false;
+ is_entered = false;
+ }
+
+ base.OnVisibleChanged (e);
+ }
+
+ protected void ResetFlagsandPaint ()
+ {
+ // Nothing to do; MS internal
+ // Should we do Invalidate (); ?
+ }
+
+ protected override void WndProc (ref Message m)
+ {
+ switch ((Msg)m.Msg) {
+ case Msg.WM_LBUTTONDBLCLK: {
+ HaveDoubleClick ();
+ break;
+ }
+
+ case Msg.WM_MBUTTONDBLCLK: {
+ HaveDoubleClick ();
+ break;
+ }
+
+ case Msg.WM_RBUTTONDBLCLK: {
+ HaveDoubleClick ();
+ break;
+ }
+ }
+
+ base.WndProc (ref m);
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Events
+ [Browsable (true)]
+ //[EditorBrowsable (EditorBrowsableState.Always)]
+ public new event EventHandler AutoSizeChanged {
+ add { base.AutoSizeChanged += value; }
+ remove { base.AutoSizeChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler ImeModeChanged {
+ add { base.ImeModeChanged += value; }
+ remove { base.ImeModeChanged -= value; }
+ }
+ #endregion // Events
+
+ #region Internal Properties
+ internal ButtonState ButtonState {
+ get {
+ ButtonState ret = ButtonState.Normal;
+
+ if (Enabled) {
+ // Popup style is only followed as long as the mouse isn't "in" the control
+ if (is_entered) {
+ if (flat_style == FlatStyle.Flat) {
+ ret |= ButtonState.Flat;
+ }
+ } else {
+ if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) {
+ ret |= ButtonState.Flat;
+ }
+ }
+
+ if (is_entered && is_pressed) {
+ ret |= ButtonState.Pushed;
+ }
+ } else {
+ ret |= ButtonState.Inactive;
+ if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) {
+ ret |= ButtonState.Flat;
+ }
+ }
+ return ret;
+ }
+ }
+
+ internal bool Pressed {
+ get { return this.is_pressed; }
+ }
+
+ // The flags to be used for MeasureText and DrawText
+ internal TextFormatFlags TextFormatFlags {
+ get { return this.text_format_flags; }
+ }
+ #endregion
+
+ #region Internal Methods
+ // Derived classes should override Draw method and we dont want
+ // to break the control signature, hence this approach.
+ internal virtual void Draw (PaintEventArgs pevent)
+ {
+ ThemeEngine.Current.DrawButtonBase (pevent.Graphics, pevent.ClipRectangle, this);
+ }
+
+ internal virtual void HaveDoubleClick ()
+ {
+ // override me
+ }
+
+ internal override void OnPaintBackgroundInternal (PaintEventArgs e)
+ {
+ base.OnPaintBackground (e);
+ }
+ #endregion // Internal Methods
+
+ #region ButtonBaseAccessibleObject sub-class
+ [ComVisible (true)]
+ public class ButtonBaseAccessibleObject : WidgetAccessibleObject
+ {
+ #region ButtonBaseAccessibleObject Local Variables
+ private new Widget owner;
+ #endregion // ButtonBaseAccessibleObject Local Variables
+
+ #region ButtonBaseAccessibleObject Constructors
+ public ButtonBaseAccessibleObject (Widget owner) : base (owner)
+ {
+ if (owner == null)
+ throw new ArgumentNullException ("owner");
+
+ this.owner = owner;
+ default_action = "Press";
+ role = AccessibleRole.PushButton;
+ }
+ #endregion // ButtonBaseAccessibleObject Constructors
+
+ #region Public Properties
+ public override AccessibleStates State {
+ get { return base.State; }
+ }
+ #endregion
+
+ #region ButtonBaseAccessibleObject Methods
+ public override void DoDefaultAction ()
+ {
+ ((ButtonBase)owner).OnClick (EventArgs.Empty);
+ }
+ #endregion // ButtonBaseAccessibleObject Methods
+ }
+ #endregion // ButtonBaseAccessibleObject sub-class
+ }
+}
diff --git a/source/ShiftUI/Internal/ButtonRenderer.cs b/source/ShiftUI/Internal/ButtonRenderer.cs
new file mode 100644
index 0000000..a2e4237
--- /dev/null
+++ b/source/ShiftUI/Internal/ButtonRenderer.cs
@@ -0,0 +1,153 @@
+//
+// ButtonRenderer.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System.Drawing;
+using ShiftUI.VisualStyles;
+using System;
+
+namespace ShiftUI
+{
+ public sealed class ButtonRenderer
+ {
+ private static bool always_use_visual_styles = false;
+
+ #region Private Constructor
+ private ButtonRenderer () { }
+ #endregion
+
+ #region Public Static Methods
+ public static void DrawButton (Graphics g, Rectangle bounds, PushButtonState state)
+ {
+ DrawButton (g, bounds, String.Empty, null, TextFormatFlags.Default, null, Rectangle.Empty, false, state);
+ }
+
+ public static void DrawButton (Graphics g, Rectangle bounds, bool focused, PushButtonState state)
+ {
+ DrawButton (g, bounds, String.Empty, null, TextFormatFlags.Default, null, Rectangle.Empty, focused, state);
+ }
+
+ public static void DrawButton (Graphics g, Rectangle bounds, Image image, Rectangle imageBounds, bool focused, PushButtonState state)
+ {
+ DrawButton (g, bounds, String.Empty, null, TextFormatFlags.Default, image, imageBounds, focused, state);
+ }
+
+ public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, bool focused, PushButtonState state)
+ {
+ DrawButton (g, bounds, buttonText, font, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, focused, state);
+ }
+
+ public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, TextFormatFlags flags, bool focused, PushButtonState state)
+ {
+ DrawButton (g, bounds, buttonText, font, flags, null, Rectangle.Empty, focused, state);
+ }
+
+ public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, Image image, Rectangle imageBounds, bool focused, PushButtonState state)
+ {
+ DrawButton (g, bounds, buttonText, font, TextFormatFlags.HorizontalCenter, image, imageBounds, focused, state);
+ }
+
+ public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, PushButtonState state)
+ {
+ if (Application.RenderWithVisualStyles || always_use_visual_styles == true) {
+ VisualStyleRenderer vsr = GetPushButtonRenderer (state);
+
+ vsr.DrawBackground (g, bounds);
+
+ if (image != null)
+ vsr.DrawImage (g, imageBounds, image);
+ } else {
+ if (state == PushButtonState.Pressed)
+ WidgetPaint.DrawButton (g, bounds, ButtonState.Pushed);
+ else
+ WidgetPaint.DrawButton (g, bounds, ButtonState.Normal);
+
+ if (image != null)
+ g.DrawImage (image, imageBounds);
+ }
+
+ Rectangle focus_rect = bounds;
+ focus_rect.Inflate (-3, -3);
+
+ if (focused)
+ WidgetPaint.DrawFocusRectangle (g, focus_rect);
+
+ if (buttonText != String.Empty)
+ if (state == PushButtonState.Disabled)
+ TextRenderer.DrawText (g, buttonText, font, focus_rect, SystemColors.GrayText, flags);
+ else
+ TextRenderer.DrawText (g, buttonText, font, focus_rect, SystemColors.ControlText, flags);
+ }
+
+ public static bool IsBackgroundPartiallyTransparent (PushButtonState state)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return false;
+
+ VisualStyleRenderer vsr = GetPushButtonRenderer (state);
+
+ return vsr.IsBackgroundPartiallyTransparent ();
+ }
+
+ public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return;
+
+ VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Default);
+
+ vsr.DrawParentBackground (g, bounds, childControl);
+ }
+ #endregion
+
+ #region Private Static Methods
+ internal static VisualStyleRenderer GetPushButtonRenderer (PushButtonState state)
+ {
+ switch (state) {
+ case PushButtonState.Normal:
+ return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Normal);
+ case PushButtonState.Hot:
+ return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Hot);
+ case PushButtonState.Pressed:
+ return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Pressed);
+ case PushButtonState.Disabled:
+ return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Disabled);
+ case PushButtonState.Default:
+ default:
+ return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Default);
+ }
+ }
+ #endregion
+
+ #region Public Static Properties
+ public static bool RenderMatchingApplicationState {
+ get { return !always_use_visual_styles; }
+ set { always_use_visual_styles = !value; }
+ }
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/CheckBoxRenderer.cs b/source/ShiftUI/Internal/CheckBoxRenderer.cs
new file mode 100644
index 0000000..8800aa0
--- /dev/null
+++ b/source/ShiftUI/Internal/CheckBoxRenderer.cs
@@ -0,0 +1,194 @@
+//
+// CheckBoxRenderer.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System.Drawing;
+using ShiftUI.VisualStyles;
+using System;
+
+namespace ShiftUI
+{
+ public sealed class CheckBoxRenderer
+ {
+ private static bool always_use_visual_styles = false;
+
+ #region Private Constructor
+ private CheckBoxRenderer () {}
+ #endregion
+
+ #region Public Static Methods
+ public static void DrawCheckBox (Graphics g, Point glyphLocation, CheckBoxState state)
+ {
+ DrawCheckBox (g, glyphLocation, Rectangle.Empty, String.Empty, null, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, false, state);
+ }
+
+ public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, bool focused, CheckBoxState state)
+ {
+ DrawCheckBox (g, glyphLocation, textBounds, checkBoxText, font, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, focused, state);
+ }
+
+ public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, TextFormatFlags flags, bool focused, CheckBoxState state)
+ {
+ DrawCheckBox (g, glyphLocation, textBounds, checkBoxText, font, flags, null, Rectangle.Empty, focused, state);
+ }
+
+ public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, Image image, Rectangle imageBounds, bool focused, CheckBoxState state)
+ {
+ DrawCheckBox (g, glyphLocation, textBounds, checkBoxText, font, TextFormatFlags.HorizontalCenter, image, imageBounds, focused, state);
+ }
+
+ public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, CheckBoxState state)
+ {
+ Rectangle bounds = new Rectangle (glyphLocation, GetGlyphSize (g, state));
+
+ if (Application.RenderWithVisualStyles || always_use_visual_styles == true) {
+ VisualStyleRenderer vsr = GetCheckBoxRenderer (state);
+
+ vsr.DrawBackground (g, bounds);
+
+ if (image != null)
+ vsr.DrawImage (g, imageBounds, image);
+
+ if (focused)
+ WidgetPaint.DrawFocusRectangle (g, textBounds);
+
+ if (checkBoxText != String.Empty)
+ if (state == CheckBoxState.CheckedDisabled || state == CheckBoxState.MixedDisabled || state == CheckBoxState.UncheckedDisabled)
+ TextRenderer.DrawText (g, checkBoxText, font, textBounds, SystemColors.GrayText, flags);
+ else
+ TextRenderer.DrawText (g, checkBoxText, font, textBounds, SystemColors.ControlText, flags);
+ } else {
+ switch (state) {
+ case CheckBoxState.CheckedDisabled:
+ case CheckBoxState.MixedDisabled:
+ case CheckBoxState.MixedPressed:
+ WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Inactive | ButtonState.Checked);
+ break;
+ case CheckBoxState.CheckedHot:
+ case CheckBoxState.CheckedNormal:
+ WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Checked);
+ break;
+ case CheckBoxState.CheckedPressed:
+ WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Pushed | ButtonState.Checked);
+ break;
+ case CheckBoxState.MixedHot:
+ case CheckBoxState.MixedNormal:
+ WidgetPaint.DrawMixedCheckBox (g, bounds, ButtonState.Checked);
+ break;
+ case CheckBoxState.UncheckedDisabled:
+ case CheckBoxState.UncheckedPressed:
+ WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Inactive);
+ break;
+ case CheckBoxState.UncheckedHot:
+ case CheckBoxState.UncheckedNormal:
+ WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Normal);
+ break;
+ }
+
+ if (image != null)
+ g.DrawImage (image, imageBounds);
+
+ if (focused)
+ WidgetPaint.DrawFocusRectangle (g, textBounds);
+
+ if (checkBoxText != String.Empty)
+ TextRenderer.DrawText (g, checkBoxText, font, textBounds, SystemColors.ControlText, flags);
+ }
+ }
+
+ public static bool IsBackgroundPartiallyTransparent (CheckBoxState state)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return false;
+
+ VisualStyleRenderer vsr = GetCheckBoxRenderer (state);
+
+ return vsr.IsBackgroundPartiallyTransparent ();
+ }
+
+ public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return;
+
+ VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedNormal);
+
+ vsr.DrawParentBackground (g, bounds, childControl);
+ }
+
+ public static Size GetGlyphSize (Graphics g, CheckBoxState state)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return new Size (13, 13);
+
+ VisualStyleRenderer vsr = GetCheckBoxRenderer (state);
+
+ return vsr.GetPartSize (g, ThemeSizeType.Draw);
+ }
+ #endregion
+
+ #region Private Static Methods
+ private static VisualStyleRenderer GetCheckBoxRenderer (CheckBoxState state)
+ {
+ switch (state) {
+ case CheckBoxState.CheckedDisabled:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedDisabled);
+ case CheckBoxState.CheckedHot:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedHot);
+ case CheckBoxState.CheckedNormal:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedNormal);
+ case CheckBoxState.CheckedPressed:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedPressed);
+ case CheckBoxState.MixedDisabled:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedDisabled);
+ case CheckBoxState.MixedHot:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedHot);
+ case CheckBoxState.MixedNormal:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedNormal);
+ case CheckBoxState.MixedPressed:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedPressed);
+ case CheckBoxState.UncheckedDisabled:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedDisabled);
+ case CheckBoxState.UncheckedHot:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedHot);
+ case CheckBoxState.UncheckedNormal:
+ default:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedNormal);
+ case CheckBoxState.UncheckedPressed:
+ return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedPressed);
+ }
+ }
+ #endregion
+
+ #region Public Static Properties
+ public static bool RenderMatchingApplicationState {
+ get { return !always_use_visual_styles; }
+ set { always_use_visual_styles = !value; }
+ }
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/Clipboard.cs b/source/ShiftUI/Internal/Clipboard.cs
new file mode 100644
index 0000000..9c832a8
--- /dev/null
+++ b/source/ShiftUI/Internal/Clipboard.cs
@@ -0,0 +1,433 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System;
+using System.Drawing;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Collections;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Threading;
+
+namespace ShiftUI {
+ public sealed class Clipboard {
+ #region Local Variables
+ #endregion // Local Variables
+
+ #region Constructors
+ private Clipboard() {
+ }
+ #endregion // Constructors
+
+ #region Private Methods
+ private static bool ConvertToClipboardData(ref int type, object obj, out byte[] data) {
+ data = null;
+ return false;
+ }
+
+ private static bool ConvertFromClipboardData(int type, IntPtr data, out object obj) {
+ obj = null;
+ if (data == IntPtr.Zero) {
+ return false;
+ }
+ return false;
+ }
+ #endregion // Private Methods
+
+ #region Public Static Methods
+ public static void Clear ()
+ {
+ IntPtr clipboard_handle;
+
+ clipboard_handle = XplatUI.ClipboardOpen (false);
+ XplatUI.ClipboardStore (clipboard_handle, null, 0, null, false);
+ }
+
+ public static bool ContainsAudio ()
+ {
+ return ClipboardContainsFormat (DataFormats.WaveAudio);
+ }
+
+ public static bool ContainsData (string format)
+ {
+ return ClipboardContainsFormat (format);
+ }
+
+ public static bool ContainsFileDropList ()
+ {
+ return ClipboardContainsFormat (DataFormats.FileDrop);
+ }
+
+ public static bool ContainsImage ()
+ {
+ return ClipboardContainsFormat (DataFormats.Bitmap);
+ }
+
+ public static bool ContainsText ()
+ {
+ return ClipboardContainsFormat (DataFormats.Text, DataFormats.UnicodeText);
+ }
+
+ public static bool ContainsText (TextDataFormat format)
+ {
+ switch (format) {
+ case TextDataFormat.Text:
+ return ClipboardContainsFormat (DataFormats.Text);
+ case TextDataFormat.UnicodeText:
+ return ClipboardContainsFormat (DataFormats.UnicodeText);
+ case TextDataFormat.Rtf:
+ return ClipboardContainsFormat (DataFormats.Rtf);
+ case TextDataFormat.Html:
+ return ClipboardContainsFormat (DataFormats.Html);
+ case TextDataFormat.CommaSeparatedValue:
+ return ClipboardContainsFormat (DataFormats.CommaSeparatedValue);
+ }
+
+ return false;
+ }
+
+ public static Stream GetAudioStream ()
+ {
+ IDataObject data = GetDataObject ();
+
+ if (data == null)
+ return null;
+
+ return (Stream)data.GetData (DataFormats.WaveAudio, true);
+ }
+
+ public static Object GetData (string format)
+ {
+ IDataObject data = GetDataObject ();
+
+ if (data == null)
+ return null;
+
+ return data.GetData (format, true);
+ }
+
+ public static IDataObject GetDataObject ()
+ {
+ return GetDataObject (false);
+ }
+
+ public static StringCollection GetFileDropList ()
+ {
+ IDataObject data = GetDataObject ();
+
+ if (data == null)
+ return null;
+
+ return (StringCollection)data.GetData (DataFormats.FileDrop, true);
+ }
+
+ public static Image GetImage ()
+ {
+ IDataObject data = GetDataObject ();
+
+ if (data == null)
+ return null;
+
+ return (Image)data.GetData (DataFormats.Bitmap, true);
+ }
+
+ public static string GetText ()
+ {
+ return GetText (TextDataFormat.UnicodeText);
+ }
+
+ public static string GetText (TextDataFormat format)
+ {
+ if (!Enum.IsDefined (typeof (TextDataFormat), format))
+ throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
+
+ IDataObject data = GetDataObject ();
+
+ if (data == null)
+ return string.Empty;
+
+ string retval;
+
+ switch (format) {
+ case TextDataFormat.Text:
+ default:
+ retval = (string)data.GetData (DataFormats.Text, true);
+ break;
+ case TextDataFormat.UnicodeText:
+ retval = (string)data.GetData (DataFormats.UnicodeText, true);
+ break;
+ case TextDataFormat.Rtf:
+ retval = (string)data.GetData (DataFormats.Rtf, true);
+ break;
+ case TextDataFormat.Html:
+ retval = (string)data.GetData (DataFormats.Html, true);
+ break;
+ case TextDataFormat.CommaSeparatedValue:
+ retval = (string)data.GetData (DataFormats.CommaSeparatedValue, true);
+ break;
+ }
+
+ return retval == null ? string.Empty : retval;
+ }
+
+ public static void SetAudio (byte[] audioBytes)
+ {
+ if (audioBytes == null)
+ throw new ArgumentNullException ("audioBytes");
+
+ MemoryStream ms = new MemoryStream (audioBytes);
+
+ SetAudio (ms);
+ }
+
+ public static void SetAudio (Stream audioStream)
+ {
+ if (audioStream == null)
+ throw new ArgumentNullException ("audioStream");
+
+ SetData (DataFormats.WaveAudio, audioStream);
+ }
+
+ public static void SetData (string format, Object data)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+
+ DataObject data_object = new DataObject (format, data);
+ SetDataObject (data_object);
+ }
+
+ public static void SetDataObject(object data) {
+ SetDataObject(data, false); // MSDN says default behavior is to place non-persistent data to clipboard
+ }
+
+ public static void SetDataObject(object data, bool copy) {
+ SetDataObject(data, copy, 10, 100); // MSDN says default behavior is to try 10 times with 100 ms delay
+ }
+
+ internal static void SetDataObjectImpl(object data, bool copy) {
+ IntPtr clipboard_handle;
+ XplatUI.ObjectToClipboard converter;
+ int native_format;
+ DataFormats.Format item_format;
+
+ converter = new XplatUI.ObjectToClipboard(ConvertToClipboardData);
+
+ clipboard_handle = XplatUI.ClipboardOpen(false);
+ XplatUI.ClipboardStore(clipboard_handle, null, 0, null, copy); // Empty clipboard
+
+ native_format = -1;
+
+ if (data is IDataObject) {
+ string[] formats;
+
+ IDataObject data_object = data as IDataObject;
+ formats = data_object.GetFormats();
+ for (int i = 0; i < formats.Length; i++) {
+ item_format = DataFormats.GetFormat(formats[i]);
+ if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) {
+ native_format = item_format.Id;
+ }
+
+ object obj = data_object.GetData (formats [i]);
+
+ // this is used only by custom formats
+ if (IsDataSerializable (obj))
+ item_format.is_serializable = true;
+
+ XplatUI.ClipboardStore(clipboard_handle, obj, native_format, converter, copy);
+ }
+ } else {
+ item_format = DataFormats.Format.Find(data.GetType().FullName);
+ if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) {
+ native_format = item_format.Id;
+ }
+
+ XplatUI.ClipboardStore(clipboard_handle, data, native_format, converter, copy);
+ }
+ XplatUI.ClipboardClose(clipboard_handle);
+ }
+
+ static bool IsDataSerializable (object obj)
+ {
+ if (obj is ISerializable)
+ return true;
+
+ AttributeCollection attrs = TypeDescriptor.GetAttributes (obj);
+ return attrs [typeof (SerializableAttribute)] != null;
+ }
+
+ public static void SetDataObject(object data, bool copy, int retryTimes, int retryDelay)
+ {
+ if (data == null)
+ throw new ArgumentNullException("data");
+ if (retryTimes < 0)
+ throw new ArgumentOutOfRangeException("retryTimes");
+ if (retryDelay < 0)
+ throw new ArgumentOutOfRangeException("retryDelay");
+
+ // MS implementation actually puts data to clipboard even when retryTimes == 0
+ bool retry = true;
+ do
+ {
+ retry = false;
+ --retryTimes;
+ try
+ {
+ SetDataObjectImpl(data, copy);
+ } catch (ExternalException) {
+ if (retryTimes <= 0)
+ throw;
+ retry = true;
+ Thread.Sleep(retryDelay);
+ }
+ } while (retry && retryTimes > 0);
+ }
+
+ [MonoInternalNote ("Needs additional checks for valid paths, see MSDN")]
+ public static void SetFileDropList (StringCollection filePaths)
+ {
+ if (filePaths == null)
+ throw new ArgumentNullException ("filePaths");
+
+ SetData (DataFormats.FileDrop, filePaths);
+ }
+
+ public static void SetImage (Image image)
+ {
+ if (image == null)
+ throw new ArgumentNullException ("image");
+
+ SetData (DataFormats.Bitmap, image);
+ }
+
+ public static void SetText (string text)
+ {
+ if (string.IsNullOrEmpty (text))
+ throw new ArgumentNullException ("text");
+
+ SetData (DataFormats.UnicodeText, text);
+ }
+
+ public static void SetText (string text, TextDataFormat format)
+ {
+ if (string.IsNullOrEmpty (text))
+ throw new ArgumentNullException ("text");
+ if (!Enum.IsDefined (typeof (TextDataFormat), format))
+ throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
+
+ switch (format) {
+ case TextDataFormat.Text:
+ SetData (DataFormats.Text, text);
+ break;
+ case TextDataFormat.UnicodeText:
+ SetData (DataFormats.UnicodeText, text);
+ break;
+ case TextDataFormat.Rtf:
+ SetData (DataFormats.Rtf, text);
+ break;
+ case TextDataFormat.Html:
+ SetData (DataFormats.Html, text);
+ break;
+ case TextDataFormat.CommaSeparatedValue:
+ SetData (DataFormats.CommaSeparatedValue, text);
+ break;
+ }
+ }
+ #endregion // Public Static Methods
+
+ #region Internal Static Methods
+ internal static IDataObject GetDataObject (bool primary_selection)
+ {
+ DataObject clipboard;
+ IntPtr clipboard_handle;
+ int[] native_formats;
+ DataFormats.Format item_format;
+ object managed_clipboard_item;
+ XplatUI.ClipboardToObject converter;
+
+ converter = new XplatUI.ClipboardToObject (ConvertFromClipboardData);
+
+ clipboard_handle = XplatUI.ClipboardOpen (primary_selection);
+ native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle);
+ if (native_formats == null) {
+ return null; // Clipboard empty
+ }
+
+ // Build the IDataObject
+ clipboard = new DataObject ();
+ for (int i = 0; i < native_formats.Length; i++) {
+ // We might get a format we don't understand or know
+ item_format = DataFormats.GetFormat (native_formats[i]);
+
+ if (item_format != null) {
+ managed_clipboard_item = XplatUI.ClipboardRetrieve (clipboard_handle, native_formats[i], converter);
+
+ if (managed_clipboard_item != null) {
+ clipboard.SetData (item_format.Name, managed_clipboard_item);
+ // We don't handle 'bitmap' since it involves handles, so we'll equate it to dib
+ if (item_format.Name == DataFormats.Dib) {
+ clipboard.SetData (DataFormats.Bitmap, managed_clipboard_item);
+ }
+ }
+ }
+ }
+
+ XplatUI.ClipboardClose (clipboard_handle);
+
+ return clipboard;
+ }
+
+ internal static bool ClipboardContainsFormat (params string[] formats)
+ {
+ IntPtr clipboard_handle;
+ int[] native_formats;
+ DataFormats.Format item_format;
+
+ clipboard_handle = XplatUI.ClipboardOpen (false);
+ native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle);
+
+ if (native_formats == null)
+ return false;
+
+ foreach (int i in native_formats) {
+ // We might get a format we don't understand or know
+ item_format = DataFormats.GetFormat (i);
+
+ if (item_format != null)
+ if (((IList)formats).Contains (item_format.Name))
+ return true;
+ }
+
+ return false;
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/Consts.cs b/source/ShiftUI/Internal/Consts.cs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/source/ShiftUI/Internal/Consts.cs
diff --git a/source/ShiftUI/Internal/ContextMenuStrip.cs b/source/ShiftUI/Internal/ContextMenuStrip.cs
new file mode 100644
index 0000000..052bb04
--- /dev/null
+++ b/source/ShiftUI/Internal/ContextMenuStrip.cs
@@ -0,0 +1,80 @@
+//
+// ContextMenuStrip.cs
+//
+// 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) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI
+{
+ [ComVisible (true)]
+ [ClassInterface (ClassInterfaceType.AutoDispatch)]
+ [DefaultEvent ("Opening")]
+ public class ContextMenuStrip : ToolStripDropDownMenu
+ {
+ Widget source_Widget;
+ internal Widget container;
+
+ #region Public Construtors
+ public ContextMenuStrip () : base ()
+ {
+ source_Widget = null;
+ }
+
+ public ContextMenuStrip (IContainer container) : base ()
+ {
+ source_Widget = null;
+ }
+ #endregion
+
+ #region Public Properties
+ [Browsable (false)]
+ //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ public Widget SourceWidget {
+ get { return this.source_Widget; }
+ }
+ #endregion
+
+ #region Protected Methods
+ protected override void Dispose (bool disposing)
+ {
+ base.Dispose (disposing);
+ }
+
+ protected override void SetVisibleCore (bool visible)
+ {
+ base.SetVisibleCore (visible);
+ if (visible)
+ XplatUI.SetTopmost (this.Handle, true);
+ }
+ #endregion
+
+ internal void SetSourceWidget (Widget source_Widget)
+ {
+ container = this.source_Widget = source_Widget;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/ControlBindingsCollection.cs b/source/ShiftUI/Internal/ControlBindingsCollection.cs
new file mode 100644
index 0000000..345efee
--- /dev/null
+++ b/source/ShiftUI/Internal/ControlBindingsCollection.cs
@@ -0,0 +1,204 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Reflection;
+
+
+namespace ShiftUI {
+ [DefaultEvent("CollectionChanged")]
+ public class WidgetBindingsCollection : BindingsCollection {
+ #region Fields
+ private Widget control;
+ private IBindableComponent bindable_component;
+ private DataSourceUpdateMode default_datasource_update_mode;
+ #endregion // Fields
+
+ #region Constructors
+ internal WidgetBindingsCollection (Widget control) {
+ this.control = control;
+ bindable_component = this.control as IBindableComponent;
+ default_datasource_update_mode = DataSourceUpdateMode.OnValidation;
+ }
+
+ public WidgetBindingsCollection (IBindableComponent control)
+ {
+ bindable_component = control;
+ control = control as Widget;
+ default_datasource_update_mode = DataSourceUpdateMode.OnValidation;
+ }
+ #endregion // Constructors
+
+ #region Public Instance Properties
+ public Widget Widget {
+ get {
+ return control;
+ }
+ }
+
+ public Binding this[string propertyName] {
+ get {
+ foreach (Binding b in base.List) {
+ if (b.PropertyName == propertyName) {
+ return b;
+ }
+ }
+ return null;
+ }
+ }
+
+ public IBindableComponent BindableComponent {
+ get {
+ return bindable_component;
+ }
+ }
+
+ public DataSourceUpdateMode DefaultDataSourceUpdateMode {
+ get {
+ return default_datasource_update_mode;
+ }
+ set {
+ default_datasource_update_mode = value;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Instance Methods
+ public new void Add (Binding binding)
+ {
+ AddCore (binding);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, binding));
+ }
+
+ public Binding Add (string propertyName, object dataSource, string dataMember)
+ {
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+
+ Binding res = new Binding (propertyName, dataSource, dataMember);
+ res.DataSourceUpdateMode = default_datasource_update_mode;
+ Add (res);
+ return res;
+ }
+
+ public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled)
+ {
+ return Add (propertyName, dataSource, dataMember, formattingEnabled, default_datasource_update_mode, null, String.Empty, null);
+ }
+
+ public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode)
+ {
+ return Add (propertyName, dataSource, dataMember, formattingEnabled, updateMode, null, String.Empty, null);
+ }
+
+ public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode,
+ object nullValue)
+ {
+ return Add (propertyName, dataSource, dataMember, formattingEnabled, updateMode, nullValue, String.Empty, null);
+ }
+
+ public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode,
+ object nullValue, string formatString)
+ {
+ return Add (propertyName, dataSource, dataMember, formattingEnabled, updateMode, nullValue, formatString, null);
+ }
+
+ public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode,
+ object nullValue, string formatString, IFormatProvider formatInfo)
+ {
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+
+ Binding res = new Binding (propertyName, dataSource, dataMember);
+ res.FormattingEnabled = formattingEnabled;
+ res.DataSourceUpdateMode = updateMode;
+ res.NullValue = nullValue;
+ res.FormatString = formatString;
+ res.FormatInfo = formatInfo;
+
+ Add (res);
+ return res;
+ }
+
+ public new void Clear() {
+ base.Clear();
+ }
+
+ public new void Remove (Binding binding) {
+ if (binding == null)
+ throw new NullReferenceException("The binding is null");
+
+ base.Remove(binding);
+ }
+
+ public new void RemoveAt(int index) {
+ if (index < 0 || index >= base.List.Count)
+ throw new ArgumentOutOfRangeException("index");
+
+ base.RemoveAt(index);
+ }
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+ protected override void AddCore (Binding dataBinding)
+ {
+ if (dataBinding == null)
+ throw new ArgumentNullException ("dataBinding");
+
+ if (dataBinding.Widget != null && dataBinding.BindableComponent != bindable_component)
+ throw new ArgumentException ("dataBinding belongs to another BindingsCollection");
+
+ for (int i = 0; i < Count; i++) {
+ Binding bnd = this [i];
+ if (bnd == null || bnd.PropertyName.Length == 0 || dataBinding.PropertyName.Length == 0) {
+ continue;
+ }
+
+ if (String.Compare (bnd.PropertyName, dataBinding.PropertyName, true) == 0) {
+ throw new ArgumentException ("The binding is already in the collection");
+ }
+ }
+
+ dataBinding.SetWidget (bindable_component);
+ dataBinding.Check ();
+ base.AddCore (dataBinding);
+ }
+
+ protected override void ClearCore() {
+ base.ClearCore ();
+ }
+
+ protected override void RemoveCore (Binding dataBinding) {
+ if (dataBinding == null)
+ throw new ArgumentNullException ("dataBinding");
+
+ base.RemoveCore (dataBinding);
+ }
+ #endregion // Protected Instance Methods
+ }
+}
+
diff --git a/source/ShiftUI/Internal/ControlEventArgs.cs b/source/ShiftUI/Internal/ControlEventArgs.cs
new file mode 100644
index 0000000..17eb992
--- /dev/null
+++ b/source/ShiftUI/Internal/ControlEventArgs.cs
@@ -0,0 +1,49 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+
+// COMPLETE
+using System;
+
+namespace ShiftUI {
+ public class WidgetEventArgs : EventArgs {
+ private Widget control;
+
+ #region Public Constructors
+ public WidgetEventArgs(Widget control) {
+ this.control=control;
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ public Widget Widget {
+ get {
+ return this.control;
+ }
+ }
+ #endregion // Public Instance Properties
+ }
+}
diff --git a/source/ShiftUI/Internal/ControlEventHandler.cs b/source/ShiftUI/Internal/ControlEventHandler.cs
new file mode 100644
index 0000000..faed044
--- /dev/null
+++ b/source/ShiftUI/Internal/ControlEventHandler.cs
@@ -0,0 +1,32 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+
+// COMPLETE
+
+namespace ShiftUI {
+ public delegate void WidgetEventHandler (object sender, WidgetEventArgs e);
+}
diff --git a/source/ShiftUI/Internal/ControlHandler.cs b/source/ShiftUI/Internal/ControlHandler.cs
new file mode 100644
index 0000000..08be9bd
--- /dev/null
+++ b/source/ShiftUI/Internal/ControlHandler.cs
@@ -0,0 +1,229 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.CarbonInternal {
+ internal class WidgetHandler : EventHandlerBase, IEventHandler {
+ internal const uint kEventWidgetInitialize = 1000;
+ internal const uint kEventWidgetDispose = 1001;
+ internal const uint kEventWidgetGetOptimalBounds = 1003;
+ internal const uint kEventWidgetDefInitialize = kEventWidgetInitialize;
+ internal const uint kEventWidgetDefDispose = kEventWidgetDispose;
+ internal const uint kEventWidgetHit = 1;
+ internal const uint kEventWidgetsimulateHit = 2;
+ internal const uint kEventWidgetHitTest = 3;
+ internal const uint kEventWidgetDraw = 4;
+ internal const uint kEventWidgetApplyBackground = 5;
+ internal const uint kEventWidgetApplyTextColor = 6;
+ internal const uint kEventWidgetsetFocusPart = 7;
+ internal const uint kEventWidgetGetFocusPart = 8;
+ internal const uint kEventWidgetActivate = 9;
+ internal const uint kEventWidgetDeactivate = 10;
+ internal const uint kEventWidgetsetCursor = 11;
+ internal const uint kEventWidgetContextualMenuClick = 12;
+ internal const uint kEventWidgetClick = 13;
+ internal const uint kEventWidgetGetNextFocusCandidate = 14;
+ internal const uint kEventWidgetGetAutoToggleValue = 15;
+ internal const uint kEventWidgetInterceptSubviewClick = 16;
+ internal const uint kEventWidgetGetClickActivation = 17;
+ internal const uint kEventWidgetDragEnter = 18;
+ internal const uint kEventWidgetDragWithin = 19;
+ internal const uint kEventWidgetDragLeave = 20;
+ internal const uint kEventWidgetDragReceive = 21;
+ internal const uint kEventWidgetInvalidateForSizeChange = 22;
+ internal const uint kEventWidgetTrackingAreaEntered = 23;
+ internal const uint kEventWidgetTrackingAreaExited = 24;
+ internal const uint kEventWidgetTrack = 51;
+ internal const uint kEventWidgetGetScrollToHereStartPoint = 52;
+ internal const uint kEventWidgetGetIndicatorDragConstraint = 53;
+ internal const uint kEventWidgetIndicatorMoved = 54;
+ internal const uint kEventWidgetGhostingFinished = 55;
+ internal const uint kEventWidgetGetActionProcPart = 56;
+ internal const uint kEventWidgetGetPartRegion = 101;
+ internal const uint kEventWidgetGetPartBounds = 102;
+ internal const uint kEventWidgetsetData = 103;
+ internal const uint kEventWidgetGetData = 104;
+ internal const uint kEventWidgetGetSizeConstraints= 105;
+ internal const uint kEventWidgetGetFrameMetrics = 106;
+ internal const uint kEventWidgetValueFieldChanged = 151;
+ internal const uint kEventWidgetAddedSubWidget = 152;
+ internal const uint kEventWidgetRemovingSubWidget = 153;
+ internal const uint kEventWidgetBoundsChanged = 154;
+ internal const uint kEventWidgetVisibilityChanged = 157;
+ internal const uint kEventWidgetTitleChanged = 158;
+ internal const uint kEventWidgetOwningWindowChanged = 159;
+ internal const uint kEventWidgetHiliteChanged = 160;
+ internal const uint kEventWidgetEnabledStateChanged = 161;
+ internal const uint kEventWidgetLayoutInfoChanged = 162;
+ internal const uint kEventWidgetArbitraryMessage = 201;
+
+ internal const uint kEventParamCGContextRef = 1668183160;
+ internal const uint kEventParamDirectObject = 757935405;
+ internal const uint kEventParamWidgetPart = 1668313716;
+ internal const uint kEventParamWidgetLikesDrag = 1668047975;
+ internal const uint kEventParamRgnHandle = 1919381096;
+ internal const uint typeWidgetRef = 1668575852;
+ internal const uint typeCGContextRef = 1668183160;
+ internal const uint typeQDPoint = 1363439732;
+ internal const uint typeQDRgnHandle = 1919381096;
+ internal const uint typeWidgetPartCode = 1668313716;
+ internal const uint typeBoolean = 1651470188;
+
+ internal WidgetHandler (XplatUICarbon driver) : base (driver) {}
+
+ public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
+ Hwnd hwnd;
+ bool client;
+
+ GetEventParameter (eventref, kEventParamDirectObject, typeWidgetRef, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref handle);
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd == null)
+ return false;
+
+ msg.hwnd = hwnd.Handle;
+ client = (hwnd.ClientWindow == handle ? true : false);
+
+ switch (kind) {
+ case kEventWidgetDraw: {
+ IntPtr rgn = IntPtr.Zero;
+ HIRect bounds = new HIRect ();
+
+ GetEventParameter (eventref, kEventParamRgnHandle, typeQDRgnHandle, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref rgn);
+
+ if (rgn != IntPtr.Zero) {
+ Rect rbounds = new Rect ();
+
+ GetRegionBounds (rgn, ref rbounds);
+
+ bounds.origin.x = rbounds.left;
+ bounds.origin.y = rbounds.top;
+ bounds.size.width = rbounds.right - rbounds.left;
+ bounds.size.height = rbounds.bottom - rbounds.top;
+ } else {
+ HIViewGetBounds (handle, ref bounds);
+ }
+
+ if (!hwnd.visible) {
+ if (client) {
+ hwnd.expose_pending = false;
+ } else {
+ hwnd.nc_expose_pending = false;
+ }
+ return false;
+ }
+
+ if (!client) {
+ DrawBorders (hwnd);
+ }
+
+ Driver.AddExpose (hwnd, client, bounds);
+
+ return true;
+ }
+ case kEventWidgetVisibilityChanged: {
+ if (client) {
+ msg.message = Msg.WM_SHOWWINDOW;
+ msg.lParam = (IntPtr) 0;
+ msg.wParam = (HIViewIsVisible (handle) ? (IntPtr)1 : (IntPtr)0);
+ return true;
+ }
+ return false;
+ }
+ case kEventWidgetBoundsChanged: {
+ HIRect view_frame = new HIRect ();
+
+ HIViewGetFrame (handle, ref view_frame);
+ if (!client) {
+ hwnd.X = (int) view_frame.origin.x;
+ hwnd.Y = (int) view_frame.origin.y;
+ hwnd.Width = (int) view_frame.size.width;
+ hwnd.Height = (int) view_frame.size.height;
+ Driver.PerformNCCalc (hwnd);
+ }
+
+ msg.message = Msg.WM_WINDOWPOSCHANGED;
+ msg.hwnd = hwnd.Handle;
+
+ return true;
+ }
+ case kEventWidgetGetFocusPart: {
+ short pcode = 0;
+ SetEventParameter (eventref, kEventParamWidgetPart, typeWidgetPartCode, (uint)Marshal.SizeOf (typeof (short)), ref pcode);
+ return false;
+ }
+ case kEventWidgetDragEnter:
+ case kEventWidgetDragWithin:
+ case kEventWidgetDragLeave:
+ case kEventWidgetDragReceive:
+ return Dnd.HandleEvent (callref, eventref, handle, kind, ref msg);
+ }
+ return false;
+ }
+
+ private void DrawBorders (Hwnd hwnd) {
+ switch (hwnd.border_style) {
+ case FormBorderStyle.Fixed3D: {
+ Graphics g;
+
+ g = Graphics.FromHwnd(hwnd.whole_window);
+ if (hwnd.border_static)
+ WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter);
+ else
+ WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken);
+ g.Dispose();
+ break;
+ }
+
+ case FormBorderStyle.FixedSingle: {
+ Graphics g;
+
+ g = Graphics.FromHwnd(hwnd.whole_window);
+ WidgetPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
+ g.Dispose();
+ break;
+ }
+ }
+ }
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetRegionBounds (IntPtr rgnhandle, ref Rect region);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int SetEventParameter (IntPtr eventref, uint name, uint type, uint size, ref short data);
+
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int HIViewGetBounds (IntPtr handle, ref HIRect rect);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int HIViewGetFrame (IntPtr handle, ref HIRect rect);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static bool HIViewIsVisible (IntPtr vHnd);
+ }
+}
diff --git a/source/ShiftUI/Internal/ControlPaint.cs b/source/ShiftUI/Internal/ControlPaint.cs
new file mode 100644
index 0000000..d469f51
--- /dev/null
+++ b/source/ShiftUI/Internal/ControlPaint.cs
@@ -0,0 +1,495 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+
+// NOT COMPLETE
+
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System;
+
+namespace ShiftUI {
+ public sealed class WidgetPaint {
+ #region Local Variables
+ static int RGBMax=255;
+ static int HLSMax=255;
+ #endregion // Local Variables
+
+ #region Private Enumerations
+
+
+ #region Constructor
+ // Prevent a public constructor from being created
+ private WidgetPaint() {
+ }
+ #endregion // Constructor
+
+
+ #endregion // Private Enumerations
+
+ #region Helpers
+ internal static void Color2HBS(Color color, out int h, out int l, out int s) {
+ int r;
+ int g;
+ int b;
+ int cMax;
+ int cMin;
+ int rDelta;
+ int gDelta;
+ int bDelta;
+
+ r=color.R;
+ g=color.G;
+ b=color.B;
+
+ cMax = Math.Max(Math.Max(r, g), b);
+ cMin = Math.Min(Math.Min(r, g), b);
+
+ l = (((cMax+cMin)*HLSMax)+RGBMax)/(2*RGBMax);
+
+ if (cMax==cMin) { // Achromatic
+ h=0; // h undefined
+ s=0;
+ return;
+ }
+
+ /* saturation */
+ if (l<=(HLSMax/2)) {
+ s=(((cMax-cMin)*HLSMax)+((cMax+cMin)/2))/(cMax+cMin);
+ } else {
+ s=(((cMax-cMin)*HLSMax)+((2*RGBMax-cMax-cMin)/2))/(2*RGBMax-cMax-cMin);
+ }
+
+ /* hue */
+ rDelta=(((cMax-r)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin);
+ gDelta=(((cMax-g)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin);
+ bDelta=(((cMax-b)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin);
+
+ if (r == cMax) {
+ h=bDelta - gDelta;
+ } else if (g == cMax) {
+ h=(HLSMax/3) + rDelta - bDelta;
+ } else { /* B == cMax */
+ h=((2*HLSMax)/3) + gDelta - rDelta;
+ }
+
+ if (h<0) {
+ h+=HLSMax;
+ }
+
+ if (h>HLSMax) {
+ h-=HLSMax;
+ }
+ }
+
+ private static int HueToRGB(int n1, int n2, int hue) {
+ if (hue<0) {
+ hue+=HLSMax;
+ }
+
+ if (hue>HLSMax) {
+ hue -= HLSMax;
+ }
+
+ /* return r,g, or b value from this tridrant */
+ if (hue<(HLSMax/6)) {
+ return(n1+(((n2-n1)*hue+(HLSMax/12))/(HLSMax/6)));
+ }
+
+ if (hue<(HLSMax/2)) {
+ return(n2);
+ }
+
+ if (hue<((HLSMax*2)/3)) {
+ return(n1+(((n2-n1)*(((HLSMax*2)/3)-hue)+(HLSMax/12))/(HLSMax/6)));
+ } else {
+ return(n1);
+ }
+ }
+
+ internal static Color HBS2Color(int hue, int lum, int sat) {
+ int R;
+ int G;
+ int B;
+ int Magic1;
+ int Magic2;
+
+ if (sat == 0) { /* Achromatic */
+ R=G=B=(lum*RGBMax)/HLSMax;
+ // FIXME : Should throw exception if hue!=0
+ } else {
+ if (lum<=(HLSMax/2)) {
+ Magic2=(lum*(HLSMax+sat)+(HLSMax/2))/HLSMax;
+ } else {
+ Magic2=sat+lum-((sat*lum)+(HLSMax/2))/HLSMax;
+ }
+ Magic1=2*lum-Magic2;
+
+ R = Math.Min(255, (HueToRGB(Magic1,Magic2,hue+(HLSMax/3))*RGBMax+(HLSMax/2))/HLSMax);
+ G = Math.Min(255, (HueToRGB(Magic1,Magic2,hue)*RGBMax+(HLSMax/2))/HLSMax);
+ B = Math.Min(255, (HueToRGB(Magic1,Magic2,hue-(HLSMax/3))*RGBMax+(HLSMax/2))/HLSMax);
+ }
+ return (Color.FromArgb(R, G, B));
+ }
+ #endregion // Helpers
+
+ #region Public Static Properties
+ public static Color ContrastControlDark {
+ get { return(SystemColors.ControlDark); }
+ }
+ #endregion // Public Static Properties
+
+ #region Public Static Methods
+ [MonoTODO ("Not implemented, will throw NotImplementedException")]
+ public static IntPtr CreateHBitmap16Bit (Bitmap bitmap, Color background)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO ("Not implemented, will throw NotImplementedException")]
+ public static IntPtr CreateHBitmapColorMask (Bitmap bitmap, IntPtr monochromeMask)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO ("Not implemented, will throw NotImplementedException")]
+ public static IntPtr CreateHBitmapTransparencyMask (Bitmap bitmap)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static Color Light(Color baseColor) {
+ return Light(baseColor, 0.5f);
+ }
+
+ public static Color Light (Color baseColor, float percOfLightLight)
+ {
+ if (baseColor.ToArgb () == ThemeEngine.Current.ColorControl.ToArgb ()) {
+ int r_sub, g_sub, b_sub;
+ Color color;
+
+ if (percOfLightLight <= 0f)
+ return ThemeEngine.Current.ColorControlLight;
+
+ if (percOfLightLight == 1.0f)
+ return ThemeEngine.Current.ColorControlLightLight;
+
+ r_sub = ThemeEngine.Current.ColorControlLightLight.R - ThemeEngine.Current.ColorControlLight.R;
+ g_sub = ThemeEngine.Current.ColorControlLightLight.G - ThemeEngine.Current.ColorControlLight.G;
+ b_sub = ThemeEngine.Current.ColorControlLightLight.B - ThemeEngine.Current.ColorControlLight.B;
+
+ color = Color.FromArgb (ThemeEngine.Current.ColorControlLight.A,
+ (int) (ThemeEngine.Current.ColorControlLight.R + (r_sub * percOfLightLight)),
+ (int) (ThemeEngine.Current.ColorControlLight.G + (g_sub * percOfLightLight)),
+ (int) (ThemeEngine.Current.ColorControlLight.B + (b_sub * percOfLightLight)));
+ return color;
+ }
+
+ int H, I, S;
+
+ WidgetPaint.Color2HBS (baseColor, out H, out I, out S);
+ int NewIntensity = Math.Min (255, I + (int) ((255 - I) * 0.5f * percOfLightLight));
+
+ return WidgetPaint.HBS2Color (H, NewIntensity, S);
+ }
+
+ public static Color LightLight (Color baseColor)
+ {
+ return Light(baseColor, 1.0f);
+ }
+
+ public static Color Dark (Color baseColor)
+ {
+ return Dark(baseColor, 0.5f);
+ }
+
+ public static Color Dark (Color baseColor, float percOfDarkDark)
+ {
+ if (baseColor.ToArgb () == ThemeEngine.Current.ColorControl.ToArgb ()) {
+
+ int r_sub, g_sub, b_sub;
+ Color color;
+
+ if (percOfDarkDark <= 0f)
+ return ThemeEngine.Current.ColorControlDark;
+
+ if (percOfDarkDark == 1.0f)
+ return ThemeEngine.Current.ColorControlDarkDark;
+
+ r_sub = ThemeEngine.Current.ColorControlDarkDark.R - ThemeEngine.Current.ColorControlDark.R;
+ g_sub = ThemeEngine.Current.ColorControlDarkDark.G - ThemeEngine.Current.ColorControlDark.G;
+ b_sub = ThemeEngine.Current.ColorControlDarkDark.B - ThemeEngine.Current.ColorControlDark.B;
+
+ color = Color.FromArgb (ThemeEngine.Current.ColorControlDark.A,
+ (int) (ThemeEngine.Current.ColorControlDark.R + (r_sub * percOfDarkDark)),
+ (int) (ThemeEngine.Current.ColorControlDark.G + (g_sub * percOfDarkDark)),
+ (int) (ThemeEngine.Current.ColorControlDark.B + (b_sub * percOfDarkDark)));
+ return color;
+ }
+
+ int H, I, S;
+
+ WidgetPaint.Color2HBS(baseColor, out H, out I, out S);
+ int PreIntensity = Math.Max (0, I - (int) (I * 0.333f));
+ int NewIntensity = Math.Max (0, PreIntensity - (int) (PreIntensity * percOfDarkDark));
+ return WidgetPaint.HBS2Color(H, NewIntensity, S);
+ }
+
+ public static Color DarkDark (Color baseColor)
+ {
+ return Dark(baseColor, 1.0f);
+ }
+
+ public static void DrawBorder (Graphics graphics, Rectangle bounds, Color color, ButtonBorderStyle style)
+ {
+ int line_width_top_left = 1;
+ int line_width_bottom_right = 1;
+
+ if (style == ButtonBorderStyle.Inset)
+ line_width_top_left = 2;
+ if (style == ButtonBorderStyle.Outset) {
+ line_width_bottom_right = 2;
+ line_width_top_left = 2;
+ }
+
+ DrawBorder(graphics, bounds, color, line_width_top_left, style, color, line_width_top_left, style, color, line_width_bottom_right, style, color, line_width_bottom_right, style);
+ }
+
+ internal static void DrawBorder (Graphics graphics, RectangleF bounds, Color color, ButtonBorderStyle style)
+ {
+ int line_width_top_left = 1;
+ int line_width_bottom_right = 1;
+
+ if (style == ButtonBorderStyle.Inset)
+ line_width_top_left = 2;
+ if (style == ButtonBorderStyle.Outset) {
+ line_width_bottom_right = 2;
+ line_width_top_left = 2;
+ }
+
+ ThemeEngine.Current.CPDrawBorder (graphics, bounds, color, line_width_top_left, style, color, line_width_top_left, style, color, line_width_bottom_right, style, color, line_width_bottom_right, style);
+ }
+
+ public static void DrawBorder( Graphics graphics, Rectangle bounds, Color leftColor, int leftWidth,
+ ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle,
+ Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, int bottomWidth,
+ ButtonBorderStyle bottomStyle) {
+
+ ThemeEngine.Current.CPDrawBorder (graphics, bounds, leftColor, leftWidth,
+ leftStyle, topColor, topWidth, topStyle, rightColor, rightWidth, rightStyle,
+ bottomColor, bottomWidth, bottomStyle);
+ }
+
+
+ public static void DrawBorder3D(Graphics graphics, Rectangle rectangle) {
+ DrawBorder3D(graphics, rectangle, Border3DStyle.Etched, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom);
+ }
+
+ public static void DrawBorder3D(Graphics graphics, Rectangle rectangle, Border3DStyle style) {
+ DrawBorder3D(graphics, rectangle, style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom);
+ }
+
+ public static void DrawBorder3D(Graphics graphics, int x, int y, int width, int height) {
+ DrawBorder3D(graphics, new Rectangle(x, y, width, height), Border3DStyle.Etched, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom);
+ }
+
+ public static void DrawBorder3D(Graphics graphics, int x, int y, int width, int height, Border3DStyle style) {
+ DrawBorder3D(graphics, new Rectangle(x, y, width, height), style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom);
+ }
+
+ public static void DrawBorder3D( Graphics graphics, int x, int y, int width, int height, Border3DStyle style,Border3DSide sides) {
+ DrawBorder3D( graphics, new Rectangle(x, y, width, height), style, sides);
+ }
+
+ public static void DrawBorder3D( Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides) {
+
+ ThemeEngine.Current.CPDrawBorder3D (graphics, rectangle, style, sides);
+ }
+
+ public static void DrawButton( Graphics graphics, int x, int y, int width, int height, ButtonState state) {
+ DrawButton(graphics, new Rectangle(x, y, width, height), state);
+ }
+
+ public static void DrawButton( Graphics graphics, Rectangle rectangle, ButtonState state) {
+
+ ThemeEngine.Current.CPDrawButton (graphics, rectangle, state);
+ }
+
+
+ public static void DrawCaptionButton(Graphics graphics, int x, int y, int width, int height, CaptionButton button, ButtonState state) {
+ DrawCaptionButton(graphics, new Rectangle(x, y, width, height), button, state);
+ }
+
+ public static void DrawCaptionButton(Graphics graphics, Rectangle rectangle, CaptionButton button, ButtonState state) {
+
+ ThemeEngine.Current.CPDrawCaptionButton (graphics, rectangle, button, state);
+ }
+
+ public static void DrawCheckBox(Graphics graphics, int x, int y, int width, int height, ButtonState state) {
+ DrawCheckBox(graphics, new Rectangle(x, y, width, height), state);
+ }
+
+ public static void DrawCheckBox(Graphics graphics, Rectangle rectangle, ButtonState state) {
+
+ ThemeEngine.Current.CPDrawCheckBox (graphics, rectangle, state);
+ }
+
+ public static void DrawComboButton(Graphics graphics, Rectangle rectangle, ButtonState state) {
+
+ ThemeEngine.Current.CPDrawComboButton (graphics, rectangle, state);
+ }
+
+ public static void DrawComboButton(Graphics graphics, int x, int y, int width, int height, ButtonState state) {
+ DrawComboButton(graphics, new Rectangle(x, y, width, height), state);
+ }
+
+ public static void DrawContainerGrabHandle(Graphics graphics, Rectangle bounds) {
+
+ ThemeEngine.Current.CPDrawContainerGrabHandle (graphics, bounds);
+ }
+
+ public static void DrawFocusRectangle( Graphics graphics, Rectangle rectangle) {
+ DrawFocusRectangle(graphics, rectangle, SystemColors.Control, SystemColors.ControlText);
+ }
+
+ public static void DrawFocusRectangle( Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor) {
+
+ ThemeEngine.Current.CPDrawFocusRectangle (graphics, rectangle, foreColor, backColor);
+ }
+
+ public static void DrawGrabHandle(Graphics graphics, Rectangle rectangle, bool primary, bool enabled) {
+
+ ThemeEngine.Current.CPDrawGrabHandle (graphics, rectangle, primary, enabled);
+ }
+
+ public static void DrawGrid(Graphics graphics, Rectangle area, Size pixelsBetweenDots, Color backColor) {
+
+ ThemeEngine.Current.CPDrawGrid (graphics, area, pixelsBetweenDots, backColor);
+ }
+
+ public static void DrawImageDisabled(Graphics graphics, Image image, int x, int y, Color background) {
+
+ ThemeEngine.Current.CPDrawImageDisabled (graphics, image, x, y, background);
+ }
+
+ public static void DrawLockedFrame(Graphics graphics, Rectangle rectangle, bool primary) {
+
+ ThemeEngine.Current.CPDrawLockedFrame (graphics, rectangle, primary);
+ }
+
+ public static void DrawMenuGlyph(Graphics graphics, Rectangle rectangle, MenuGlyph glyph) {
+
+ ThemeEngine.Current.CPDrawMenuGlyph (graphics, rectangle, glyph, ThemeEngine.Current.ColorMenuText, Color.Empty);
+ }
+
+ public static void DrawMenuGlyph (Graphics graphics, Rectangle rectangle, MenuGlyph glyph, Color foreColor, Color backColor)
+ {
+ ThemeEngine.Current.CPDrawMenuGlyph (graphics, rectangle, glyph, foreColor, backColor);
+ }
+
+ public static void DrawMenuGlyph(Graphics graphics, int x, int y, int width, int height, MenuGlyph glyph) {
+ DrawMenuGlyph(graphics, new Rectangle(x, y, width, height), glyph);
+ }
+
+ public static void DrawMenuGlyph (Graphics graphics, int x, int y, int width, int height, MenuGlyph glyph, Color foreColor, Color backColor)
+ {
+ DrawMenuGlyph (graphics, new Rectangle (x, y, width, height), glyph, foreColor, backColor);
+ }
+
+ public static void DrawMixedCheckBox(Graphics graphics, Rectangle rectangle, ButtonState state) {
+ ThemeEngine.Current.CPDrawMixedCheckBox (graphics, rectangle, state);
+ }
+
+ public static void DrawMixedCheckBox(Graphics graphics, int x, int y, int width, int height, ButtonState state) {
+ DrawMixedCheckBox(graphics, new Rectangle(x, y, width, height), state);
+ }
+
+
+ public static void DrawRadioButton(Graphics graphics, int x, int y, int width, int height, ButtonState state) {
+ DrawRadioButton(graphics, new Rectangle(x, y, width, height), state);
+ }
+
+ public static void DrawRadioButton(Graphics graphics, Rectangle rectangle, ButtonState state) {
+
+ ThemeEngine.Current.CPDrawRadioButton (graphics, rectangle, state);
+ }
+
+ public static void DrawReversibleFrame(Rectangle rectangle, Color backColor, FrameStyle style) {
+ XplatUI.DrawReversibleFrame (rectangle, backColor, style);
+ }
+
+ public static void DrawReversibleLine(Point start, Point end, Color backColor) {
+ XplatUI.DrawReversibleLine (start, end, backColor);
+ }
+
+ public static void FillReversibleRectangle(Rectangle rectangle, Color backColor) {
+ XplatUI.FillReversibleRectangle (rectangle, backColor);
+ }
+
+ public static void DrawScrollButton (Graphics graphics, int x, int y, int width, int height, ScrollButton button, ButtonState state) {
+ ThemeEngine.Current.CPDrawScrollButton (graphics, new Rectangle(x, y, width, height), button, state);
+ }
+
+ public static void DrawScrollButton (Graphics graphics, Rectangle rectangle, ScrollButton button, ButtonState state) {
+ ThemeEngine.Current.CPDrawScrollButton (graphics, rectangle, button, state);
+ }
+
+ [MonoTODO ("Stub, does nothing")]
+ private static bool DSFNotImpl = false;
+ public static void DrawSelectionFrame(Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect, Color backColor) {
+ if (!DSFNotImpl) {
+ DSFNotImpl = true;
+ Console.WriteLine("NOT IMPLEMENTED: DrawSelectionFrame(Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect, Color backColor)");
+ }
+ //throw new NotImplementedException();
+ }
+
+ public static void DrawSizeGrip (Graphics graphics, Color backColor, Rectangle bounds)
+ {
+ ThemeEngine.Current.CPDrawSizeGrip (graphics, backColor, bounds);
+ }
+
+ public static void DrawSizeGrip(Graphics graphics, Color backColor, int x, int y, int width, int height) {
+ DrawSizeGrip(graphics, backColor, new Rectangle(x, y, width, height));
+ }
+
+ public static void DrawStringDisabled(Graphics graphics, string s, Font font, Color color, RectangleF layoutRectangle, StringFormat format) {
+
+ ThemeEngine.Current.CPDrawStringDisabled (graphics, s, font, color, layoutRectangle, format);
+ }
+
+ public static void DrawStringDisabled (IDeviceContext dc, string s, Font font, Color color, Rectangle layoutRectangle, TextFormatFlags format)
+ {
+ ThemeEngine.Current.CPDrawStringDisabled (dc, s, font, color, layoutRectangle, format);
+ }
+
+ public static void DrawVisualStyleBorder (Graphics graphics, Rectangle bounds)
+ {
+ ThemeEngine.Current.CPDrawVisualStyleBorder (graphics, bounds);
+ }
+ #endregion // Public Static Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/CurrencyManager.cs b/source/ShiftUI/Internal/CurrencyManager.cs
new file mode 100644
index 0000000..9f68fd4
--- /dev/null
+++ b/source/ShiftUI/Internal/CurrencyManager.cs
@@ -0,0 +1,453 @@
+// 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) 2005 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+// Ivan N. Zlatev ([email protected])
+//
+
+using System;
+using System.Data;
+using System.Reflection;
+using System.Collections;
+using System.ComponentModel;
+
+namespace ShiftUI {
+ public class CurrencyManager : BindingManagerBase {
+
+ protected int listposition;
+ protected Type finalType;
+
+ private IList list;
+ private bool binding_suspended;
+
+ private object data_source;
+
+ bool editing;
+
+ internal CurrencyManager ()
+ {
+ }
+
+ internal CurrencyManager (object data_source)
+ {
+ SetDataSource (data_source);
+ }
+
+ public IList List {
+ get { return list; }
+ }
+
+ public override object Current {
+ get {
+ if (listposition == -1 || listposition >= list.Count) {
+ // Console.WriteLine ("throwing exception from here");
+ // Console.WriteLine (Environment.StackTrace);
+ throw new IndexOutOfRangeException ("list position");
+ }
+ return list [listposition];
+ }
+ }
+
+ public override int Count {
+ get { return list.Count; }
+ }
+
+ public override int Position {
+ get {
+ return listposition;
+ }
+ set {
+ if (value < 0)
+ value = 0;
+ if (value >= list.Count)
+ value = list.Count - 1;
+ if (listposition == value)
+ return;
+
+ if (listposition != -1)
+ EndCurrentEdit ();
+
+ listposition = value;
+ OnCurrentChanged (EventArgs.Empty);
+ OnPositionChanged (EventArgs.Empty);
+ }
+ }
+
+ internal void SetDataSource (object data_source)
+ {
+ if (this.data_source is IBindingList)
+ ((IBindingList)this.data_source).ListChanged -= new ListChangedEventHandler (ListChangedHandler);
+
+ if (data_source is IListSource)
+ data_source = ((IListSource)data_source).GetList();
+
+ this.data_source = data_source;
+ if (data_source != null)
+ this.finalType = data_source.GetType();
+
+ listposition = -1;
+ if (this.data_source is IBindingList)
+ ((IBindingList)this.data_source).ListChanged += new ListChangedEventHandler (ListChangedHandler);
+
+ list = (IList)data_source;
+
+ // XXX this is wrong. MS invokes OnItemChanged directly, which seems to call PushData.
+ ListChangedHandler (null, new ListChangedEventArgs (ListChangedType.Reset, -1));
+ }
+
+ public override PropertyDescriptorCollection GetItemProperties ()
+ {
+ return ListBindingHelper.GetListItemProperties (list);
+ }
+
+ public override void RemoveAt (int index)
+ {
+ list.RemoveAt (index);
+ }
+
+ public override void SuspendBinding ()
+ {
+ binding_suspended = true;
+ }
+
+ public override void ResumeBinding ()
+ {
+ binding_suspended = false;
+ }
+
+ internal override bool IsSuspended {
+ get {
+ // Always return true if we don't have items
+ if (Count == 0)
+ return true;
+
+ return binding_suspended;
+ }
+ }
+
+ internal bool AllowNew {
+ get {
+ if (list is IBindingList)
+ return ((IBindingList)list).AllowNew;
+
+ if (list.IsReadOnly)
+ return false;
+
+ return false;
+ }
+ }
+
+ internal bool AllowRemove {
+ get {
+ if (list.IsReadOnly)
+ return false;
+
+ if (list is IBindingList)
+ return ((IBindingList)list).AllowRemove;
+
+ return false;
+ }
+ }
+
+ internal bool AllowEdit {
+ get {
+ if (list is IBindingList)
+ return ((IBindingList)list).AllowEdit;
+
+ return false;
+ }
+ }
+
+ public override void AddNew ()
+ {
+ IBindingList ibl = list as IBindingList;
+
+ if (ibl == null)
+ throw new NotSupportedException ();
+
+ ibl.AddNew ();
+
+ bool validate = (Position != (list.Count - 1));
+ ChangeRecordState (list.Count - 1, validate, validate, true, true);
+ }
+
+
+ void BeginEdit ()
+ {
+ IEditableObject editable = Current as IEditableObject;
+
+ if (editable != null) {
+ try {
+ editable.BeginEdit ();
+ editing = true;
+ }
+ catch {
+ /* swallow exceptions in IEditableObject.BeginEdit () */
+ }
+ }
+ }
+
+ public override void CancelCurrentEdit ()
+ {
+ if (listposition == -1)
+ return;
+
+ IEditableObject editable = Current as IEditableObject;
+
+ if (editable != null) {
+ editing = false;
+ editable.CancelEdit ();
+ OnItemChanged (new ItemChangedEventArgs (Position));
+ }
+ if (list is ICancelAddNew)
+ ((ICancelAddNew)list).CancelNew (listposition);
+ }
+
+ public override void EndCurrentEdit ()
+ {
+ if (listposition == -1)
+ return;
+
+ IEditableObject editable = Current as IEditableObject;
+
+ if (editable != null) {
+ editing = false;
+ editable.EndEdit ();
+ }
+
+ if (list is ICancelAddNew)
+ ((ICancelAddNew)list).EndNew (listposition);
+ }
+
+ public void Refresh ()
+ {
+ ListChangedHandler (null, new ListChangedEventArgs (ListChangedType.Reset, -1));
+ }
+
+ protected void CheckEmpty ()
+ {
+ if (list == null || list.Count < 1)
+ throw new Exception ("List is empty.");
+
+ }
+
+ protected internal override void OnCurrentChanged (EventArgs e)
+ {
+ if (onCurrentChangedHandler != null) {
+ onCurrentChangedHandler (this, e);
+ }
+
+ // don't call OnCurrentItemChanged here, as it can be overridden
+ if (onCurrentItemChangedHandler != null) {
+ onCurrentItemChangedHandler (this, e);
+ }
+
+ }
+
+ protected override void OnCurrentItemChanged (EventArgs e)
+ {
+ if (onCurrentItemChangedHandler != null) {
+ onCurrentItemChangedHandler (this, e);
+ }
+ }
+
+ protected virtual void OnItemChanged (ItemChangedEventArgs e)
+ {
+ if (ItemChanged != null)
+ ItemChanged (this, e);
+
+ transfering_data = true;
+ PushData ();
+ transfering_data = false;
+ }
+
+ void OnListChanged (ListChangedEventArgs args)
+ {
+ if (ListChanged != null)
+ ListChanged (this, args);
+ }
+
+ protected virtual void OnPositionChanged (EventArgs e)
+ {
+ if (onPositionChangedHandler != null)
+ onPositionChangedHandler (this, e);
+ }
+
+ protected internal override string GetListName (ArrayList listAccessors)
+ {
+ if (list is ITypedList) {
+ PropertyDescriptor [] pds = null;
+ if (listAccessors != null) {
+ pds = new PropertyDescriptor [listAccessors.Count];
+ listAccessors.CopyTo (pds, 0);
+ }
+ return ((ITypedList) list).GetListName (pds);
+ }
+ else if (finalType != null) {
+ return finalType.Name;
+ }
+ return String.Empty;
+ }
+
+ protected override void UpdateIsBinding ()
+ {
+ UpdateItem ();
+
+ foreach (Binding binding in Bindings)
+ binding.UpdateIsBinding ();
+
+ ChangeRecordState (listposition, false, false, true, false);
+
+ OnItemChanged (new ItemChangedEventArgs (-1));
+ }
+
+ private void ChangeRecordState (int newPosition,
+ bool validating,
+ bool endCurrentEdit,
+ bool firePositionChanged,
+ bool pullData)
+ {
+ if (endCurrentEdit)
+ EndCurrentEdit ();
+
+ int old_index = listposition;
+
+ listposition = newPosition;
+
+ if (listposition >= list.Count)
+ listposition = list.Count - 1;
+
+ if (old_index != -1 && listposition != -1)
+ OnCurrentChanged (EventArgs.Empty);
+
+ if (firePositionChanged)
+ OnPositionChanged (EventArgs.Empty);
+ }
+
+ private void UpdateItem ()
+ {
+ // Probably should be validating or something here
+ if (!transfering_data && listposition == -1 && list.Count > 0) {
+ listposition = 0;
+ BeginEdit ();
+ }
+ }
+
+ internal object this [int index] {
+ get { return list [index]; }
+ }
+
+ private PropertyDescriptorCollection GetBrowsableProperties (Type t)
+ {
+ Attribute [] att = new System.Attribute [1];
+ att [0] = new BrowsableAttribute (true);
+ return TypeDescriptor.GetProperties (t, att);
+ }
+
+ protected void OnMetaDataChanged (EventArgs e)
+ {
+ if (MetaDataChanged != null)
+ MetaDataChanged (this, e);
+ }
+
+ private void ListChangedHandler (object sender, ListChangedEventArgs e)
+ {
+ switch (e.ListChangedType) {
+ case ListChangedType.PropertyDescriptorAdded:
+ case ListChangedType.PropertyDescriptorDeleted:
+ case ListChangedType.PropertyDescriptorChanged:
+ OnMetaDataChanged (EventArgs.Empty);
+ OnListChanged (e);
+ break;
+ case ListChangedType.ItemDeleted:
+ if (list.Count == 0) {
+ /* the last row was deleted */
+ listposition = -1;
+ UpdateIsBinding ();
+
+ OnPositionChanged (EventArgs.Empty);
+ OnCurrentChanged (EventArgs.Empty);
+ }
+ else if (e.NewIndex <= listposition) {
+ /* the deleted row was either the current one, or one earlier in the list.
+ Update the index and emit PositionChanged, CurrentChanged, and ItemChanged. */
+ // FIXME: this looks wrong, shouldn't it be (listposition - 1) instead of e.NewIndex ?
+ ChangeRecordState (e.NewIndex,
+ false, false, e.NewIndex != listposition, false);
+ }
+ else {
+ /* the deleted row was after the current one, so we don't
+ need to update bound Widgets for Position/Current changed */
+ }
+
+ OnItemChanged (new ItemChangedEventArgs (-1));
+ OnListChanged (e);
+ break;
+ case ListChangedType.ItemAdded:
+ if (list.Count == 1) {
+ /* it's the first one we've added */
+ ChangeRecordState (e.NewIndex,
+ false, false, true, false);
+
+ OnItemChanged (new ItemChangedEventArgs (-1));
+ OnListChanged (e);
+ }
+ else {
+ if (e.NewIndex <= listposition) {
+ ChangeRecordState (listposition + 1,
+ false, false, false, false);
+ OnItemChanged (new ItemChangedEventArgs (-1));
+ OnListChanged (e);
+ OnPositionChanged (EventArgs.Empty);
+ }
+ else {
+ OnItemChanged (new ItemChangedEventArgs (-1));
+ OnListChanged (e);
+ }
+ }
+
+ break;
+ case ListChangedType.ItemChanged:
+ if (editing) {
+ if (e.NewIndex == listposition)
+ OnCurrentItemChanged (EventArgs.Empty);
+ OnItemChanged (new ItemChangedEventArgs (e.NewIndex));
+ }
+ OnListChanged (e);
+ break;
+ case ListChangedType.Reset:
+ PushData();
+ UpdateIsBinding();
+ OnListChanged (e);
+ break;
+ default:
+ OnListChanged (e);
+ break;
+ }
+ }
+
+ public event ListChangedEventHandler ListChanged;
+ public event ItemChangedEventHandler ItemChanged;
+ public event EventHandler MetaDataChanged;
+ }
+}
+
diff --git a/source/ShiftUI/Internal/Cursor.cs b/source/ShiftUI/Internal/Cursor.cs
new file mode 100644
index 0000000..1b3e0f6
--- /dev/null
+++ b/source/ShiftUI/Internal/Cursor.cs
@@ -0,0 +1,245 @@
+// 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) 2008 Novell, Inc.
+//
+// Authors:
+// Geoff Norton ([email protected])
+//
+//
+
+
+using System;
+using System.Drawing;
+using ShiftUI;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.CarbonInternal {
+ internal class Cursor {
+ internal static CarbonCursor defcur = new CarbonCursor (StdCursor.Default);
+
+ internal static Bitmap DefineStdCursorBitmap (StdCursor id) {
+ // FIXME
+ return new Bitmap (16, 16);
+ }
+ internal static IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
+ CarbonCursor cc = new CarbonCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot);
+
+ return (IntPtr) GCHandle.Alloc (cc);
+ }
+ internal static IntPtr DefineStdCursor (StdCursor id) {
+ CarbonCursor cc = new CarbonCursor (id);
+
+ return (IntPtr) GCHandle.Alloc (cc);
+ }
+ internal static void SetCursor (IntPtr cursor) {
+ if (cursor == IntPtr.Zero) {
+ defcur.SetCursor ();
+ return;
+ }
+
+ CarbonCursor cc = (CarbonCursor) ((GCHandle) cursor).Target;
+
+ cc.SetCursor ();
+ }
+ }
+
+ internal struct CarbonCursor {
+ private Bitmap bmp;
+ private Bitmap mask;
+ private Color cursor_color;
+ private Color mask_color;
+ private int hot_x;
+ private int hot_y;
+ private StdCursor id;
+ private bool standard;
+
+ public CarbonCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
+ this.id = StdCursor.Default;
+ this.bmp = bitmap;
+ this.mask = mask;
+ this.cursor_color = cursor_pixel;
+ this.mask_color = mask_pixel;
+ this.hot_x = xHotSpot;
+ this.hot_y = yHotSpot;
+ standard = true;
+ }
+
+ public CarbonCursor (StdCursor id) {
+ this.id = id;
+ this.bmp = null;
+ this.mask = null;
+ this.cursor_color = Color.Black;
+ this.mask_color = Color.Black;
+ this.hot_x = 0;
+ this.hot_y = 0;
+ standard = true;
+ }
+
+ public StdCursor StdCursor {
+ get {
+ return id;
+ }
+ }
+
+ public Bitmap Bitmap {
+ get {
+ return bmp;
+ }
+ }
+
+ public Bitmap Mask {
+ get {
+ return mask;
+ }
+ }
+
+ public Color CursorColor {
+ get {
+ return cursor_color;
+ }
+ }
+
+ public Color MaskColor {
+ get {
+ return mask_color;
+ }
+ }
+
+ public int HotSpotX {
+ get {
+ return hot_x;
+ }
+ }
+
+ public int HotSpotY {
+ get {
+ return hot_y;
+ }
+ }
+
+ public void SetCursor () {
+ if (standard)
+ SetStandardCursor ();
+ else
+ SetCustomCursor ();
+ }
+
+ public void SetCustomCursor () {
+ throw new NotImplementedException ("We dont support custom cursors yet");
+ }
+
+ public void SetStandardCursor () {
+ switch (id) {
+ case StdCursor.AppStarting:
+ SetThemeCursor (ThemeCursor.kThemeSpinningCursor);
+ break;
+ case StdCursor.Arrow:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.Cross:
+ SetThemeCursor (ThemeCursor.kThemeCrossCursor);
+ break;
+ case StdCursor.Default:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.Hand:
+ SetThemeCursor (ThemeCursor.kThemeOpenHandCursor);
+ break;
+ case StdCursor.Help:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.HSplit:
+ SetThemeCursor (ThemeCursor.kThemeResizeLeftRightCursor);
+ break;
+ case StdCursor.IBeam:
+ SetThemeCursor (ThemeCursor.kThemeIBeamCursor);
+ break;
+ case StdCursor.No:
+ SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor);
+ break;
+ case StdCursor.NoMove2D:
+ SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor);
+ break;
+ case StdCursor.NoMoveHoriz:
+ SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor);
+ break;
+ case StdCursor.NoMoveVert:
+ SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor);
+ break;
+ case StdCursor.PanEast:
+ SetThemeCursor (ThemeCursor.kThemeResizeRightCursor);
+ break;
+ case StdCursor.PanNE:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.PanNorth:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.PanNW:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.PanSE:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.PanSouth:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.PanSW:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.PanWest:
+ SetThemeCursor (ThemeCursor.kThemeResizeLeftCursor);
+ break;
+ case StdCursor.SizeAll:
+ SetThemeCursor (ThemeCursor.kThemeResizeLeftRightCursor);
+ break;
+ case StdCursor.SizeNESW:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.SizeNS:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.SizeNWSE:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.SizeWE:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.UpArrow:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.VSplit:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ case StdCursor.WaitCursor:
+ SetThemeCursor (ThemeCursor.kThemeSpinningCursor);
+ break;
+ default:
+ SetThemeCursor (ThemeCursor.kThemeArrowCursor);
+ break;
+ }
+ return;
+ }
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int SetThemeCursor (ThemeCursor cursor);
+
+ }
+}
diff --git a/source/ShiftUI/Internal/CursorConverter.cs b/source/ShiftUI/Internal/CursorConverter.cs
new file mode 100644
index 0000000..d84b3d2
--- /dev/null
+++ b/source/ShiftUI/Internal/CursorConverter.cs
@@ -0,0 +1,126 @@
+// 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) 2005 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.Design.Serialization;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+
+namespace ShiftUI
+{
+ public class CursorConverter : TypeConverter
+ {
+ public CursorConverter ()
+ {
+ }
+
+ public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof (byte []))
+ return true;
+ return base.CanConvertFrom (context, sourceType);
+ }
+
+ public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof (byte []) || destinationType == typeof (InstanceDescriptor))
+ return true;
+ return base.CanConvertTo (context, destinationType);
+ }
+
+ public override object ConvertFrom (ITypeDescriptorContext context,
+ CultureInfo culture, object value)
+ {
+ byte [] val = value as byte [];
+ if (val == null)
+ return base.ConvertFrom (context, culture, value);
+
+ using (MemoryStream s = new MemoryStream (val)) {
+ return new Cursor (s);
+ }
+ }
+
+ public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture,
+ object value, Type destinationType)
+ {
+ if (destinationType == null)
+ throw new ArgumentNullException ("destinationType");
+
+ if (value == null && destinationType == typeof (string))
+ return "(none)";
+
+ if ( !(value is Cursor))
+ throw new ArgumentException("object must be of class Cursor", "value");
+
+ if (destinationType == typeof (byte [])) {
+ Cursor c;
+ SerializationInfo si;
+
+ if (value == null) {
+ return new byte [0];
+ }
+
+ c = (Cursor)value;
+
+ si = new SerializationInfo(typeof(Cursor), new FormatterConverter());
+ ((ISerializable)c).GetObjectData(si, new StreamingContext(StreamingContextStates.Remoting));
+
+ return (byte[])si.GetValue("CursorData", typeof(byte[]));
+ } else if (destinationType == typeof (InstanceDescriptor)) {
+ PropertyInfo[] properties = typeof (Cursors).GetProperties ();
+ foreach (PropertyInfo propInfo in properties) {
+ if (propInfo.GetValue (null, null) == value) {
+ return new InstanceDescriptor (propInfo, null);
+ }
+ }
+ }
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context)
+ {
+ PropertyInfo[] props = typeof (Cursors).GetProperties();
+
+ ArrayList vals = new ArrayList ();
+
+ for (int i = 0; i < props.Length; i++) {
+ vals.Add (props [i].GetValue (null, null));
+ }
+ return new StandardValuesCollection (vals);
+ }
+
+ public override bool GetStandardValuesSupported (ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/Cursors.cs b/source/ShiftUI/Internal/Cursors.cs
new file mode 100644
index 0000000..2d43345
--- /dev/null
+++ b/source/ShiftUI/Internal/Cursors.cs
@@ -0,0 +1,365 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+// COMPLETE
+
+using ShiftUI;
+
+namespace ShiftUI {
+ public sealed class Cursors {
+ #region Local Variables
+ internal static Cursor app_starting;
+ internal static Cursor arrow;
+ internal static Cursor cross;
+ internal static Cursor def;
+ internal static Cursor hand;
+ internal static Cursor help;
+ internal static Cursor hsplit;
+ internal static Cursor ibeam;
+ internal static Cursor no;
+ internal static Cursor no_move_2d;
+ internal static Cursor no_move_horiz;
+ internal static Cursor no_move_vert;
+ internal static Cursor pan_east;
+ internal static Cursor pan_ne;
+ internal static Cursor pan_north;
+ internal static Cursor pan_nw;
+ internal static Cursor pan_se;
+ internal static Cursor pan_south;
+ internal static Cursor pan_sw;
+ internal static Cursor pan_west;
+ internal static Cursor size_all;
+ internal static Cursor size_nesw;
+ internal static Cursor size_ns;
+ internal static Cursor size_nwse;
+ internal static Cursor size_we;
+ internal static Cursor up_arrow;
+ internal static Cursor vsplit;
+ internal static Cursor wait_cursor;
+ #endregion // Local Variables
+
+ #region Constructors
+ private Cursors() {
+ }
+ #endregion // Constructors
+
+ #region Public Static Properties
+ public static Cursor AppStarting {
+ get {
+ if (app_starting == null) {
+ app_starting = new Cursor(StdCursor.AppStarting);
+ app_starting.name = "AppStarting";
+ }
+ return app_starting;
+ }
+ }
+
+ public static Cursor Arrow {
+ get {
+ if (arrow == null) {
+ arrow = new Cursor(StdCursor.Arrow);
+ arrow.name = "Arrow";
+ }
+ return arrow;
+ }
+ }
+
+ public static Cursor Cross {
+ get {
+ if (cross == null) {
+ cross = new Cursor(StdCursor.Cross);
+ cross.name = "Cross";
+ }
+ return cross;
+ }
+ }
+
+ public static Cursor Default {
+ get {
+ if (def == null) {
+ def = new Cursor(StdCursor.Default);
+ def.name = "Default";
+ }
+ return def;
+ }
+ }
+
+ public static Cursor Hand {
+ get {
+ if (hand == null) {
+ hand = new Cursor(StdCursor.Hand);
+ hand.name = "Hand";
+ }
+ return hand;
+ }
+ }
+
+ public static Cursor Help {
+ get {
+ if (help == null) {
+ help = new Cursor(StdCursor.Help);
+ help.name = "Help";
+ }
+ return help;
+ }
+ }
+
+ public static Cursor HSplit {
+ get {
+ if (hsplit == null) {
+ hsplit = new Cursor(global::ShiftUI.Properties.Resources.SplitterWE);
+ hsplit.name = "HSplit";
+ }
+ return hsplit;
+ }
+ }
+
+ public static Cursor IBeam {
+ get {
+ if (ibeam == null) {
+ ibeam = new Cursor(StdCursor.IBeam);
+ ibeam.name = "IBeam";
+ }
+ return ibeam;
+ }
+ }
+
+ public static Cursor No {
+ get {
+ if (no == null) {
+ no = new Cursor(StdCursor.No);
+ no.name = "No";
+ }
+ return no;
+ }
+ }
+
+ public static Cursor NoMove2D {
+ get {
+ if (no_move_2d == null) {
+ no_move_2d = new Cursor(StdCursor.NoMove2D);
+ no_move_2d.name = "NoMove2D";
+ }
+ return no_move_2d;
+ }
+ }
+
+ public static Cursor NoMoveHoriz {
+ get {
+ if (no_move_horiz == null) {
+ no_move_horiz = new Cursor(StdCursor.NoMoveHoriz);
+ no_move_horiz.name = "NoMoveHoriz";
+ }
+ return no_move_horiz;
+ }
+ }
+
+ public static Cursor NoMoveVert {
+ get {
+ if (no_move_vert == null) {
+ no_move_vert = new Cursor(StdCursor.NoMoveVert);
+ no_move_vert.name = "NoMoveVert";
+ }
+ return no_move_vert;
+ }
+ }
+
+ public static Cursor PanEast {
+ get {
+ if (pan_east == null) {
+ pan_east = new Cursor(StdCursor.PanEast);
+ pan_east.name = "PanEast";
+ }
+ return pan_east;
+ }
+ }
+
+
+
+
+ public static Cursor PanNE {
+ get {
+ if (pan_ne == null) {
+ pan_ne = new Cursor(StdCursor.PanNE);
+ pan_ne.name = "PanNE";
+ }
+ return pan_ne;
+ }
+ }
+
+
+ public static Cursor PanNorth {
+ get {
+ if (pan_north == null) {
+ pan_north = new Cursor(StdCursor.PanNorth);
+ pan_north.name = "PanNorth";
+ }
+ return pan_north;
+ }
+ }
+
+ public static Cursor PanNW {
+ get {
+ if (pan_nw == null) {
+ pan_nw = new Cursor(StdCursor.PanNW);
+ pan_nw.name = "PanNW";
+ }
+ return pan_nw;
+ }
+ }
+
+ public static Cursor PanSE {
+ get {
+ if (pan_se == null) {
+ pan_se = new Cursor(StdCursor.PanSE);
+ pan_se.name = "PanSE";
+ }
+ return pan_se;
+ }
+ }
+
+ public static Cursor PanSouth {
+ get {
+ if (pan_south == null) {
+ pan_south = new Cursor(StdCursor.PanSouth);
+ pan_south.name = "PanSouth";
+ }
+ return pan_south;
+ }
+ }
+
+ public static Cursor PanSW {
+ get {
+ if (pan_sw == null) {
+ pan_sw = new Cursor(StdCursor.PanSW);
+ pan_sw.name = "PanSW";
+ }
+ return pan_sw;
+ }
+ }
+
+ public static Cursor PanWest {
+ get {
+ if (pan_west == null) {
+ pan_west = new Cursor(StdCursor.PanWest);
+ pan_west.name = "PanWest";
+ }
+ return pan_west;
+ }
+ }
+
+ public static Cursor SizeAll {
+ get {
+ if (size_all == null) {
+ size_all = new Cursor(StdCursor.SizeAll);
+ size_all.name = "SizeAll";
+ }
+ return size_all;
+ }
+ }
+
+ public static Cursor SizeNESW {
+ get {
+ if (size_nesw == null) {
+ if (XplatUI.RunningOnUnix) {
+ size_nesw = new Cursor(Properties.Resources.NESW);
+ size_nesw.name = "SizeNESW";
+ } else {
+ size_nesw = new Cursor(StdCursor.SizeNESW);
+ size_nesw.name = "SizeNESW";
+ }
+ }
+ return size_nesw;
+ }
+ }
+
+ public static Cursor SizeNS {
+ get {
+ if (size_ns == null) {
+ size_ns = new Cursor(StdCursor.SizeNS);
+ size_ns.name = "SizeNS";
+ }
+ return size_ns;
+ }
+ }
+
+ public static Cursor SizeNWSE {
+ get {
+ if (size_nwse == null) {
+ if (XplatUI.RunningOnUnix) {
+ size_nwse = new Cursor(Properties.Resources.NWSE);
+ size_nwse.name = "SizeNWSE";
+ } else {
+ size_nwse = new Cursor(StdCursor.SizeNWSE);
+ size_nwse.name = "SizeNWSE";
+ }
+ }
+ return size_nwse;
+ }
+ }
+
+ public static Cursor SizeWE {
+ get {
+ if (size_we == null) {
+ size_we = new Cursor(StdCursor.SizeWE);
+ size_we.name = "SizeWE";
+ }
+ return size_we;
+ }
+ }
+
+ public static Cursor UpArrow {
+ get {
+ if (up_arrow == null) {
+ up_arrow = new Cursor(StdCursor.UpArrow);
+ up_arrow.name = "UpArrow";
+ }
+ return up_arrow;
+ }
+ }
+
+ public static Cursor VSplit {
+ get {
+ if (vsplit == null) {
+ vsplit = new Cursor(Properties.Resources.SplitterWE);
+ vsplit.name = "VSplit";
+ }
+ return vsplit;
+ }
+ }
+
+ public static Cursor WaitCursor {
+ get {
+ if (wait_cursor == null) {
+ wait_cursor = new Cursor(StdCursor.WaitCursor);
+ wait_cursor.name = "WaitCursor";
+ }
+ return wait_cursor;
+ }
+ }
+ #endregion // Public Static Properties
+ }
+}
diff --git a/source/ShiftUI/Internal/DataObject.cs b/source/ShiftUI/Internal/DataObject.cs
new file mode 100644
index 0000000..cfe74d5
--- /dev/null
+++ b/source/ShiftUI/Internal/DataObject.cs
@@ -0,0 +1,485 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System;
+using System.IO;
+using System.Drawing;
+using System.Collections;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI {
+ [ClassInterface(ClassInterfaceType.None)]
+ public class DataObject : IDataObject, System.Runtime.InteropServices.ComTypes.IDataObject
+ {
+ #region DataObject.Entry Class
+ private class Entry {
+ #region Local Variables
+ private string type;
+ private object data;
+ private bool autoconvert;
+ internal Entry next;
+ #endregion // Local Variables
+
+ #region Constructors
+ internal Entry(string type, object data, bool autoconvert) {
+ this.type = type;
+ this.data = data;
+ this.autoconvert = autoconvert;
+ }
+ #endregion // Constructors
+
+ #region Properties
+ public object Data {
+ get {
+ return data;
+ }
+
+ set {
+ data = value;
+ }
+ }
+ public bool AutoConvert {
+ get {
+ return autoconvert;
+ }
+ set {
+ autoconvert = value;
+ }
+ }
+ #endregion // Properties
+
+ #region Methods
+ public static int Count(Entry entries) {
+ int result;
+
+ result = 0;
+
+ while (entries != null) {
+ result++;
+ entries = entries.next;
+ }
+
+ return result;
+ }
+
+ public static Entry Find (Entry entries, string type) {
+ return Find (entries, type, false);
+ }
+
+ public static Entry Find(Entry entries, string type, bool only_convertible) {
+ while (entries != null) {
+ bool available = true;
+ if (only_convertible && !entries.autoconvert)
+ available = false;
+ if (available && String.Compare (entries.type, type, true) == 0) {
+ return entries;
+ }
+ entries = entries.next;
+ }
+
+ return null;
+ }
+
+ public static Entry FindConvertible(Entry entries, string type) {
+ Entry e;
+
+ e = Find(entries, type);
+ if (e != null) {
+ return e;
+ }
+
+ // map to *any* other text format if needed
+ if (type == DataFormats.StringFormat || type == DataFormats.Text || type == DataFormats.UnicodeText) {
+ e = entries;
+ while (e != null) {
+ if (e.type == DataFormats.StringFormat || e.type == DataFormats.Text || e.type == DataFormats.UnicodeText)
+ return e;
+
+ e = e.next;
+ }
+ }
+
+ return null;
+ }
+
+ public static string[] Entries(Entry entries, bool convertible) {
+ Entry e;
+ ArrayList list;
+ string[] result;
+
+ // Initially store into something that we can grow easily
+ list = new ArrayList(Entry.Count(entries));
+ e = entries;
+
+ if (convertible) {
+ // Add the convertibles
+ Entry text_entry = Entry.Find (entries, DataFormats.Text);
+ Entry utext_entry = Entry.Find (entries, DataFormats.UnicodeText);
+ Entry string_entry = Entry.Find (entries, DataFormats.StringFormat);
+ bool text_convertible = text_entry != null && text_entry.AutoConvert;
+ bool utext_convertible = utext_entry != null && utext_entry.AutoConvert;
+ bool string_convertible = string_entry != null && string_entry.AutoConvert;
+
+ if (text_convertible || utext_convertible || string_convertible) {
+ list.Add (DataFormats.StringFormat);
+ list.Add (DataFormats.UnicodeText);
+ list.Add (DataFormats.Text);
+ }
+ }
+
+ while (e != null) {
+ if (!list.Contains (e.type))
+ list.Add (e.type);
+ e = e.next;
+ }
+
+ // Copy the results into a string array
+ result = new string[list.Count];
+ for (int i = 0; i < list.Count; i++) {
+ result[i] = (string)list[i];
+ }
+
+ return result;
+ }
+ #endregion // Methods
+ }
+ #endregion // DataObject.Entry class
+
+ #region Local Variables
+ private Entry entries;
+ #endregion // Local Variables
+
+ #region Public Constructors
+ public DataObject() {
+ entries = null;
+ }
+
+ public DataObject(object data) {
+ SetData(data);
+ }
+
+ public DataObject(string format, object data) {
+ SetData(format, data);
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Methods
+ public virtual bool ContainsAudio ()
+ {
+ return GetDataPresent (DataFormats.WaveAudio, true);
+ }
+
+ public virtual bool ContainsFileDropList ()
+ {
+ return GetDataPresent (DataFormats.FileDrop, true);
+ }
+
+ public virtual bool ContainsImage ()
+ {
+ return GetDataPresent (DataFormats.Bitmap, true);
+ }
+
+ public virtual bool ContainsText ()
+ {
+ return GetDataPresent (DataFormats.UnicodeText, true);
+ }
+
+ public virtual bool ContainsText (TextDataFormat format)
+ {
+ if (!Enum.IsDefined (typeof (TextDataFormat), format))
+ throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
+
+ return GetDataPresent (TextFormatToDataFormat (format), true);
+ }
+
+ public virtual Stream GetAudioStream ()
+ {
+ return (Stream)GetData (DataFormats.WaveAudio, true);
+ }
+
+ public virtual object GetData(string format) {
+ return GetData(format, true);
+ }
+
+ public virtual object GetData(string format, bool autoConvert) {
+ Entry e;
+ if (autoConvert) {
+ e = Entry.FindConvertible(entries, format);
+ } else {
+ e = Entry.Find(entries, format);
+ }
+ if (e == null)
+ return null;
+ return e.Data;
+ }
+
+ public virtual object GetData(Type format) {
+ return GetData(format.FullName, true);
+ }
+
+ public virtual bool GetDataPresent(string format) {
+ return GetDataPresent(format, true);
+ }
+
+ public virtual bool GetDataPresent(string format, bool autoConvert) {
+ if (autoConvert) {
+ return Entry.FindConvertible(entries, format) != null;
+ } else {
+ return Entry.Find(entries, format) != null;
+ }
+ }
+
+ public virtual bool GetDataPresent(Type format) {
+ return GetDataPresent(format.FullName, true);
+ }
+
+ public virtual StringCollection GetFileDropList ()
+ {
+ return (StringCollection)GetData (DataFormats.FileDrop, true);
+ }
+ public virtual string[] GetFormats() {
+ return GetFormats(true);
+ }
+
+ public virtual string[] GetFormats(bool autoConvert) {
+ return Entry.Entries(entries, autoConvert);
+ }
+
+ public virtual Image GetImage ()
+ {
+ return (Image)GetData (DataFormats.Bitmap, true);
+ }
+
+ public virtual string GetText ()
+ {
+ return (string)GetData (DataFormats.UnicodeText, true);
+ }
+
+ public virtual string GetText (TextDataFormat format)
+ {
+ if (!Enum.IsDefined (typeof (TextDataFormat), format))
+ throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
+
+ return (string)GetData (TextFormatToDataFormat (format), false);
+ }
+
+ public virtual void SetAudio (byte[] audioBytes)
+ {
+ if (audioBytes == null)
+ throw new ArgumentNullException ("audioBytes");
+
+ MemoryStream ms = new MemoryStream (audioBytes);
+
+ SetAudio (ms);
+ }
+
+ public virtual void SetAudio (Stream audioStream)
+ {
+ if (audioStream == null)
+ throw new ArgumentNullException ("audioStream");
+
+ SetData (DataFormats.WaveAudio, audioStream);
+ }
+
+ public virtual void SetData(object data) {
+ SetData(data.GetType(), data);
+ }
+
+ public virtual void SetData(string format, bool autoConvert, object data) {
+ Entry entry;
+ Entry e;
+
+ entry = Entry.Find(entries, format);
+
+ if (entry == null) {
+ entry = new DataObject.Entry(format, data, autoConvert);
+ } else {
+ entry.Data = data;
+ return;
+ }
+
+ lock (this) {
+ if (entries == null) {
+ entries = entry;
+ } else {
+ // Insert into the list of known/defined formats
+ e = entries;
+
+ while (e.next != null) {
+ e = e.next;
+ }
+ e.next = entry;
+ }
+ }
+ }
+
+ public virtual void SetData(string format, object data) {
+ SetData(format, true, data);
+ }
+
+ public virtual void SetData(Type format, object data) {
+ SetData(EnsureFormat(format), true, data);
+ }
+
+ [MonoInternalNote ("Needs additional checks for valid paths, see MSDN")]
+ public virtual void SetFileDropList (StringCollection filePaths)
+ {
+ if (filePaths == null)
+ throw new ArgumentNullException ("filePaths");
+
+ SetData (DataFormats.FileDrop, filePaths);
+ }
+
+ public virtual void SetImage (Image image)
+ {
+ if (image == null)
+ throw new ArgumentNullException ("image");
+
+ SetData (DataFormats.Bitmap, image);
+ }
+
+ public virtual void SetText (string textData)
+ {
+ if (string.IsNullOrEmpty (textData))
+ throw new ArgumentNullException ("text");
+
+ SetData (DataFormats.UnicodeText, textData);
+ }
+
+ public virtual void SetText (string textData, TextDataFormat format)
+ {
+ if (string.IsNullOrEmpty (textData))
+ throw new ArgumentNullException ("text");
+ if (!Enum.IsDefined (typeof (TextDataFormat), format))
+ throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
+
+ switch (format) {
+ case TextDataFormat.Text:
+ SetData (DataFormats.Text, textData);
+ break;
+ case TextDataFormat.UnicodeText:
+ SetData (DataFormats.UnicodeText, textData);
+ break;
+ case TextDataFormat.Rtf:
+ SetData (DataFormats.Rtf, textData);
+ break;
+ case TextDataFormat.Html:
+ SetData (DataFormats.Html, textData);
+ break;
+ case TextDataFormat.CommaSeparatedValue:
+ SetData (DataFormats.CommaSeparatedValue, textData);
+ break;
+ }
+ }
+ #endregion // Public Instance Methods
+
+ #region Private Methods
+ internal string EnsureFormat(string name) {
+ DataFormats.Format f;
+
+ f = DataFormats.Format.Find(name);
+ if (f == null) {
+ // Register the format
+ f = DataFormats.Format.Add(name);
+ }
+
+ return f.Name;
+ }
+
+ internal string EnsureFormat(Type type) {
+ return EnsureFormat(type.FullName);
+ }
+
+ private string TextFormatToDataFormat (TextDataFormat format)
+ {
+ switch (format) {
+ case TextDataFormat.Text:
+ default:
+ return DataFormats.Text;
+ case TextDataFormat.UnicodeText:
+ return DataFormats.UnicodeText;
+ case TextDataFormat.Rtf:
+ return DataFormats.Rtf;
+ case TextDataFormat.Html:
+ return DataFormats.Html;
+ case TextDataFormat.CommaSeparatedValue:
+ return DataFormats.CommaSeparatedValue;
+ }
+ }
+ #endregion // Private Methods
+
+ #region IDataObject Members
+ int System.Runtime.InteropServices.ComTypes.IDataObject.DAdvise (ref System.Runtime.InteropServices.ComTypes.FORMATETC pFormatetc, System.Runtime.InteropServices.ComTypes.ADVF advf, System.Runtime.InteropServices.ComTypes.IAdviseSink adviseSink, out int connection)
+ {
+ throw new NotImplementedException ();
+ }
+
+ void System.Runtime.InteropServices.ComTypes.IDataObject.DUnadvise (int connection)
+ {
+ throw new NotImplementedException ();
+ }
+
+ int System.Runtime.InteropServices.ComTypes.IDataObject.EnumDAdvise (out System.Runtime.InteropServices.ComTypes.IEnumSTATDATA enumAdvise)
+ {
+ throw new NotImplementedException ();
+ }
+
+ System.Runtime.InteropServices.ComTypes.IEnumFORMATETC System.Runtime.InteropServices.ComTypes.IDataObject.EnumFormatEtc (System.Runtime.InteropServices.ComTypes.DATADIR direction)
+ {
+ throw new NotImplementedException ();
+ }
+
+ int System.Runtime.InteropServices.ComTypes.IDataObject.GetCanonicalFormatEtc (ref System.Runtime.InteropServices.ComTypes.FORMATETC formatIn, out System.Runtime.InteropServices.ComTypes.FORMATETC formatOut)
+ {
+ throw new NotImplementedException ();
+ }
+
+ void System.Runtime.InteropServices.ComTypes.IDataObject.GetData (ref System.Runtime.InteropServices.ComTypes.FORMATETC format, out System.Runtime.InteropServices.ComTypes.STGMEDIUM medium)
+ {
+ throw new NotImplementedException ();
+ }
+
+ void System.Runtime.InteropServices.ComTypes.IDataObject.GetDataHere (ref System.Runtime.InteropServices.ComTypes.FORMATETC format, ref System.Runtime.InteropServices.ComTypes.STGMEDIUM medium)
+ {
+ throw new NotImplementedException ();
+ }
+
+ int System.Runtime.InteropServices.ComTypes.IDataObject.QueryGetData (ref System.Runtime.InteropServices.ComTypes.FORMATETC format)
+ {
+ throw new NotImplementedException ();
+ }
+
+ void System.Runtime.InteropServices.ComTypes.IDataObject.SetData (ref System.Runtime.InteropServices.ComTypes.FORMATETC formatIn, ref System.Runtime.InteropServices.ComTypes.STGMEDIUM medium, bool release)
+ {
+ throw new NotImplementedException ();
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/Day.cs b/source/ShiftUI/Internal/Day.cs
new file mode 100644
index 0000000..0c797a7
--- /dev/null
+++ b/source/ShiftUI/Internal/Day.cs
@@ -0,0 +1,39 @@
+//
+// 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 Novell, Inc.
+//
+// Authors:
+// John BouAntoun [email protected]
+//
+
+namespace ShiftUI {
+ // used mainly by monthcalendar
+ public enum Day {
+ Monday,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday,
+ Default
+ }
+}
diff --git a/source/ShiftUI/Internal/DebugHelper.cs b/source/ShiftUI/Internal/DebugHelper.cs
new file mode 100644
index 0000000..3c76307
--- /dev/null
+++ b/source/ShiftUI/Internal/DebugHelper.cs
@@ -0,0 +1,257 @@
+// 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) 2008 Novell, Inc.
+//
+// Authors:
+// Andreia Gaita ([email protected])
+//
+
+//#define DEBUG
+//#define TRACE
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+
+namespace ShiftUI
+{
+ internal class DebugHelper
+ {
+ static DebugHelper () {
+ Debug.AutoFlush = true;
+ }
+
+ struct Data {
+ public MethodBase method;
+ public object[] args;
+ public Data (MethodBase m, object[] a) {
+ this.method = m;
+ this.args = a;
+ }
+ }
+
+ static Stack<Data> methods = new Stack<Data>();
+
+ [Conditional("DEBUG")]
+ internal static void DumpCallers () {
+ StackTrace trace = new StackTrace(true);
+ int count = trace.FrameCount;
+ Debug.Indent ();
+ for (int i = 1; i < count; i++) {
+ StackFrame parentFrame = trace.GetFrame(i);
+ MethodBase parentMethod = parentFrame.GetMethod();
+ string file = parentFrame.GetFileName();
+ if (file != null && file.Length > 1)
+ file = file.Substring (file.LastIndexOf (Path.DirectorySeparatorChar) + 1);
+ Debug.WriteLine(parentMethod.DeclaringType.Name + "." + parentMethod.Name +
+ " at " + file + ":" + parentFrame.GetFileLineNumber()
+ );
+ }
+
+ Debug.Unindent ();
+ }
+
+ [Conditional("DEBUG")]
+ internal static void DumpCallers (int count) {
+ StackTrace trace = new StackTrace(true);
+ int c = (count > trace.FrameCount ? trace.FrameCount : count);
+ Debug.Indent ();
+ for (int i = 1; i < c; i++) {
+ StackFrame parentFrame = trace.GetFrame(i);
+ MethodBase parentMethod = parentFrame.GetMethod();
+ string file = parentFrame.GetFileName();
+ if (file != null && file.Length > 1)
+ file = file.Substring (file.LastIndexOf (Path.DirectorySeparatorChar) + 1);
+ Debug.WriteLine(parentMethod.DeclaringType.Name + "." + parentMethod.Name +
+ " at " + file + ":" + parentFrame.GetFileLineNumber()
+ );
+ }
+
+ Debug.Unindent ();
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Enter ()
+ {
+ StackTrace trace = new StackTrace();
+ methods.Push (new Data (trace.GetFrame(1).GetMethod(), null));
+ Print ();
+ Debug.Indent ();
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Enter (object[] args)
+ {
+ StackTrace trace = new StackTrace();
+ methods.Push (new Data (trace.GetFrame(1).GetMethod(), args));
+ Print ();
+ Debug.Indent ();
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Leave ()
+ {
+ if (methods.Count > 0) {
+ methods.Pop ();
+ Debug.Unindent ();
+ }
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Print ()
+ {
+ if (methods.Count == 0)
+ return;
+
+ Data data = methods.Peek ();
+ Debug.WriteLine (data.method.DeclaringType.Name + "." + data.method.Name);
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Print (int index)
+ {
+ if (methods.Count == 0 || methods.Count <= index || index < 0)
+ return;
+
+ Stack<Data> temp = new Stack<Data>(index-1);
+
+ for (int i = 0; i < index; i++)
+ temp.Push (methods.Pop ());
+
+ Data data = methods.Peek ();
+ for (int i = 0; i < temp.Count; i++)
+ methods.Push (temp.Pop());
+ temp = null;
+
+ Debug.WriteLine (data.method.DeclaringType.Name + "." + data.method.Name);
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Print (string methodName, string parameterName)
+ {
+ if (methods.Count == 0)
+ return;
+
+ Stack<Data> temp = new Stack<Data>();
+
+ Data data = methods.Peek ();
+ bool foundit = false;
+ for (int i = 0; i < methods.Count; i++)
+ {
+ data = methods.Peek ();
+ if (data.method.Name.Equals (methodName)) {
+ foundit = true;
+ break;
+ }
+ temp.Push (methods.Pop ());
+ }
+
+ for (int i = 0; i < temp.Count; i++)
+ methods.Push (temp.Pop());
+ temp = null;
+
+ if (!foundit)
+ return;
+
+ Debug.WriteLine (data.method.DeclaringType.Name + "." + data.method.Name);
+ ParameterInfo[] pi = data.method.GetParameters ();
+
+ for (int i = 0; i < pi.Length; i++) {
+ if (pi[i].Name == parameterName) {
+ Debug.Indent ();
+ Debug.Write (parameterName + "=");
+ if (pi[i].ParameterType == typeof(IntPtr))
+ Debug.WriteLine (String.Format ("0x{0:x}", ((IntPtr)data.args[i]).ToInt32()));
+ else
+ Debug.WriteLine (data.args[i]);
+ Debug.Unindent ();
+ }
+ }
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Print (string parameterName)
+ {
+ if (methods.Count == 0)
+ return;
+ Data data = methods.Peek ();
+
+ ParameterInfo[] pi = data.method.GetParameters ();
+
+ for (int i = 0; i < pi.Length; i++) {
+ if (pi[i].Name == parameterName) {
+ Debug.Indent ();
+ Debug.Write (parameterName + "=");
+ if (pi[i].ParameterType == typeof(IntPtr))
+ Debug.WriteLine (String.Format ("0x{0:x}", data.args[i]));
+ else
+ Debug.WriteLine (data.args[i]);
+ Debug.Unindent ();
+ }
+ }
+ }
+
+ [Conditional("DEBUG")]
+ internal static void WriteLine (object arg)
+ {
+ Debug.WriteLine (arg);
+ }
+
+ [Conditional("DEBUG")]
+ internal static void WriteLine (string format, params object[] arg)
+ {
+ Debug.WriteLine (String.Format (format, arg));
+ }
+
+ [Conditional("DEBUG")]
+ internal static void WriteLine (string message)
+ {
+ Debug.WriteLine (message);
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Indent ()
+ {
+ Debug.Indent ();
+ }
+
+ [Conditional("DEBUG")]
+ internal static void Unindent ()
+ {
+ Debug.Unindent ();
+ }
+
+ [Conditional("TRACE")]
+ internal static void TraceWriteLine (string format, params object[] arg)
+ {
+ Debug.WriteLine (String.Format (format, arg));
+ }
+
+ [Conditional("TRACE")]
+ internal static void TraceWriteLine (string message)
+ {
+ Debug.WriteLine (message);
+ }
+
+ }
+}
diff --git a/source/ShiftUI/Internal/DefaultLayout.cs b/source/ShiftUI/Internal/DefaultLayout.cs
new file mode 100644
index 0000000..4fbf647
--- /dev/null
+++ b/source/ShiftUI/Internal/DefaultLayout.cs
@@ -0,0 +1,290 @@
+//
+// DefaultLayout.cs
+//
+// 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) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+// Stefan Noack ([email protected])
+//
+
+using System;
+using System.Drawing;
+
+namespace ShiftUI.Layout
+{
+ class DefaultLayout : LayoutEngine
+ {
+ void LayoutDockedChildren (Widget parent, Widget[] Widgets)
+ {
+ Rectangle space = parent.DisplayRectangle;
+ MdiClient mdi = null;
+
+ // Deal with docking; go through in reverse, MS docs say that lowest Z-order is closest to edge
+ for (int i = Widgets.Length - 1; i >= 0; i--) {
+ Widget child = Widgets[i];
+ Size child_size = child.Size;
+
+ if (child.AutoSize)
+ child_size = GetPreferredWidgetSize (child);
+
+ if (!child.VisibleInternal
+ || child.WidgetLayoutType == Widget.LayoutType.Anchor)
+ continue;
+
+ // MdiClient never fills the whole area like other Widgets, have to do it later
+ if (child is MdiClient) {
+ mdi = (MdiClient)child;
+ continue;
+ }
+
+ switch (child.Dock) {
+ case DockStyle.None:
+ // Do nothing
+ break;
+
+ case DockStyle.Left:
+ child.SetBoundsInternal (space.Left, space.Y, child_size.Width, space.Height, BoundsSpecified.None);
+ space.X += child.Width;
+ space.Width -= child.Width;
+ break;
+
+ case DockStyle.Top:
+ child.SetBoundsInternal (space.Left, space.Y, space.Width, child_size.Height, BoundsSpecified.None);
+ space.Y += child.Height;
+ space.Height -= child.Height;
+ break;
+
+ case DockStyle.Right:
+ child.SetBoundsInternal (space.Right - child_size.Width, space.Y, child_size.Width, space.Height, BoundsSpecified.None);
+ space.Width -= child.Width;
+ break;
+
+ case DockStyle.Bottom:
+ child.SetBoundsInternal (space.Left, space.Bottom - child_size.Height, space.Width, child_size.Height, BoundsSpecified.None);
+ space.Height -= child.Height;
+ break;
+
+ case DockStyle.Fill:
+ child.SetBoundsInternal (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None);
+ break;
+ }
+ }
+
+ // MdiClient gets whatever space is left
+ if (mdi != null)
+ mdi.SetBoundsInternal (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None);
+ }
+
+ void LayoutAnchoredChildren (Widget parent, Widget[] Widgets)
+ {
+ Rectangle space = parent.ClientRectangle;
+
+ for (int i = 0; i < Widgets.Length; i++) {
+ int left;
+ int top;
+ int width;
+ int height;
+
+ Widget child = Widgets[i];
+
+ if (!child.VisibleInternal
+ || child.WidgetLayoutType == Widget.LayoutType.Dock)
+ continue;
+
+ AnchorStyles anchor = child.Anchor;
+
+ left = child.Left;
+ top = child.Top;
+
+ width = child.Width;
+ height = child.Height;
+
+ if ((anchor & AnchorStyles.Right) != 0) {
+ if ((anchor & AnchorStyles.Left) != 0)
+ width = space.Width - child.dist_right - left;
+ else
+ left = space.Width - child.dist_right - width;
+ }
+ else if ((anchor & AnchorStyles.Left) == 0) {
+ // left+=diff_width/2 will introduce rounding errors (diff_width removed from svn after r51780)
+ // This calculates from scratch every time:
+ left = left + (space.Width - (left + width + child.dist_right)) / 2;
+ child.dist_right = space.Width - (left + width);
+ }
+
+ if ((anchor & AnchorStyles.Bottom) != 0) {
+ if ((anchor & AnchorStyles.Top) != 0)
+ height = space.Height - child.dist_bottom - top;
+ else
+ top = space.Height - child.dist_bottom - height;
+ }
+ else if ((anchor & AnchorStyles.Top) == 0) {
+ // top += diff_height/2 will introduce rounding errors (diff_height removed from after r51780)
+ // This calculates from scratch every time:
+ top = top + (space.Height - (top + height + child.dist_bottom)) / 2;
+ child.dist_bottom = space.Height - (top + height);
+ }
+
+ // Sanity
+ if (width < 0)
+ width = 0;
+
+ if (height < 0)
+ height = 0;
+
+ child.SetBoundsInternal (left, top, width, height, BoundsSpecified.None);
+ }
+ }
+
+ void LayoutAutoSizedChildren (Widget parent, Widget[] Widgets)
+ {
+ for (int i = 0; i < Widgets.Length; i++) {
+ int left;
+ int top;
+
+ Widget child = Widgets[i];
+ if (!child.VisibleInternal
+ || child.WidgetLayoutType == Widget.LayoutType.Dock
+ || !child.AutoSize)
+ continue;
+
+ AnchorStyles anchor = child.Anchor;
+ left = child.Left;
+ top = child.Top;
+
+ Size preferredsize = GetPreferredWidgetSize (child);
+
+ if (((anchor & AnchorStyles.Left) != 0) || ((anchor & AnchorStyles.Right) == 0))
+ child.dist_right += child.Width - preferredsize.Width;
+ if (((anchor & AnchorStyles.Top) != 0) || ((anchor & AnchorStyles.Bottom) == 0))
+ child.dist_bottom += child.Height - preferredsize.Height;
+
+ child.SetBoundsInternal (left, top, preferredsize.Width, preferredsize.Height, BoundsSpecified.None);
+ }
+ }
+
+ void LayoutAutoSizeContainer (Widget container)
+ {
+ int left;
+ int top;
+ int width;
+ int height;
+
+ if (!container.VisibleInternal || container.WidgetLayoutType == Widget.LayoutType.Dock || !container.AutoSize)
+ return;
+
+ left = container.Left;
+ top = container.Top;
+
+ Size preferredsize = container.PreferredSize;
+
+ if (container.GetAutoSizeMode () == AutoSizeMode.GrowAndShrink) {
+ width = preferredsize.Width;
+ height = preferredsize.Height;
+ } else {
+ width = container.ExplicitBounds.Width;
+ height = container.ExplicitBounds.Height;
+ if (preferredsize.Width > width)
+ width = preferredsize.Width;
+ if (preferredsize.Height > height)
+ height = preferredsize.Height;
+ }
+
+ // Sanity
+ if (width < container.MinimumSize.Width)
+ width = container.MinimumSize.Width;
+
+ if (height < container.MinimumSize.Height)
+ height = container.MinimumSize.Height;
+
+ if (container.MaximumSize.Width != 0 && width > container.MaximumSize.Width)
+ width = container.MaximumSize.Width;
+
+ if (container.MaximumSize.Height != 0 && height > container.MaximumSize.Height)
+ height = container.MaximumSize.Height;
+
+ container.SetBoundsInternal (left, top, width, height, BoundsSpecified.None);
+ }
+
+ public override bool Layout (object container, LayoutEventArgs args)
+ {
+ Widget parent = container as Widget;
+
+ Widget[] Widgets = parent.Widgets.GetAllWidgets ();
+
+ LayoutDockedChildren (parent, Widgets);
+ LayoutAnchoredChildren (parent, Widgets);
+ LayoutAutoSizedChildren (parent, Widgets);
+ if (parent is Form) LayoutAutoSizeContainer (parent);
+
+ return false;
+ }
+
+ private Size GetPreferredWidgetSize (Widget child)
+ {
+ int width;
+ int height;
+ Size preferredsize = child.PreferredSize;
+
+ if (child.GetAutoSizeMode () == AutoSizeMode.GrowAndShrink || (child.Dock != DockStyle.None && !(child is Button) && !(child is FlowLayoutPanel))) {
+ width = preferredsize.Width;
+ height = preferredsize.Height;
+ } else {
+ width = child.ExplicitBounds.Width;
+ height = child.ExplicitBounds.Height;
+ if (preferredsize.Width > width)
+ width = preferredsize.Width;
+ if (preferredsize.Height > height)
+ height = preferredsize.Height;
+ }
+ if (child.AutoSize && child is FlowLayoutPanel && child.Dock != DockStyle.None) {
+ switch (child.Dock) {
+ case DockStyle.Left:
+ case DockStyle.Right:
+ if (preferredsize.Width < child.ExplicitBounds.Width && preferredsize.Height < child.Parent.PaddingClientRectangle.Height)
+ width = preferredsize.Width;
+ break;
+ case DockStyle.Top:
+ case DockStyle.Bottom:
+ if (preferredsize.Height < child.ExplicitBounds.Height && preferredsize.Width < child.Parent.PaddingClientRectangle.Width)
+ height = preferredsize.Height;
+ break;
+ }
+ }
+ // Sanity
+ if (width < child.MinimumSize.Width)
+ width = child.MinimumSize.Width;
+
+ if (height < child.MinimumSize.Height)
+ height = child.MinimumSize.Height;
+
+ if (child.MaximumSize.Width != 0 && width > child.MaximumSize.Width)
+ width = child.MaximumSize.Width;
+
+ if (child.MaximumSize.Height != 0 && height > child.MaximumSize.Height)
+ height = child.MaximumSize.Height;
+
+ return new Size (width, height);
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/Dnd.cs b/source/ShiftUI/Internal/Dnd.cs
new file mode 100644
index 0000000..b08b528
--- /dev/null
+++ b/source/ShiftUI/Internal/Dnd.cs
@@ -0,0 +1,371 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton ([email protected])
+//
+//
+
+
+using System;
+using System.IO;
+using System.Text;
+using System.Drawing;
+using System.Threading;
+using System.Collections;
+using ShiftUI;
+using System.Runtime.Serialization;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization.Formatters.Binary;
+
+namespace ShiftUI.CarbonInternal {
+ internal delegate void DragTrackingDelegate (short message, IntPtr window, IntPtr data, IntPtr dragref);
+
+ internal class Dnd {
+ internal const uint kEventParamDragRef = 1685217639;
+ internal const uint typeDragRef = 1685217639;
+
+ internal const uint typeMono = 1836019311;
+ internal const uint typeMonoSerializedObject = 1836279154;
+
+ private static DragDropEffects effects = DragDropEffects.None;
+ private static DragTrackingDelegate DragTrackingHandler = new DragTrackingDelegate (TrackingCallback);
+
+ static Dnd () {
+ try {
+ InstallTrackingHandler (DragTrackingHandler, IntPtr.Zero, IntPtr.Zero);
+ } catch (EntryPointNotFoundException) {
+ // it is deprecated in 10.6 and does not exist anymore.
+ }
+ }
+
+ internal Dnd () {
+ }
+
+ internal static void TrackingCallback (short message, IntPtr window, IntPtr data, IntPtr dragref) {
+ XplatUICarbon.GetInstance ().FlushQueue ();
+ }
+
+ internal static DragDropEffects DragActionsToEffects (UInt32 actions) {
+ DragDropEffects effects = DragDropEffects.None;
+ if ((actions & 1) != 0)
+ effects |= DragDropEffects.Copy;
+ if ((actions & (1 << 4)) != 0)
+ effects |= DragDropEffects.Move;
+ if ((actions & 0xFFFFFFFF) != 0)
+ effects |= DragDropEffects.All;
+
+ return effects;
+ }
+
+ internal static DataObject DragToDataObject (IntPtr dragref) {
+ UInt32 items = 0;
+ ArrayList flavorlist = new ArrayList ();
+
+ CountDragItems (dragref, ref items);
+
+ for (uint item_counter = 1; item_counter <= items; item_counter++) {
+ IntPtr itemref = IntPtr.Zero;
+ UInt32 flavors = 0;
+
+ GetDragItemReferenceNumber (dragref, item_counter, ref itemref);
+ CountDragItemFlavors (dragref, itemref, ref flavors);
+ for (uint flavor_counter = 1; flavor_counter <= flavors; flavor_counter++) {
+ FlavorHandler flavor = new FlavorHandler (dragref, itemref, flavor_counter);
+ if (flavor.Supported)
+ flavorlist.Add (flavor);
+ }
+ }
+
+ if (flavorlist.Count > 0) {
+ return ((FlavorHandler) flavorlist [0]).Convert (flavorlist);
+ }
+
+ return new DataObject ();
+ }
+
+ internal static bool HandleEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
+ Widget Widget;
+ DataObject data;
+ DragEventArgs drag_event;
+ DragDropEffects allowed;
+ QDPoint point = new QDPoint ();
+ UInt32 actions = 0;
+ IntPtr dragref = IntPtr.Zero;
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd == null || hwnd.Handle != handle)
+ return false;
+
+ GetEventParameter (eventref, kEventParamDragRef, typeDragRef, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref dragref);
+ XplatUICarbon.GetGlobalMouse (ref point);
+ GetDragAllowableActions (dragref, ref actions);
+ Widget = Widget.FromHandle (hwnd.Handle);
+ allowed = DragActionsToEffects (actions);
+ data = DragToDataObject (dragref);
+ drag_event = new DragEventArgs (data, 0, point.x, point.y, allowed, DragDropEffects.None);
+
+ switch (kind) {
+ case WidgetHandler.kEventWidgetDragEnter: {
+ bool accept = Widget.AllowDrop;
+ SetEventParameter (eventref, WidgetHandler.kEventParamWidgetLikesDrag, WidgetHandler.typeBoolean, (uint)Marshal.SizeOf (typeof (bool)), ref accept);
+
+ Widget.DndEnter (drag_event);
+ effects = drag_event.Effect;
+ return false;
+ }
+ case WidgetHandler.kEventWidgetDragWithin:
+ Widget.DndOver (drag_event);
+ effects = drag_event.Effect;
+ break;
+ case WidgetHandler.kEventWidgetDragLeave:
+ Widget.DndLeave (drag_event);
+ break;
+ case WidgetHandler.kEventWidgetDragReceive:
+ Widget.DndDrop (drag_event);
+ break;
+ }
+ return true;
+ }
+
+ public void SetAllowDrop (Hwnd hwnd, bool allow) {
+ if (hwnd.allow_drop == allow)
+ return;
+
+ hwnd.allow_drop = allow;
+ SetWidgetDragTrackingEnabled (hwnd.whole_window, true);
+ SetWidgetDragTrackingEnabled (hwnd.client_window, true);
+ }
+
+ public void SendDrop (IntPtr handle, IntPtr from, IntPtr time) {
+ }
+
+ public DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowed_effects) {
+ IntPtr dragref = IntPtr.Zero;
+ EventRecord eventrecord = new EventRecord ();
+
+ effects = DragDropEffects.None;
+
+ NewDrag (ref dragref);
+ XplatUICarbon.GetGlobalMouse (ref eventrecord.mouse);
+ StoreObjectInDrag (handle, dragref, data);
+
+ TrackDrag (dragref, ref eventrecord, IntPtr.Zero);
+
+ DisposeDrag (dragref);
+
+ return effects;
+ }
+
+ public void StoreObjectInDrag (IntPtr handle, IntPtr dragref, object data) {
+ IntPtr type = IntPtr.Zero;
+ IntPtr dataptr = IntPtr.Zero;
+ Int32 size = 0;
+
+ if (data is string) {
+ // implement me
+ throw new NotSupportedException ("Implement me.");
+ } else if (data is ISerializable) {
+ MemoryStream stream = new MemoryStream ();
+ BinaryFormatter bf = new BinaryFormatter ();
+
+ bf.Serialize (stream, data);
+
+ dataptr = Marshal.AllocHGlobal ((int) stream.Length);
+ stream.Seek (0, 0);
+
+ for (int i = 0; i < stream.Length; i++) {
+ Marshal.WriteByte (dataptr, i, (byte) stream.ReadByte ());
+ }
+
+ type = (IntPtr) typeMonoSerializedObject;
+ size = (int) stream.Length;
+ } else {
+ dataptr = (IntPtr) GCHandle.Alloc (data);
+
+ type = (IntPtr) typeMono;
+ size = Marshal.SizeOf (typeof (IntPtr));
+ }
+
+ AddDragItemFlavor (dragref, handle, type, ref dataptr, size, 1 << 0);
+ }
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int InstallTrackingHandler (DragTrackingDelegate callback, IntPtr window, IntPtr data);
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int SetEventParameter (IntPtr eventref, uint name, uint type, uint size, ref bool data);
+
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int SetWidgetDragTrackingEnabled (IntPtr view, bool enabled);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int AddDragItemFlavor (IntPtr dragref, IntPtr itemref, IntPtr flavortype, ref IntPtr data, Int32 size, UInt32 flags);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int CountDragItems (IntPtr dragref, ref UInt32 count);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int CountDragItemFlavors (IntPtr dragref, IntPtr itemref, ref UInt32 count);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int GetDragItemReferenceNumber (IntPtr dragref, UInt32 index, ref IntPtr itemref);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int NewDrag (ref IntPtr dragref);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int TrackDrag (IntPtr dragref, ref EventRecord eventrecord, IntPtr region);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int DisposeDrag (IntPtr dragref);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int GetDragAllowableActions (IntPtr dragref, ref UInt32 actions);
+ }
+
+ internal struct EventRecord {
+ internal UInt16 what;
+ internal UInt32 message;
+ internal UInt32 when;
+ internal QDPoint mouse;
+ internal UInt16 modifiers;
+ }
+
+ internal class FlavorHandler {
+ internal IntPtr flavorref;
+ internal IntPtr dragref;
+ internal IntPtr itemref;
+ internal Int32 size;
+ internal UInt32 flags;
+ internal byte [] data;
+ internal string fourcc;
+
+ internal FlavorHandler (IntPtr dragref, IntPtr itemref, uint counter) {
+ GetFlavorType (dragref, itemref, counter, ref flavorref);
+ GetFlavorFlags (dragref, itemref, flavorref, ref flags);
+ byte [] fourcc_b = BitConverter.GetBytes ((Int32)flavorref);
+ this.fourcc = String.Format ("{0}{1}{2}{3}", (char)fourcc_b [3], (char)fourcc_b [2], (char)fourcc_b [1], (char)fourcc_b [0]);
+ this.dragref = dragref;
+ this.itemref = itemref;
+
+ this.GetData ();
+ }
+
+ internal void GetData () {
+ GetFlavorDataSize (dragref, itemref, flavorref, ref size);
+ data = new byte [size];
+ GetFlavorData (dragref, itemref, flavorref, data, ref size, 0);
+ }
+
+ internal string DataString {
+ get { return Encoding.Default.GetString (this.data); }
+ }
+
+ internal byte[] DataArray {
+ get { return this.data; }
+ }
+
+ internal IntPtr DataPtr {
+ get { return (IntPtr) BitConverter.ToInt32 (this.data, 0); }
+ }
+
+ internal bool Supported {
+ get {
+ switch (fourcc) {
+ case "furl":
+ return true;
+ case "mono":
+ return true;
+ case "mser":
+ return true;
+ }
+ return false;
+ }
+ }
+
+ internal DataObject Convert (ArrayList flavorlist) {
+ switch (fourcc) {
+ case "furl":
+ return ConvertToFileDrop (flavorlist);
+ case "mono":
+ return ConvertToObject (flavorlist);
+ case "mser":
+ return DeserializeObject (flavorlist);
+ }
+
+ return new DataObject ();
+ }
+
+ internal DataObject DeserializeObject (ArrayList flavorlist) {
+ DataObject data = new DataObject ();
+ MemoryStream stream = new MemoryStream (this.DataArray);
+ BinaryFormatter bf = new BinaryFormatter ();
+
+ if (stream.Length == 0)
+ return data;
+
+ stream.Seek (0, 0);
+ data.SetData (bf.Deserialize (stream));
+
+ return data;
+ }
+
+ internal DataObject ConvertToObject (ArrayList flavorlist) {
+ DataObject data = new DataObject ();
+
+ foreach (FlavorHandler flavor in flavorlist) {
+ GCHandle handle = (GCHandle) flavor.DataPtr;
+
+ data.SetData (handle.Target);
+ }
+
+ return data;
+ }
+
+ internal DataObject ConvertToFileDrop (ArrayList flavorlist) {
+ DataObject data = new DataObject ();
+ ArrayList uri_list = new ArrayList ();
+
+ foreach (FlavorHandler flavor in flavorlist) {
+ try {
+ uri_list.Add (new Uri (flavor.DataString).LocalPath);
+ } catch { }
+ }
+
+ string [] l = (string []) uri_list.ToArray (typeof (string));
+ if (l.Length < 1)
+ return data;
+ data.SetData (DataFormats.FileDrop, l);
+ data.SetData ("FileName", l [0]);
+ data.SetData ("FileNameW", l [0]);
+
+ return data;
+ }
+
+ public override string ToString () {
+ return fourcc;
+ }
+
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int GetFlavorDataSize (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref Int32 size);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int GetFlavorData (IntPtr dragref, IntPtr itemref, IntPtr flavorref, [In, Out] byte[] data, ref Int32 size, UInt32 offset);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int GetFlavorFlags (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref UInt32 flags);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ extern static int GetFlavorType (IntPtr dragref, IntPtr itemref, UInt32 index, ref IntPtr flavor);
+ }
+}
diff --git a/source/ShiftUI/Internal/DockingAttribute.cs b/source/ShiftUI/Internal/DockingAttribute.cs
new file mode 100644
index 0000000..3aba6bf
--- /dev/null
+++ b/source/ShiftUI/Internal/DockingAttribute.cs
@@ -0,0 +1,74 @@
+//
+// DockingAttribute.cs
+//
+// 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) 2006 Daniel Nauck
+//
+// Author:
+// Daniel Nauck (dna(at)mono-project(dot)de)
+
+
+using System;
+using ShiftUI;
+
+namespace ShiftUI
+{
+ [AttributeUsageAttribute(AttributeTargets.Class)]
+ public sealed class DockingAttribute : Attribute
+ {
+ private DockingBehavior dockingBehavior;
+
+ public DockingAttribute()
+ {
+ dockingBehavior = DockingBehavior.Never;
+ }
+
+ public DockingAttribute(DockingBehavior dockingBehavior)
+ {
+ this.dockingBehavior = dockingBehavior;
+ }
+
+ public static readonly DockingAttribute Default = new DockingAttribute();
+
+ public DockingBehavior DockingBehavior
+ {
+ get { return dockingBehavior; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is DockingAttribute)
+ return (dockingBehavior == ((DockingAttribute)obj).DockingBehavior);
+ else
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return dockingBehavior.GetHashCode();
+ }
+
+ public override bool IsDefaultAttribute()
+ {
+ return Default.Equals(this);
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/DockingBehavior.cs b/source/ShiftUI/Internal/DockingBehavior.cs
new file mode 100644
index 0000000..b5dcdc0
--- /dev/null
+++ b/source/ShiftUI/Internal/DockingBehavior.cs
@@ -0,0 +1,38 @@
+//
+// DockingBehavior.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+namespace ShiftUI
+{
+ public enum DockingBehavior
+ {
+ Never = 0,
+ Ask = 1,
+ AutoDock = 2
+ }
+}
diff --git a/source/ShiftUI/Internal/DrawToolTipEventArgs.cs b/source/ShiftUI/Internal/DrawToolTipEventArgs.cs
new file mode 100644
index 0000000..8d66f5f
--- /dev/null
+++ b/source/ShiftUI/Internal/DrawToolTipEventArgs.cs
@@ -0,0 +1,113 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Rolf Bjarne Kvinge <[email protected]>
+//
+//
+// COMPLETE
+
+
+using System.Drawing;
+using System;
+
+namespace ShiftUI
+{
+ public class DrawToolTipEventArgs : EventArgs
+ {
+ private Widget associated_control;
+ private IWin32Window associated_window;
+ private Color back_color;
+ private Font font;
+ private Rectangle bounds;
+ private Color fore_color;
+ private Graphics graphics;
+ private string tooltip_text;
+
+ public DrawToolTipEventArgs (Graphics graphics, IWin32Window associatedWindow, Widget associatedControl, Rectangle bounds, string toolTipText, Color backColor, Color foreColor, Font font)
+ {
+ this.graphics = graphics;
+ this.associated_window = associatedWindow;
+ this.associated_control = associatedControl;
+ this.bounds = bounds;
+ this.tooltip_text = toolTipText;
+ this.back_color = backColor;
+ this.fore_color = foreColor;
+ this.font = font;
+ }
+
+ public void DrawBackground ()
+ {
+ graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (back_color), bounds);
+ }
+
+ public void DrawBorder ()
+ {
+ WidgetPaint.DrawBorder (graphics, bounds, SystemColors.WindowFrame, ButtonBorderStyle.Solid);
+ }
+
+ public void DrawText ()
+ {
+ DrawText (TextFormatFlags.HidePrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
+ }
+
+ public void DrawText (TextFormatFlags flags)
+ {
+ TextRenderer.DrawTextInternal (graphics, tooltip_text, font, bounds, fore_color, flags, false);
+ }
+
+ public Widget AssociatedWidget {
+ get {
+ return associated_control;
+ }
+ }
+
+ public IWin32Window AssociatedWindow {
+ get {
+ return associated_window;
+ }
+ }
+
+ public Rectangle Bounds {
+ get {
+ return bounds;
+ }
+ }
+
+ public Font Font {
+ get {
+ return font;
+ }
+ }
+
+ public Graphics Graphics {
+ get {
+ return graphics;
+ }
+ }
+
+ public string ToolTipText {
+ get {
+ return tooltip_text;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/DrawToolTipEventHandler.cs b/source/ShiftUI/Internal/DrawToolTipEventHandler.cs
new file mode 100644
index 0000000..e647ae8
--- /dev/null
+++ b/source/ShiftUI/Internal/DrawToolTipEventHandler.cs
@@ -0,0 +1,31 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Rolf Bjarne Kvinge <[email protected]>
+//
+//
+// COMPLETE
+
+namespace ShiftUI
+{
+ public delegate void DrawToolTipEventHandler (object sender, DrawToolTipEventArgs e);
+}
diff --git a/source/ShiftUI/Internal/Enums.cs b/source/ShiftUI/Internal/Enums.cs
new file mode 100644
index 0000000..50d705e
--- /dev/null
+++ b/source/ShiftUI/Internal/Enums.cs
@@ -0,0 +1,108 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+
+using System;
+
+namespace ShiftUI.CarbonInternal {
+ internal enum WindowClass : uint {
+ kAlertWindowClass = 1,
+ kMovableAlertWindowClass = 2,
+ kModalWindowClass = 3,
+ kMovableModalWindowClass = 4,
+ kFloatingWindowClass = 5,
+ kDocumentWindowClass = 6,
+ kUtilityWindowClass = 8,
+ kHelpWindowClass = 10,
+ kSheetWindowClass = 11,
+ kToolbarWindowClass = 12,
+ kPlainWindowClass = 13,
+ kOverlayWindowClass = 14,
+ kSheetAlertWindowClass = 15,
+ kAltPlainWindowClass = 16,
+ kDrawerWindowClass = 20,
+ kAllWindowClasses = 0xFFFFFFFF
+ }
+
+ internal enum WindowAttributes : uint {
+ kWindowNoAttributes = 0,
+ kWindowCloseBoxAttribute = (1u << 0),
+ kWindowHorizontalZoomAttribute = (1u << 1),
+ kWindowVerticalZoomAttribute = (1u << 2),
+ kWindowFullZoomAttribute = (kWindowVerticalZoomAttribute | kWindowHorizontalZoomAttribute),
+ kWindowCollapseBoxAttribute = (1u << 3),
+ kWindowResizableAttribute = (1u << 4),
+ kWindowSideTitlebarAttribute = (1u << 5),
+ kWindowToolbarButtonAttribute = (1u << 6),
+ kWindowMetalAttribute = (1u << 8),
+ kWindowNoUpdatesAttribute = (1u << 16),
+ kWindowNoActivatesAttribute = (1u << 17),
+ kWindowOpaqueForEventsAttribute = (1u << 18),
+ kWindowCompositingAttribute = (1u << 19),
+ kWindowNoShadowAttribute = (1u << 21),
+ kWindowHideOnSuspendAttribute = (1u << 24),
+ kWindowStandardHandlerAttribute = (1u << 25),
+ kWindowHideOnFullScreenAttribute = (1u << 26),
+ kWindowInWindowMenuAttribute = (1u << 27),
+ kWindowLiveResizeAttribute = (1u << 28),
+ kWindowIgnoreClicksAttribute = (1u << 29),
+ kWindowNoConstrainAttribute = (1u << 31),
+ kWindowStandardDocumentAttributes = (kWindowCloseBoxAttribute | kWindowFullZoomAttribute | kWindowCollapseBoxAttribute | kWindowResizableAttribute),
+ kWindowStandardFloatingAttributes = (kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute)
+ }
+
+ internal enum ThemeCursor : uint {
+ kThemeArrowCursor = 0,
+ kThemeCopyArrowCursor = 1,
+ kThemeAliasArrowCursor = 2,
+ kThemeContextualMenuArrowCursor = 3,
+ kThemeIBeamCursor = 4,
+ kThemeCrossCursor = 5,
+ kThemePlusCursor = 6,
+ kThemeWatchCursor = 7,
+ kThemeClosedHandCursor = 8,
+ kThemeOpenHandCursor = 9,
+ kThemePointingHandCursor = 10,
+ kThemeCountingUpHandCursor = 11,
+ kThemeCountingDownHandCursor = 12,
+ kThemeCountingUpAndDownHandCursor = 13,
+ kThemeSpinningCursor = 14,
+ kThemeResizeLeftCursor = 15,
+ kThemeResizeRightCursor = 16,
+ kThemeResizeLeftRightCursor = 17,
+ kThemeNotAllowedCursor = 18
+ }
+
+ internal enum MouseTrackingResult : ushort {
+ kMouseTrackingMouseDown = 1,
+ kMouseTrackingMouseUp = 2,
+ kMouseTrackingMouseExited = 3,
+ kMouseTrackingMouseEntered = 4,
+ kMouseTrackingMouseDragged = 5,
+ kMouseTrackingKeyModifiersChanged = 6,
+ kMouseTrackingUserCancelled = 7,
+ kMouseTrackingTimedOut = 8,
+ kMouseTrackingMouseMoved = 9
+ }
+}
diff --git a/source/ShiftUI/Internal/EventHandler.cs b/source/ShiftUI/Internal/EventHandler.cs
new file mode 100644
index 0000000..673e3d0
--- /dev/null
+++ b/source/ShiftUI/Internal/EventHandler.cs
@@ -0,0 +1,184 @@
+// 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 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.CarbonInternal {
+ internal delegate int EventDelegate (IntPtr callref, IntPtr eventref, IntPtr user_data);
+
+ internal class EventHandler {
+ internal static EventDelegate EventHandlerDelegate = new EventDelegate (EventCallback);
+ internal static XplatUICarbon Driver;
+
+ internal const int EVENT_NOT_HANDLED = 0;
+ internal const int EVENT_HANDLED = -9874;
+
+ internal const uint kEventClassMouse = 1836021107;
+ internal const uint kEventClassKeyboard = 1801812322;
+ internal const uint kEventClassTextInput = 1952807028;
+ internal const uint kEventClassApplication = 1634758764;
+ internal const uint kEventClassAppleEvent = 1701867619;
+ internal const uint kEventClassMenu = 1835363957;
+ internal const uint kEventClassWindow = 2003398244;
+ internal const uint kEventClassWidget = 1668183148;
+ internal const uint kEventClassCommand = 1668113523;
+ internal const uint kEventClassTablet = 1952607348;
+ internal const uint kEventClassVolume = 1987013664;
+ internal const uint kEventClassAppearance = 1634758765;
+ internal const uint kEventClassService = 1936028278;
+ internal const uint kEventClassToolbar = 1952604530;
+ internal const uint kEventClassToolbarItem = 1952606580;
+ internal const uint kEventClassAccessibility = 1633903461;
+ internal const uint kEventClassHIObject = 1751740258;
+
+ internal static EventTypeSpec [] HIObjectEvents = new EventTypeSpec [] {
+ new EventTypeSpec (kEventClassHIObject, HIObjectHandler.kEventHIObjectConstruct),
+ new EventTypeSpec (kEventClassHIObject, HIObjectHandler.kEventHIObjectInitialize),
+ new EventTypeSpec (kEventClassHIObject, HIObjectHandler.kEventHIObjectDestruct)
+ };
+ internal static EventTypeSpec [] WidgetEvents = new EventTypeSpec [] {
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetBoundsChanged),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDraw),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragEnter),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragWithin),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragLeave),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragReceive),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetGetFocusPart),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetInitialize),
+ new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetVisibilityChanged)
+ };
+
+ internal static EventTypeSpec [] ApplicationEvents = new EventTypeSpec[] {
+ new EventTypeSpec (kEventClassApplication, ApplicationHandler.kEventAppActivated),
+ new EventTypeSpec (kEventClassApplication, ApplicationHandler.kEventAppDeactivated)
+ };
+
+ private static EventTypeSpec [] WindowEvents = new EventTypeSpec[] {
+ new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseMoved),
+ new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseDragged),
+ new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseDown),
+ new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseUp),
+ new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseWheelMoved),
+ new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseScroll),
+
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowDeactivated),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowActivated),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowDeactivated),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowCollapsed),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowCollapsing),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowExpanded),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowExpanding),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowBoundsChanged),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowResizeStarted),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowResizeCompleted),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowClose),
+ new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowShown),
+
+ new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyModifiersChanged),
+ new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyDown),
+ new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyRepeat),
+ new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyUp),
+ new EventTypeSpec (kEventClassTextInput, KeyboardHandler.kEventTextInputUnicodeForKeyEvent)
+ };
+
+ internal static int EventCallback (IntPtr callref, IntPtr eventref, IntPtr handle) {
+ uint klass = GetEventClass (eventref);
+ uint kind = GetEventKind (eventref);
+ MSG msg = new MSG ();
+ IEventHandler handler = null;
+
+ switch (klass) {
+ case kEventClassHIObject: {
+ handler = (IEventHandler) Driver.HIObjectHandler;
+ break;
+ }
+ case kEventClassKeyboard:
+ case kEventClassTextInput:
+ handler = (IEventHandler) Driver.KeyboardHandler;
+ break;
+ case kEventClassWindow:
+ handler = (IEventHandler) Driver.WindowHandler;
+ break;
+ case kEventClassMouse:
+ handler = (IEventHandler) Driver.MouseHandler;
+ break;
+ case kEventClassWidget:
+ handler = (IEventHandler) Driver.WidgetHandler;
+ break;
+ case kEventClassApplication:
+ handler = (IEventHandler) Driver.ApplicationHandler;
+ break;
+ default:
+ return EVENT_NOT_HANDLED;
+ }
+
+ if (handler.ProcessEvent (callref, eventref, handle, kind, ref msg)) {
+ Driver.EnqueueMessage (msg);
+ return EVENT_HANDLED;
+ }
+
+ return EVENT_NOT_HANDLED;
+ }
+
+ internal static bool TranslateMessage (ref MSG msg) {
+ bool result = false;
+
+ if (!result)
+ result = Driver.KeyboardHandler.TranslateMessage (ref msg);
+ if (!result)
+ result = Driver.MouseHandler.TranslateMessage (ref msg);
+
+ return result;
+ }
+
+ internal static void InstallApplicationHandler () {
+ InstallEventHandler (GetApplicationEventTarget (), EventHandlerDelegate, (uint)ApplicationEvents.Length, ApplicationEvents, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ internal static void InstallWidgetHandler (IntPtr Widget) {
+ InstallEventHandler (GetWidgetEventTarget (Widget), EventHandlerDelegate, (uint)WidgetEvents.Length, WidgetEvents, Widget, IntPtr.Zero);
+ }
+
+ internal static void InstallWindowHandler (IntPtr window) {
+ InstallEventHandler (GetWindowEventTarget (window), EventHandlerDelegate, (uint)WindowEvents.Length, WindowEvents, window, IntPtr.Zero);
+ }
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern IntPtr GetApplicationEventTarget ();
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern IntPtr GetWidgetEventTarget (IntPtr Widget);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern IntPtr GetWindowEventTarget (IntPtr window);
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern uint GetEventClass (IntPtr eventref);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern uint GetEventKind (IntPtr eventref);
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int InstallEventHandler (IntPtr window, EventDelegate event_handler, uint count, EventTypeSpec [] types, IntPtr user_data, IntPtr handlerref);
+ }
+}
diff --git a/source/ShiftUI/Internal/EventHandlerBase.cs b/source/ShiftUI/Internal/EventHandlerBase.cs
new file mode 100644
index 0000000..39bada4
--- /dev/null
+++ b/source/ShiftUI/Internal/EventHandlerBase.cs
@@ -0,0 +1,40 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+
+namespace ShiftUI.CarbonInternal {
+ internal abstract class EventHandlerBase {
+ internal XplatUICarbon Driver;
+
+ public EventHandlerBase () {
+ }
+
+ public EventHandlerBase (XplatUICarbon driver) {
+ Driver = driver;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/FixedSizeTextBox.cs b/source/ShiftUI/Internal/FixedSizeTextBox.cs
new file mode 100644
index 0000000..33b5dff
--- /dev/null
+++ b/source/ShiftUI/Internal/FixedSizeTextBox.cs
@@ -0,0 +1,47 @@
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+//
+//
+
+// This is an internal class that allows us to use a textbox as a child control
+// for things such as UpDown Widgets, and the ComboBox that will not have their
+// size altered by scaling
+
+namespace ShiftUI {
+
+ internal class FixedSizeTextBox : TextBox {
+
+ public FixedSizeTextBox ()
+ {
+ SetStyle (Widgetstyles.FixedWidth, true);
+ SetStyle (Widgetstyles.FixedHeight, true);
+ }
+
+ public FixedSizeTextBox (bool fixed_horz, bool fixed_vert) {
+ SetStyle (Widgetstyles.FixedWidth, fixed_horz);
+ SetStyle (Widgetstyles.FixedHeight, fixed_vert);
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/FlowLayout.cs b/source/ShiftUI/Internal/FlowLayout.cs
new file mode 100644
index 0000000..5eb55a5
--- /dev/null
+++ b/source/ShiftUI/Internal/FlowLayout.cs
@@ -0,0 +1,589 @@
+//
+// FlowLayout.cs
+//
+// 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) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+
+namespace ShiftUI.Layout
+{
+ class FlowLayout : LayoutEngine
+ {
+ private static FlowLayoutSettings default_settings = new FlowLayoutSettings ();
+
+ public FlowLayout ()
+ {
+ }
+
+ public override void InitLayout (object child, BoundsSpecified specified)
+ {
+ base.InitLayout (child, specified);
+ }
+
+ public override bool Layout (object container, LayoutEventArgs args)
+ {
+ if (container is ToolStripPanel)
+ return false;
+
+ if (container is ToolStrip)
+ return LayoutToolStrip ((ToolStrip)container);
+
+ Widget parent = container as Widget;
+
+ FlowLayoutSettings settings;
+ if (parent is FlowLayoutPanel)
+ settings = (parent as FlowLayoutPanel).LayoutSettings;
+ else
+ settings = default_settings;
+
+ // Nothing to layout, exit method
+ if (parent.Widgets.Count == 0) return false;
+
+ // Use DisplayRectangle so that parent.Padding is honored.
+ Rectangle parentDisplayRectangle = parent.DisplayRectangle;
+ Point currentLocation;
+
+ // Set our starting point based on flow direction
+ switch (settings.FlowDirection) {
+ case FlowDirection.BottomUp:
+ currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom);
+ break;
+ case FlowDirection.LeftToRight:
+ case FlowDirection.TopDown:
+ default:
+ currentLocation = parentDisplayRectangle.Location;
+ break;
+ case FlowDirection.RightToLeft:
+ currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top);
+ break;
+ }
+
+ bool forceFlowBreak = false;
+
+ List<Widget> rowWidgets = new List<Widget> ();
+
+ foreach (Widget c in parent.Widgets) {
+ // Only apply layout to visible Widgets.
+ if (!c.Visible) { continue; }
+
+ // Resize any AutoSize Widgets to their preferred size
+ if (c.AutoSize == true) {
+ Size new_size = c.GetPreferredSize (c.Size);
+ c.SetBoundsInternal (c.Left, c.Top, new_size.Width, new_size.Height, BoundsSpecified.None);
+ }
+
+ switch (settings.FlowDirection) {
+ case FlowDirection.BottomUp:
+ // Decide if it's time to start a new column
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents)
+ if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
+
+ currentLocation.X = FinishColumn (rowWidgets);
+ currentLocation.Y = parentDisplayRectangle.Bottom;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the right margin and set the Widget to our point
+ currentLocation.Offset (0, c.Margin.Bottom * -1);
+ c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height, c.Width, c.Height, BoundsSpecified.None);
+
+ // Update our location pointer
+ currentLocation.Y -= (c.Height + c.Margin.Top);
+ break;
+ case FlowDirection.LeftToRight:
+ default:
+ // Decide if it's time to start a new row
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents && !(parent is ToolStripPanel))
+ if ((parentDisplayRectangle.Width + parentDisplayRectangle.Left - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
+
+ currentLocation.Y = FinishRow (rowWidgets);
+ currentLocation.X = parentDisplayRectangle.Left;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the left margin and set the Widget to our point
+ currentLocation.Offset (c.Margin.Left, 0);
+ c.SetBoundsInternal (currentLocation.X, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None);
+
+ // Update our location pointer
+ currentLocation.X += c.Width + c.Margin.Right;
+ break;
+ case FlowDirection.RightToLeft:
+ // Decide if it's time to start a new row
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents)
+ if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
+
+ currentLocation.Y = FinishRow (rowWidgets);
+ currentLocation.X = parentDisplayRectangle.Right;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the right margin and set the Widget to our point
+ currentLocation.Offset (c.Margin.Right * -1, 0);
+ c.SetBoundsInternal (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None);
+
+ // Update our location pointer
+ currentLocation.X -= (c.Width + c.Margin.Left);
+ break;
+ case FlowDirection.TopDown:
+ // Decide if it's time to start a new column
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents)
+ if ((parentDisplayRectangle.Height + parentDisplayRectangle.Top - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
+
+ currentLocation.X = FinishColumn (rowWidgets);
+ currentLocation.Y = parentDisplayRectangle.Top;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the top margin and set the Widget to our point
+ currentLocation.Offset (0, c.Margin.Top);
+ c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y, c.Width, c.Height, BoundsSpecified.None);
+
+ // Update our location pointer
+ currentLocation.Y += c.Height + c.Margin.Bottom;
+ break;
+ }
+ // Add it to our list of things to adjust the second dimension of
+ rowWidgets.Add (c);
+
+ // If user set a flowbreak on this Widget, it will be the last one in this row/column
+ if (settings.GetFlowBreak (c))
+ forceFlowBreak = true;
+ }
+
+ // Set the Widget heights/widths for the last row/column
+ if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft)
+ FinishRow (rowWidgets);
+ else
+ FinishColumn (rowWidgets);
+
+ return false;
+ }
+
+ // Calculate the heights of the Widgets, returns the y coordinate of the greatest height it uses
+ private int FinishRow (List<Widget> row)
+ {
+ // Nothing to do
+ if (row.Count == 0) return 0;
+
+ int rowTop = int.MaxValue;
+ int rowBottom = 0;
+ bool allDockFill = true;
+ bool noAuto = true;
+
+ // Special semantics if all Widgets are Dock.Fill/Anchor:Top,Bottom or AutoSize = true
+ foreach (Widget c in row) {
+ if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
+ allDockFill = false;
+ if (c.AutoSize == true)
+ noAuto = false;
+ }
+
+ // Find the tallest Widget with a concrete height
+ foreach (Widget c in row) {
+ if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true))
+ rowBottom = c.Bottom + c.Margin.Bottom;
+ if (c.Top - c.Margin.Top < rowTop)
+ rowTop = c.Top - c.Margin.Top;
+ }
+
+ // Find the tallest Widget that is AutoSize = true
+ if (rowBottom == 0)
+ foreach (Widget c in row)
+ if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true))
+ rowBottom = c.Bottom + c.Margin.Bottom;
+
+ // Find the tallest Widget that is Dock = Fill
+ if (rowBottom == 0)
+ foreach (Widget c in row)
+ if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill))
+ rowBottom = c.Bottom + c.Margin.Bottom;
+
+ // Set the new heights for each Widget
+ foreach (Widget c in row)
+ if (allDockFill && noAuto)
+ c.SetBoundsInternal (c.Left, c.Top, c.Width, 0, BoundsSpecified.None);
+ else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
+ c.SetBoundsInternal (c.Left, c.Top, c.Width, rowBottom - c.Top - c.Margin.Bottom, BoundsSpecified.None);
+ else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
+ c.SetBoundsInternal (c.Left, rowBottom - c.Margin.Bottom - c.Height, c.Width, c.Height, BoundsSpecified.None);
+ else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top))
+ continue;
+ else
+ c.SetBoundsInternal (c.Left, ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop, c.Width, c.Height, BoundsSpecified.None);
+
+ // Return bottom y of this row used
+ if (rowBottom == 0)
+ return rowTop;
+
+ return rowBottom;
+ }
+
+ // Calculate the widths of the Widgets, returns the x coordinate of the greatest width it uses
+ private int FinishColumn (List<Widget> col)
+ {
+ // Nothing to do
+ if (col.Count == 0) return 0;
+
+ int rowLeft = int.MaxValue;
+ int rowRight = 0;
+ bool allDockFill = true;
+ bool noAuto = true;
+
+ // Special semantics if all Widgets are Dock.Fill/Anchor:Left,Right or AutoSize = true
+ foreach (Widget c in col) {
+ if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
+ allDockFill = false;
+ if (c.AutoSize == true)
+ noAuto = false;
+ }
+
+ // Find the widest Widget with a concrete width
+ foreach (Widget c in col) {
+ if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true))
+ rowRight = c.Right + c.Margin.Right;
+ if (c.Left - c.Margin.Left < rowLeft)
+ rowLeft = c.Left - c.Margin.Left;
+ }
+
+ // Find the widest Widget that is AutoSize = true
+ if (rowRight == 0)
+ foreach (Widget c in col)
+ if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true))
+ rowRight = c.Right + c.Margin.Right;
+
+ // Find the widest Widget that is Dock = Fill
+ if (rowRight == 0)
+ foreach (Widget c in col)
+ if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill))
+ rowRight = c.Right + c.Margin.Right;
+
+ // Set the new widths for each Widget
+ foreach (Widget c in col)
+ if (allDockFill && noAuto)
+ c.SetBoundsInternal (c.Left, c.Top, 0, c.Height, BoundsSpecified.None);
+ else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
+ c.SetBoundsInternal (c.Left, c.Top, rowRight - c.Left - c.Margin.Right, c.Height, BoundsSpecified.None);
+ else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
+ c.SetBoundsInternal (rowRight - c.Margin.Right - c.Width, c.Top, c.Width, c.Height, BoundsSpecified.None);
+ else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left))
+ continue;
+ else
+ c.SetBoundsInternal (((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft, c.Top, c.Width, c.Height, BoundsSpecified.None);
+
+ // Return rightmost x of this row used
+ if (rowRight == 0)
+ return rowLeft;
+
+ return rowRight;
+ }
+
+ #region Layout for ToolStrip
+ // ToolStrips use the same FlowLayout, but is made up of ToolStripItems which
+ // are Components instead of Widgets, so we have to duplicate this login for
+ // ToolStripItems.
+ private bool LayoutToolStrip (ToolStrip parent)
+ {
+ FlowLayoutSettings settings;
+ settings = (FlowLayoutSettings)parent.LayoutSettings;
+
+ // Nothing to layout, exit method
+ if (parent.Items.Count == 0) return false;
+
+ foreach (ToolStripItem tsi in parent.Items)
+ tsi.SetPlacement (ToolStripItemPlacement.Main);
+
+ // Use DisplayRectangle so that parent.Padding is honored.
+ Rectangle parentDisplayRectangle = parent.DisplayRectangle;
+ Point currentLocation;
+
+ // Set our starting point based on flow direction
+ switch (settings.FlowDirection) {
+ case FlowDirection.BottomUp:
+ currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom);
+ break;
+ case FlowDirection.LeftToRight:
+ case FlowDirection.TopDown:
+ default:
+ currentLocation = parentDisplayRectangle.Location;
+ break;
+ case FlowDirection.RightToLeft:
+ currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top);
+ break;
+ }
+
+ bool forceFlowBreak = false;
+
+ List<ToolStripItem> rowWidgets = new List<ToolStripItem> ();
+
+ foreach (ToolStripItem c in parent.Items) {
+ // Only apply layout to visible Widgets.
+ if (!c.Available) { continue; }
+
+ // Resize any AutoSize Widgets to their preferred size
+ if (c.AutoSize == true)
+ c.SetBounds (new Rectangle (c.Location, c.GetPreferredSize (c.Size)));
+
+ switch (settings.FlowDirection) {
+ case FlowDirection.BottomUp:
+ // Decide if it's time to start a new column
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents)
+ if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
+
+ currentLocation.X = FinishColumn (rowWidgets);
+ currentLocation.Y = parentDisplayRectangle.Bottom;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the right margin and set the Widget to our point
+ currentLocation.Offset (0, c.Margin.Bottom * -1);
+ c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height);
+
+ // Update our location pointer
+ currentLocation.Y -= (c.Height + c.Margin.Top);
+ break;
+ case FlowDirection.LeftToRight:
+ default:
+ // Decide if it's time to start a new row
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents)
+ if ((parentDisplayRectangle.Width - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
+
+ currentLocation.Y = FinishRow (rowWidgets);
+ currentLocation.X = parentDisplayRectangle.Left;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the left margin and set the Widget to our point
+ currentLocation.Offset (c.Margin.Left, 0);
+ c.Location = new Point (currentLocation.X, currentLocation.Y + c.Margin.Top);
+
+ // Update our location pointer
+ currentLocation.X += c.Width + c.Margin.Right;
+ break;
+ case FlowDirection.RightToLeft:
+ // Decide if it's time to start a new row
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents)
+ if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
+
+ currentLocation.Y = FinishRow (rowWidgets);
+ currentLocation.X = parentDisplayRectangle.Right;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the right margin and set the Widget to our point
+ currentLocation.Offset (c.Margin.Right * -1, 0);
+ c.Location = new Point (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top);
+
+ // Update our location pointer
+ currentLocation.X -= (c.Width + c.Margin.Left);
+ break;
+ case FlowDirection.TopDown:
+ // Decide if it's time to start a new column
+ // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true
+ if (settings.WrapContents)
+ if ((parentDisplayRectangle.Height - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
+
+ currentLocation.X = FinishColumn (rowWidgets);
+ currentLocation.Y = parentDisplayRectangle.Top;
+
+ forceFlowBreak = false;
+ rowWidgets.Clear ();
+ }
+
+ // Offset the top margin and set the Widget to our point
+ currentLocation.Offset (0, c.Margin.Top);
+ c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y);
+
+ // Update our location pointer
+ currentLocation.Y += c.Height + c.Margin.Bottom;
+ break;
+ }
+ // Add it to our list of things to adjust the second dimension of
+ rowWidgets.Add (c);
+
+ // If user set a flowbreak on this Widget, it will be the last one in this row/column
+ if (settings.GetFlowBreak (c))
+ forceFlowBreak = true;
+ }
+
+ int final_height = 0;
+
+ // Set the Widget heights/widths for the last row/column
+ if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft)
+ final_height = FinishRow (rowWidgets);
+ else
+ FinishColumn (rowWidgets);
+
+ if (final_height > 0)
+ parent.SetBoundsInternal (parent.Left, parent.Top, parent.Width, final_height + parent.Padding.Bottom, BoundsSpecified.None);
+
+ return false;
+
+ }
+
+ // Calculate the heights of the Widgets, returns the y coordinate of the greatest height it uses
+ private int FinishRow (List<ToolStripItem> row)
+ {
+ // Nothing to do
+ if (row.Count == 0) return 0;
+
+ int rowTop = int.MaxValue;
+ int rowBottom = 0;
+ bool allDockFill = true;
+ bool noAuto = true;
+
+ // Special semantics if all Widgets are Dock.Fill/Anchor:Top,Bottom or AutoSize = true
+ foreach (ToolStripItem c in row) {
+ if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
+ allDockFill = false;
+ if (c.AutoSize == true)
+ noAuto = false;
+ }
+
+ // Find the tallest Widget with a concrete height
+ foreach (ToolStripItem c in row) {
+ if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true))
+ rowBottom = c.Bottom + c.Margin.Bottom;
+ if (c.Top - c.Margin.Top < rowTop)
+ rowTop = c.Top - c.Margin.Top;
+ }
+
+ // Find the tallest Widget that is AutoSize = true
+ if (rowBottom == 0)
+ foreach (ToolStripItem c in row)
+ if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true))
+ rowBottom = c.Bottom + c.Margin.Bottom;
+
+ // Find the tallest Widget that is Dock = Fill
+ if (rowBottom == 0)
+ foreach (ToolStripItem c in row)
+ if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill))
+ rowBottom = c.Bottom + c.Margin.Bottom;
+
+ // Set the new heights for each Widget
+ foreach (ToolStripItem c in row)
+ if (allDockFill && noAuto)
+ c.Height = 0;
+ else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
+ c.Height = rowBottom - c.Top - c.Margin.Bottom;
+ else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
+ c.Top = rowBottom - c.Margin.Bottom - c.Height;
+ else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top))
+ continue;
+ else
+ c.Top = ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop;
+
+ // Return bottom y of this row used
+ if (rowBottom == 0)
+ return rowTop;
+
+ return rowBottom;
+ }
+
+ // Calculate the widths of the Widgets, returns the x coordinate of the greatest width it uses
+ private int FinishColumn (List<ToolStripItem> col)
+ {
+ // Nothing to do
+ if (col.Count == 0) return 0;
+
+ int rowLeft = int.MaxValue;
+ int rowRight = 0;
+ bool allDockFill = true;
+ bool noAuto = true;
+
+ // Special semantics if all Widgets are Dock.Fill/Anchor:Left,Right or AutoSize = true
+ foreach (ToolStripItem c in col) {
+ if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
+ allDockFill = false;
+ if (c.AutoSize == true)
+ noAuto = false;
+ }
+
+ // Find the widest Widget with a concrete width
+ foreach (ToolStripItem c in col) {
+ if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true))
+ rowRight = c.Right + c.Margin.Right;
+ if (c.Left - c.Margin.Left < rowLeft)
+ rowLeft = c.Left - c.Margin.Left;
+ }
+
+ // Find the widest Widget that is AutoSize = true
+ if (rowRight == 0)
+ foreach (ToolStripItem c in col)
+ if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true))
+ rowRight = c.Right + c.Margin.Right;
+
+ // Find the widest Widget that is Dock = Fill
+ if (rowRight == 0)
+ foreach (ToolStripItem c in col)
+ if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill))
+ rowRight = c.Right + c.Margin.Right;
+
+ // Set the new widths for each Widget
+ foreach (ToolStripItem c in col)
+ if (allDockFill && noAuto)
+ c.Width = 0;
+ else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
+ c.Width = rowRight - c.Left - c.Margin.Right;
+ else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
+ c.Left = rowRight - c.Margin.Right - c.Width;
+ else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left))
+ continue;
+ else
+ c.Left = ((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft;
+
+ // Return rightmost x of this row used
+ if (rowRight == 0)
+ return rowLeft;
+
+ return rowRight;
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/FlowLayoutSettings.cs b/source/ShiftUI/Internal/FlowLayoutSettings.cs
new file mode 100644
index 0000000..3480165
--- /dev/null
+++ b/source/ShiftUI/Internal/FlowLayoutSettings.cs
@@ -0,0 +1,111 @@
+//
+// FlowLayoutSettings.cs
+//
+// 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) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using ShiftUI.Layout;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System;
+
+namespace ShiftUI
+{
+ [DefaultProperty ("FlowDirection")]
+ public class FlowLayoutSettings : LayoutSettings
+ {
+ private FlowDirection flow_direction;
+ private bool wrap_contents;
+ private LayoutEngine layout_engine;
+ private Dictionary<object, bool> flow_breaks;
+ private Widget owner;
+
+ internal FlowLayoutSettings () : this (null)
+ {
+ }
+
+ internal FlowLayoutSettings (Widget owner)
+ {
+ flow_breaks = new Dictionary<object, bool> ();
+ wrap_contents = true;
+ flow_direction = FlowDirection.LeftToRight;
+ this.owner = owner;
+ }
+
+ #region Public Properties
+ [DefaultValue (FlowDirection.LeftToRight)]
+ public FlowDirection FlowDirection {
+ get { return this.flow_direction; }
+ set {
+ if (this.flow_direction != value) {
+ this.flow_direction = value;
+ if (owner != null)
+ owner.PerformLayout (owner, "FlowDirection");
+ }
+ }
+ }
+
+ public override LayoutEngine LayoutEngine {
+ get {
+ if (this.layout_engine == null)
+ this.layout_engine = new FlowLayout ();
+
+ return this.layout_engine;
+ }
+ }
+
+ [DefaultValue (true)]
+ public bool WrapContents {
+ get { return this.wrap_contents; }
+ set {
+ if (this.wrap_contents != value) {
+ this.wrap_contents = value;
+ if (owner != null)
+ owner.PerformLayout (owner, "WrapContents");
+ }
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ public bool GetFlowBreak (Object child)
+ {
+ bool retval;
+
+ if (flow_breaks.TryGetValue (child, out retval))
+ return retval;
+
+ return false;
+ }
+
+ public void SetFlowBreak (Object child, bool value)
+ {
+ flow_breaks[child] = value;
+ if (owner != null)
+ owner.PerformLayout ((Widget)child, "FlowBreak");
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/GetChildAtPointSkip.cs b/source/ShiftUI/Internal/GetChildAtPointSkip.cs
new file mode 100644
index 0000000..963406c
--- /dev/null
+++ b/source/ShiftUI/Internal/GetChildAtPointSkip.cs
@@ -0,0 +1,41 @@
+//
+// GetChildAtPointSkip.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+using System;
+
+
+namespace ShiftUI
+{
+ [Flags]
+ public enum GetChildAtPointSkip
+ {
+ None = 0,
+ Invisible = 1,
+ Disabled = 2,
+ Transparent = 4
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/GridItem.cs b/source/ShiftUI/Internal/GridItem.cs
new file mode 100644
index 0000000..3efac21
--- /dev/null
+++ b/source/ShiftUI/Internal/GridItem.cs
@@ -0,0 +1,114 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// NOT COMPLETE
+
+using System;
+using System.Drawing;
+using System.ComponentModel;
+
+namespace ShiftUI
+{
+ public abstract class GridItem
+ {
+ #region Fields
+ private bool expanded;
+ private object tag;
+ #endregion Fields
+
+ #region Constructors
+ protected GridItem()
+ {
+ expanded = false;
+ }
+ #endregion // Constructors
+
+ #region Public Instance Properties
+ public virtual bool Expandable
+ {
+ get {
+ return GridItems.Count > 1;
+ }
+ }
+
+ public virtual bool Expanded
+ {
+ get {
+ return expanded;
+ }
+
+ set {
+ expanded = value;
+ }
+ }
+
+ public abstract GridItemCollection GridItems
+ {
+ get;
+ }
+
+ public abstract GridItemType GridItemType
+ {
+ get;
+ }
+
+ public abstract string Label
+ {
+ get;
+ }
+
+
+ public abstract GridItem Parent
+ {
+ get;
+ }
+
+
+ public abstract PropertyDescriptor PropertyDescriptor
+ {
+ get;
+ }
+
+ [Localizable (false)]
+ [Bindable (true)]
+ [DefaultValue (null)]
+ [TypeConverter (typeof (StringConverter))]
+ public Object Tag {
+ get { return this.tag; }
+ set { this.tag = value; }
+ }
+
+ public abstract object Value
+ {
+ get;
+ set;
+ }
+ #endregion
+
+ #region Public Instance Methods
+ public abstract bool Select ();
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/GridItemType.cs b/source/ShiftUI/Internal/GridItemType.cs
new file mode 100644
index 0000000..821626a
--- /dev/null
+++ b/source/ShiftUI/Internal/GridItemType.cs
@@ -0,0 +1,38 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public enum GridItemType
+ {
+ Property = 0,
+ Category = 1,
+ ArrayValue = 2,
+ Root = 3
+ }
+}
+
diff --git a/source/ShiftUI/Internal/GroupBoxRenderer.cs b/source/ShiftUI/Internal/GroupBoxRenderer.cs
new file mode 100644
index 0000000..c0c9699
--- /dev/null
+++ b/source/ShiftUI/Internal/GroupBoxRenderer.cs
@@ -0,0 +1,157 @@
+//
+// GroupBoxRenderer.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System.Drawing;
+using ShiftUI.VisualStyles;
+using System;
+
+namespace ShiftUI
+{
+ public sealed class GroupBoxRenderer
+ {
+ private static bool always_use_visual_styles = false;
+
+ #region Private Constructor
+ private GroupBoxRenderer () { }
+ #endregion
+
+ #region Public Static Methods
+ public static void DrawGroupBox (Graphics g, Rectangle bounds, GroupBoxState state)
+ {
+ DrawGroupBox (g, bounds, String.Empty, null, Color.Empty, TextFormatFlags.Default, state);
+ }
+
+ public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, GroupBoxState state)
+ {
+ DrawGroupBox (g, bounds, groupBoxText, font, Color.Empty, TextFormatFlags.Default, state);
+ }
+
+ public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, Color textColor, GroupBoxState state)
+ {
+ DrawGroupBox (g, bounds, groupBoxText, font, textColor, TextFormatFlags.Default, state);
+ }
+
+ public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, TextFormatFlags flags, GroupBoxState state)
+ {
+ DrawGroupBox (g, bounds, groupBoxText, font, Color.Empty, flags, state);
+ }
+
+ public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, Color textColor, TextFormatFlags flags, GroupBoxState state)
+ {
+ Size font_size = TextRenderer.MeasureText (groupBoxText, font);
+
+ if (Application.RenderWithVisualStyles || always_use_visual_styles == true) {
+ VisualStyleRenderer vsr;
+ Rectangle new_bounds;
+
+ switch (state) {
+ case GroupBoxState.Normal:
+ default:
+ vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Normal);
+ new_bounds = new Rectangle (bounds.Left, bounds.Top + (int)(font_size.Height / 2) - 1, bounds.Width, bounds.Height - (int)(font_size.Height / 2) + 1);
+ break;
+ case GroupBoxState.Disabled:
+ vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Disabled);
+ new_bounds = new Rectangle (bounds.Left, bounds.Top + (int)(font_size.Height / 2) - 2, bounds.Width, bounds.Height - (int)(font_size.Height / 2) + 2);
+ break;
+ }
+
+ if (groupBoxText == String.Empty)
+ vsr.DrawBackground (g, bounds);
+ else
+ vsr.DrawBackgroundExcludingArea (g, new_bounds, new Rectangle (bounds.Left + 9, bounds.Top, font_size.Width - 3, font_size.Height));
+
+ if (textColor == Color.Empty)
+ textColor = vsr.GetColor (ColorProperty.TextColor);
+
+ if (groupBoxText != String.Empty)
+ TextRenderer.DrawText (g, groupBoxText, font, new Point (bounds.Left + 8, bounds.Top), textColor, flags);
+ }
+ else {
+ // MS has a pretty big bug when rendering the non-visual styles group box. Instead of using the height
+ // part of the bounds as height, they use it as the bottom, so the boxes are drawn in completely different
+ // places. Rather than emulate this bug, we do it correctly. After googling for a while, I don't think
+ // anyone has ever actually used this class for anything, so it should be fine. :)
+ Rectangle new_bounds = new Rectangle (bounds.Left, bounds.Top + (int)(font_size.Height / 2), bounds.Width, bounds.Height - (int)(font_size.Height / 2));
+
+ // Don't paint over the background where we are going to put the text
+ Region old_clip = g.Clip;
+ g.SetClip (new Rectangle (bounds.Left + 9, bounds.Top, font_size.Width - 3, font_size.Height), System.Drawing.Drawing2D.CombineMode.Exclude);
+
+ WidgetPaint.DrawBorder3D (g, new_bounds, Border3DStyle.Etched);
+
+ g.Clip = old_clip;
+
+ if (groupBoxText != String.Empty) {
+ if (textColor == Color.Empty)
+ textColor = state == GroupBoxState.Normal ? SystemColors.ControlText :
+ SystemColors.GrayText;
+ TextRenderer.DrawText (g, groupBoxText, font, new Point (bounds.Left + 8, bounds.Top), textColor, flags);
+ }
+ }
+ }
+
+ public static bool IsBackgroundPartiallyTransparent (GroupBoxState state)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return false;
+
+ VisualStyleRenderer vsr;
+
+ switch (state) {
+ case GroupBoxState.Normal:
+ default:
+ vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Normal);
+ break;
+ case GroupBoxState.Disabled:
+ vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Disabled);
+ break;
+ }
+
+ return vsr.IsBackgroundPartiallyTransparent ();
+ }
+
+ public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return;
+
+ VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Normal);
+
+ vsr.DrawParentBackground (g, bounds, childControl);
+ }
+ #endregion
+
+ #region Public Static Properties
+ public static bool RenderMatchingApplicationState {
+ get { return !always_use_visual_styles; }
+ set { always_use_visual_styles = !value; }
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/HIObjectHandler.cs b/source/ShiftUI/Internal/HIObjectHandler.cs
new file mode 100644
index 0000000..ca7adc0
--- /dev/null
+++ b/source/ShiftUI/Internal/HIObjectHandler.cs
@@ -0,0 +1,57 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.CarbonInternal {
+ internal class HIObjectHandler : EventHandlerBase, IEventHandler {
+ internal const uint kEventHIObjectConstruct = 1;
+ internal const uint kEventHIObjectInitialize = 2;
+ internal const uint kEventHIObjectDestruct = 3;
+
+ internal HIObjectHandler (XplatUICarbon driver) : base (driver) {}
+
+ public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
+ switch (kind) {
+ case kEventHIObjectConstruct:
+ IntPtr v = IntPtr.Zero;
+ GetEventParameter (eventref, (uint)1751740265, (uint)1751740258, IntPtr.Zero, 4, IntPtr.Zero, ref v);
+ return false;
+ case kEventHIObjectInitialize:
+ CallNextEventHandler (callref, eventref);
+ return false;
+ case kEventHIObjectDestruct:
+ return false;
+ }
+ return false;
+ }
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int CallNextEventHandler (IntPtr callref, IntPtr eventref);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data);
+ }
+}
diff --git a/source/ShiftUI/Internal/HScrollProperties.cs b/source/ShiftUI/Internal/HScrollProperties.cs
new file mode 100644
index 0000000..4eed2da
--- /dev/null
+++ b/source/ShiftUI/Internal/HScrollProperties.cs
@@ -0,0 +1,33 @@
+// 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.
+//
+// Authors:
+// Olivier Dufour [email protected]
+//
+
+namespace ShiftUI
+{
+ public class HScrollProperties : ScrollProperties
+ {
+ public HScrollProperties (ScrollableWidget container) : base (container)
+ {
+ scroll_bar = container.hscrollbar;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/Hwnd.cs b/source/ShiftUI/Internal/Hwnd.cs
new file mode 100644
index 0000000..fcdc17d
--- /dev/null
+++ b/source/ShiftUI/Internal/Hwnd.cs
@@ -0,0 +1,910 @@
+// 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) 2005-2006 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// NOT COMPLETE
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+// NOTE: Possible optimization:
+// Several properties calculate dimensions on the fly; instead; they can
+// be stored in a field and only be recalculated when a style is changed (DefaultClientRect, for example)
+
+namespace ShiftUI {
+ internal class Hwnd : IDisposable {
+ #region Local Variables
+ private static Hashtable windows = new Hashtable(100, 0.5f);
+ //private const int menu_height = 14; // FIXME - Read this value from somewhere
+
+ private IntPtr handle;
+ internal IntPtr client_window;
+ internal IntPtr whole_window;
+ internal IntPtr cursor;
+ internal Menu menu;
+ internal TitleStyle title_style;
+ internal FormBorderStyle border_style;
+ internal bool border_static;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal bool allow_drop;
+ internal Hwnd parent;
+ internal bool visible;
+ internal bool mapped;
+ internal uint opacity;
+ internal bool enabled;
+ internal bool zero_sized;
+ internal ArrayList invalid_list;
+ internal Rectangle nc_invalid;
+ internal bool expose_pending;
+ internal bool nc_expose_pending;
+ internal bool configure_pending;
+ internal bool resizing_or_moving; // Used by the X11 backend to track form resize/move
+ internal bool reparented;
+ internal Stack drawing_stack;
+ internal object user_data;
+ internal Rectangle client_rectangle;
+ internal ArrayList marshal_free_list;
+ internal int caption_height;
+ internal int tool_caption_height;
+ internal bool whacky_wm;
+ internal bool fixed_size;
+ internal bool zombie; /* X11 only flag. true if the X windows have been destroyed but we haven't been Disposed */
+ internal bool topmost; /* X11 only. */
+ internal Region user_clip;
+ internal XEventQueue queue;
+ internal WindowExStyles initial_ex_style;
+ internal WindowStyles initial_style;
+ internal FormWindowState cached_window_state = (FormWindowState)(-1); /* X11 only field */
+ internal Point previous_child_startup_location = new Point (int.MinValue, int.MinValue);
+ static internal Point previous_main_startup_location = new Point (int.MinValue, int.MinValue);
+ internal ArrayList children;
+
+ [ThreadStatic]
+ private static Bitmap bmp;
+ [ThreadStatic]
+ private static Graphics bmp_g;
+ #endregion // Local Variables
+
+ // locks for some operations (used in XplatUIX11.cs)
+ internal object configure_lock = new object ();
+ internal object expose_lock = new object ();
+
+ #region Constructors and destructors
+ public Hwnd() {
+ x = 0;
+ y = 0;
+ width = 0;
+ height = 0;
+ visible = false;
+ menu = null;
+ border_style = FormBorderStyle.None;
+ client_window = IntPtr.Zero;
+ whole_window = IntPtr.Zero;
+ cursor = IntPtr.Zero;
+ handle = IntPtr.Zero;
+ parent = null;
+ invalid_list = new ArrayList();
+ expose_pending = false;
+ nc_expose_pending = false;
+ enabled = true;
+ reparented = false;
+ client_rectangle = Rectangle.Empty;
+ marshal_free_list = new ArrayList(2);
+ opacity = 0xffffffff;
+ fixed_size = false;
+ drawing_stack = new Stack ();
+ children = new ArrayList ();
+ resizing_or_moving = false;
+ whacky_wm = false;
+ topmost = false;
+ }
+
+ public void Dispose() {
+ expose_pending = false;
+ nc_expose_pending = false;
+ Parent = null;
+ lock (windows) {
+ windows.Remove(client_window);
+ windows.Remove(whole_window);
+ }
+ client_window = IntPtr.Zero;
+ whole_window = IntPtr.Zero;
+ zombie = false;
+ for (int i = 0; i < marshal_free_list.Count; i++) {
+ Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
+ }
+ marshal_free_list.Clear();
+ }
+ #endregion
+
+ #region Static Methods
+ public static Hwnd ObjectFromWindow(IntPtr window) {
+ Hwnd rv;
+ lock (windows) {
+ rv = (Hwnd)windows[window];
+ }
+ return rv;
+ }
+
+ public static Hwnd ObjectFromHandle(IntPtr handle) {
+ //return (Hwnd)(((GCHandle)handle).Target);
+ Hwnd rv;
+ lock (windows) {
+ rv = (Hwnd)windows[handle];
+ }
+ return rv;
+ }
+
+ public static IntPtr HandleFromObject(Hwnd obj) {
+ return obj.handle;
+ }
+
+ public static Hwnd GetObjectFromWindow(IntPtr window) {
+ Hwnd rv;
+ lock (windows) {
+ rv = (Hwnd)windows[window];
+ }
+ return rv;
+ }
+
+ public static IntPtr GetHandleFromWindow(IntPtr window) {
+ Hwnd hwnd;
+
+ lock (windows) {
+ hwnd = (Hwnd)windows[window];
+ }
+ if (hwnd != null) {
+ return hwnd.handle;
+ } else {
+ return IntPtr.Zero;
+ }
+ }
+
+ public static Borders GetBorderWidth (CreateParams cp)
+ {
+ Borders border_size = new Borders ();
+
+ Size windowborder = ThemeEngine.Current.BorderSize; /*new Size (1, 1);*/ // This is the only one that can be changed from the display properties in windows.
+ Size border = ThemeEngine.Current.BorderStaticSize; /*new Size (1, 1);*/
+ Size clientedge = ThemeEngine.Current.Border3DSize; /*new Size (2, 2);*/
+ Size thickframe = new Size (2 + windowborder.Width, 2 + windowborder.Height);
+ Size dialogframe = ThemeEngine.Current.BorderSizableSize; /* new Size (3, 3);*/
+
+ if (cp.IsSet (WindowStyles.WS_CAPTION)) {
+ border_size.Inflate (dialogframe);
+ } else if (cp.IsSet (WindowStyles.WS_BORDER)) {
+ if (cp.IsSet (WindowExStyles.WS_EX_DLGMODALFRAME)) {
+ if (cp.IsSet (WindowStyles.WS_THICKFRAME) && (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE) || cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE))) {
+ border_size.Inflate (border);
+ }
+ } else {
+ border_size.Inflate (border);
+ }
+ } else if (cp.IsSet (WindowStyles.WS_DLGFRAME)) {
+ border_size.Inflate (dialogframe);
+ }
+
+ if (cp.IsSet (WindowStyles.WS_THICKFRAME)) {
+ if (cp.IsSet (WindowStyles.WS_DLGFRAME)) {
+ border_size.Inflate (border);
+ } else {
+ border_size.Inflate (thickframe);
+ }
+ }
+
+ bool only_small_border;
+ Size small_border = Size.Empty;
+
+ only_small_border = cp.IsSet (WindowStyles.WS_THICKFRAME) || cp.IsSet (WindowStyles.WS_DLGFRAME);
+ if (only_small_border && cp.IsSet (WindowStyles.WS_THICKFRAME) && !cp.IsSet (WindowStyles.WS_BORDER) && !cp.IsSet (WindowStyles.WS_DLGFRAME)) {
+ small_border = border;
+ }
+
+ if (cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE | WindowExStyles.WS_EX_DLGMODALFRAME)) {
+ border_size.Inflate (clientedge + (only_small_border ? small_border : dialogframe));
+ } else if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE | WindowExStyles.WS_EX_DLGMODALFRAME)) {
+ border_size.Inflate (only_small_border ? small_border : dialogframe);
+ } else if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE | WindowExStyles.WS_EX_CLIENTEDGE)) {
+ border_size.Inflate (border + (only_small_border ? Size.Empty : clientedge));
+ } else {
+ if (cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE)) {
+ border_size.Inflate (clientedge);
+ }
+ if (cp.IsSet (WindowExStyles.WS_EX_DLGMODALFRAME) && !cp.IsSet (WindowStyles.WS_DLGFRAME)) {
+ border_size.Inflate (cp.IsSet (WindowStyles.WS_THICKFRAME) ? border : dialogframe);
+ }
+ if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE)) {
+ if (cp.IsSet (WindowStyles.WS_THICKFRAME) || cp.IsSet (WindowStyles.WS_DLGFRAME)) {
+ border_size.Inflate (new Size (-border.Width, -border.Height));
+ } else {
+ border_size.Inflate (border);
+ }
+ }
+ }
+
+ return border_size;
+ }
+
+ public static Rectangle GetWindowRectangle (CreateParams cp, Menu menu)
+ {
+ return GetWindowRectangle (cp, menu, Rectangle.Empty);
+ }
+
+ public static Rectangle GetWindowRectangle (CreateParams cp, Menu menu, Rectangle client_rect)
+ {
+ Rectangle rect;
+ Borders borders;
+
+ borders = GetBorders (cp, menu);
+
+ rect = new Rectangle (Point.Empty, client_rect.Size);
+ rect.Y -= borders.top;
+ rect.Height += borders.top + borders.bottom;
+ rect.X -= borders.left;
+ rect.Width += borders.left + borders.right;
+
+ #if debug
+ Console.WriteLine ("GetWindowRectangle ({0}, {1}, {2}): {3}", cp, menu != null, client_rect, rect);
+ #endif
+ return rect;
+ }
+
+ public Rectangle GetClientRectangle (int width, int height)
+ {
+ CreateParams cp = new CreateParams ();
+ cp.WindowStyle = initial_style;
+ cp.WindowExStyle = initial_ex_style;
+ return GetClientRectangle (cp, menu, width, height);
+ }
+
+ // This could be greatly optimized by caching the outputs and only updating when something is moved
+ // in the parent planar space. To do that we need to track z-order in the parent space as well
+ public ArrayList GetClippingRectangles ()
+ {
+ ArrayList masks = new ArrayList ();
+
+ if (x < 0) {
+ masks.Add (new Rectangle (0, 0, x*-1, Height));
+ if (y < 0) {
+ masks.Add (new Rectangle (x*-1, 0, Width, y*-1));
+ }
+ } else if (y < 0) {
+ masks.Add (new Rectangle (0, 0, Width, y*-1));
+ }
+
+ foreach (Hwnd child in children) {
+ if (child.visible)
+ masks.Add (new Rectangle (child.X, child.Y, child.Width, child.Height));
+ }
+
+ if (parent == null) {
+ return masks;
+ }
+
+ ArrayList siblings = parent.children;
+
+ foreach (Hwnd sibling in siblings) {
+ IntPtr sibling_handle = whole_window;
+
+ if (sibling == this)
+ continue;
+
+ // This entire method should be cached to find all higher views at the time of query
+ do {
+ sibling_handle = XplatUI.GetPreviousWindow (sibling_handle);
+
+ if (sibling_handle == sibling.WholeWindow && sibling.visible) {
+
+ Rectangle intersect = Rectangle.Intersect (new Rectangle (X, Y, Width, Height), new Rectangle (sibling.X, sibling.Y, sibling.Width, sibling.Height));
+
+ if (intersect == Rectangle.Empty)
+ continue;
+
+ intersect.X -= X;
+ intersect.Y -= Y;
+
+ masks.Add (intersect);
+ }
+ } while (sibling_handle != IntPtr.Zero);
+ }
+
+ return masks;
+ }
+
+ public static Borders GetBorders (CreateParams cp, Menu menu)
+ {
+
+ Borders borders = new Borders ();
+
+ if (menu != null) {
+ int menu_height = menu.Rect.Height;
+ if (menu_height == 0)
+ menu_height = ThemeEngine.Current.CalcMenuBarSize (GraphicsContext, menu, cp.Width);
+ borders.top += menu_height;
+ }
+
+ if (cp.IsSet (WindowStyles.WS_CAPTION)) {
+ int caption_height;
+ if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
+ caption_height = ThemeEngine.Current.ToolWindowCaptionHeight;
+ } else {
+ caption_height = ThemeEngine.Current.CaptionHeight;
+ }
+ borders.top += caption_height;
+ }
+
+ Borders border_width = GetBorderWidth (cp);
+
+ borders.left += border_width.left;
+ borders.right += border_width.right;
+ borders.top += border_width.top;
+ borders.bottom += border_width.bottom;
+
+ return borders;
+ }
+
+ public static Rectangle GetClientRectangle(CreateParams cp, Menu menu, int width, int height) {
+ Rectangle rect;
+ Borders borders;
+
+ borders = GetBorders (cp, menu);
+
+ rect = new Rectangle(0, 0, width, height);
+ rect.Y += borders.top;
+ rect.Height -= borders.top + borders.bottom;
+ rect.X += borders.left;
+ rect.Width -= borders.left + borders.right;
+
+ #if debug
+ Console.WriteLine ("GetClientRectangle ({0}, {1}, {2}, {3}): {4}", cp, menu != null, width, height, rect);
+ #endif
+
+ return rect;
+ }
+
+ public static Graphics GraphicsContext {
+ get {
+ if (bmp_g == null) {
+ bmp = new Bitmap (1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ bmp_g = Graphics.FromImage (bmp);
+ }
+
+ return bmp_g;
+ }
+ }
+ #endregion // Static Methods
+
+ #region Instance Properties
+ public FormBorderStyle BorderStyle {
+ get {
+ return border_style;
+ }
+
+ set {
+ border_style = value;
+ }
+ }
+
+ public Rectangle ClientRect {
+ get {
+ if (client_rectangle == Rectangle.Empty) {
+ return DefaultClientRect;
+ }
+ return client_rectangle;
+ }
+
+ set {
+ client_rectangle = value;
+ }
+ }
+
+ public IntPtr Cursor {
+ get {
+ return cursor;
+ }
+
+ set {
+ cursor = value;
+ }
+ }
+
+ public IntPtr ClientWindow {
+ get {
+ return client_window;
+ }
+
+ set {
+ client_window = value;
+ handle = value;
+
+ zombie = false;
+
+ if (client_window != IntPtr.Zero) {
+ lock (windows) {
+ if (windows[client_window] == null) {
+ windows[client_window] = this;
+ }
+ }
+ }
+ }
+ }
+
+ public Region UserClip {
+ get {
+ return user_clip;
+ }
+
+ set {
+ user_clip = value;
+ }
+ }
+
+ public Rectangle DefaultClientRect {
+ get {
+ // We pass a Zero for the menu handle so the menu size is
+ // not computed this is done via an WM_NCCALC
+ CreateParams cp = new CreateParams ();
+ Rectangle rect;
+
+ cp.WindowStyle = initial_style;
+ cp.WindowExStyle = initial_ex_style;
+
+ rect = GetClientRectangle (cp, null, width, height);
+
+ return rect;
+ }
+ }
+
+ public bool ExposePending {
+ get {
+ return expose_pending;
+ }
+ }
+
+ public IntPtr Handle {
+ get {
+ if (handle == IntPtr.Zero) {
+ throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
+ }
+ return handle;
+ }
+ }
+
+ public int Height {
+ get {
+ return height;
+ }
+
+ set {
+ height = value;
+ }
+ }
+
+ public Menu Menu {
+ get {
+ return menu;
+ }
+
+ set {
+ menu = value;
+ }
+ }
+
+ public bool Reparented {
+ get {
+ return reparented;
+ }
+
+ set {
+ reparented = value;
+ }
+ }
+
+ public uint Opacity {
+ get {
+ return opacity;
+ }
+
+ set {
+ opacity = value;
+ }
+ }
+
+ public XEventQueue Queue {
+ get {
+ return queue;
+ }
+
+ set {
+ queue = value;
+ }
+ }
+
+ public bool Enabled {
+ get {
+ if (!enabled) {
+ return false;
+ }
+
+ if (parent != null) {
+ return parent.Enabled;
+ }
+
+ return true;
+ }
+
+ set {
+ enabled = value;
+ }
+ }
+
+ public IntPtr EnabledHwnd {
+ get {
+ if (Enabled || parent == null) {
+ return Handle;
+ }
+
+ return parent.EnabledHwnd;
+ }
+ }
+
+ public Point MenuOrigin {
+ get {
+ Form frm = Widget.FromHandle (handle) as Form;
+ if (frm != null && frm.window_manager != null)
+ return frm.window_manager.GetMenuOrigin ();
+
+ Point pt;
+ Size border_3D_size = ThemeEngine.Current.Border3DSize;
+
+ pt = new Point(0, 0);
+
+ if (border_style == FormBorderStyle.Fixed3D) {
+ pt.X += border_3D_size.Width;
+ pt.Y += border_3D_size.Height;
+ } else if (border_style == FormBorderStyle.FixedSingle) {
+ pt.X += 1;
+ pt.Y += 1;
+ }
+
+ if (this.title_style == TitleStyle.Normal) {
+ pt.Y += caption_height;
+ } else if (this.title_style == TitleStyle.Normal) {
+ pt.Y += tool_caption_height;
+ }
+
+ return pt;
+ }
+ }
+
+ public Rectangle Invalid {
+ get {
+ if (invalid_list.Count == 0)
+ return Rectangle.Empty;
+
+ Rectangle result = (Rectangle)invalid_list[0];
+ for (int i = 1; i < invalid_list.Count; i ++) {
+ result = Rectangle.Union (result, (Rectangle)invalid_list[i]);
+ }
+ return result;
+ }
+ }
+
+ public Rectangle[] ClipRectangles {
+ get {
+ return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle));
+ }
+ }
+
+ public Rectangle NCInvalid {
+ get { return nc_invalid; }
+ set { nc_invalid = value; }
+
+ }
+
+ public bool NCExposePending {
+ get {
+ return nc_expose_pending;
+ }
+ }
+
+ public Hwnd Parent {
+ get {
+ return parent;
+ }
+
+ set {
+ if (parent != null)
+ parent.children.Remove (this);
+ parent = value;
+ if (parent != null)
+ parent.children.Add (this);
+ }
+ }
+
+ public bool Mapped {
+ get {
+ if (!mapped) {
+ return false;
+ }
+
+ if (parent != null) {
+ return parent.Mapped;
+ }
+
+ return true;
+ }
+
+ set {
+ mapped = value;
+ }
+ }
+
+ public int CaptionHeight {
+ get { return caption_height; }
+ set { caption_height = value; }
+ }
+
+ public int ToolCaptionHeight {
+ get { return tool_caption_height; }
+ set { tool_caption_height = value; }
+ }
+
+ public TitleStyle TitleStyle {
+ get {
+ return title_style;
+ }
+
+ set {
+ title_style = value;
+ }
+ }
+
+ public object UserData {
+ get {
+ return user_data;
+ }
+
+ set {
+ user_data = value;
+ }
+ }
+
+ public IntPtr WholeWindow {
+ get {
+ return whole_window;
+ }
+
+ set {
+ whole_window = value;
+
+ zombie = false;
+
+ if (whole_window != IntPtr.Zero) {
+ lock (windows) {
+ if (windows[whole_window] == null) {
+ windows[whole_window] = this;
+ }
+ }
+ }
+ }
+ }
+
+ public int Width {
+ get {
+ return width;
+ }
+
+ set {
+ width = value;
+ }
+ }
+
+ public bool Visible {
+ get {
+ return visible;
+ }
+
+ set {
+ visible = value;
+ }
+ }
+
+ public int X {
+ get {
+ return x;
+ }
+
+ set {
+ x = value;
+ }
+ }
+
+ public int Y {
+ get {
+ return y;
+ }
+
+ set {
+ y = value;
+ }
+ }
+
+ #endregion // Instance properties
+
+ #region Methods
+ public void AddInvalidArea(int x, int y, int width, int height) {
+ AddInvalidArea(new Rectangle(x, y, width, height));
+ }
+
+ public void AddInvalidArea(Rectangle rect) {
+ ArrayList tmp = new ArrayList ();
+ foreach (Rectangle r in invalid_list) {
+ if (!rect.Contains (r)) {
+ tmp.Add (r);
+ }
+ }
+ tmp.Add (rect);
+ invalid_list = tmp;
+ }
+
+ public void ClearInvalidArea() {
+ invalid_list.Clear();
+ expose_pending = false;
+ }
+
+ public void AddNcInvalidArea(int x, int y, int width, int height) {
+ if (nc_invalid == Rectangle.Empty) {
+ nc_invalid = new Rectangle (x, y, width, height);
+ return;
+ }
+
+ int right, bottom;
+ right = Math.Max (nc_invalid.Right, x + width);
+ bottom = Math.Max (nc_invalid.Bottom, y + height);
+ nc_invalid.X = Math.Min (nc_invalid.X, x);
+ nc_invalid.Y = Math.Min (nc_invalid.Y, y);
+
+ nc_invalid.Width = right - nc_invalid.X;
+ nc_invalid.Height = bottom - nc_invalid.Y;
+ }
+
+ public void AddNcInvalidArea(Rectangle rect) {
+ if (nc_invalid == Rectangle.Empty) {
+ nc_invalid = rect;
+ return;
+ }
+ nc_invalid = Rectangle.Union (nc_invalid, rect);
+ }
+
+ public void ClearNcInvalidArea() {
+ nc_invalid = Rectangle.Empty;
+ nc_expose_pending = false;
+ }
+
+ public override string ToString() {
+ return String.Format("Hwnd, Mapped:{3} ClientWindow:0x{0:X}, WholeWindow:0x{1:X}, Zombie={4}, Parent:[{2:X}]", client_window.ToInt32(), whole_window.ToInt32(), parent != null ? parent.ToString() : "<null>", Mapped, zombie);
+ }
+
+ public static Point GetNextStackedFormLocation (CreateParams cp, Hwnd parent_hwnd)
+ {
+ if (cp.control == null)
+ return Point.Empty;
+
+ int X = cp.X;
+ int Y = cp.Y;
+ Point previous, next;
+ Rectangle within;
+
+ if (parent_hwnd != null) {
+ Widget parent = cp.control.Parent;
+ previous = parent_hwnd.previous_child_startup_location;
+ if (parent_hwnd.client_rectangle == Rectangle.Empty && parent != null) {
+ within = parent.ClientRectangle;
+ } else {
+ within = parent_hwnd.client_rectangle;
+ }
+ } else {
+ previous = Hwnd.previous_main_startup_location;
+ within = ShiftUI.Screen.PrimaryScreen.WorkingArea;
+ }
+
+ if (previous.X == int.MinValue || previous.Y == int.MinValue) {
+ next = Point.Empty;
+ } else {
+ next = new Point (previous.X + 22, previous.Y + 22);
+ }
+
+ if (!within.Contains (next.X * 3, next.Y * 3)) {
+ next = Point.Empty;
+ }
+
+ if (next == Point.Empty && cp.Parent == IntPtr.Zero) {
+ next = new Point (22, 22);
+ }
+
+ if (parent_hwnd != null) {
+ parent_hwnd.previous_child_startup_location = next;
+ } else {
+ Hwnd.previous_main_startup_location = next;
+ }
+
+ if (X == int.MinValue && Y == int.MinValue) {
+ X = next.X;
+ Y = next.Y;
+ }
+
+ return new Point (X, Y);
+ }
+
+ #endregion // Methods
+
+ internal struct Borders
+ {
+ public int top;
+ public int bottom;
+ public int left;
+ public int right;
+
+ public void Inflate (Size size)
+ {
+ left += size.Width;
+ right += size.Width;
+ top += size.Height;
+ bottom += size.Height;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format("{{top={0}, bottom={1}, left={2}, right={3}}}", top, bottom, left, right);
+ }
+
+ public static bool operator == (Borders a, Borders b)
+ {
+ return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom);
+ }
+
+ public static bool operator != (Borders a, Borders b)
+ {
+ return !(a == b);
+ }
+
+ public override bool Equals (object obj)
+ {
+ return base.Equals (obj);
+ }
+
+ public override int GetHashCode ()
+ {
+ return base.GetHashCode ();
+ }
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/IBindableComponent.cs b/source/ShiftUI/Internal/IBindableComponent.cs
new file mode 100644
index 0000000..8c7edaa
--- /dev/null
+++ b/source/ShiftUI/Internal/IBindableComponent.cs
@@ -0,0 +1,34 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+
+
+using System;
+using System.ComponentModel;
+
+namespace ShiftUI {
+
+ public interface IBindableComponent : IComponent, IDisposable
+ {
+ BindingContext BindingContext { get; set; }
+ WidgetBindingsCollection DataBindings { get; }
+ }
+}
diff --git a/source/ShiftUI/Internal/IBounds.cs b/source/ShiftUI/Internal/IBounds.cs
new file mode 100644
index 0000000..923a029
--- /dev/null
+++ b/source/ShiftUI/Internal/IBounds.cs
@@ -0,0 +1,40 @@
+//
+// IBounds.cs
+//
+// 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) 2008 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+
+namespace ShiftUI
+{
+ interface IBounds
+ {
+ Rectangle Bounds { get; }
+ }
+}
diff --git a/source/ShiftUI/Internal/IButtonControl.cs b/source/ShiftUI/Internal/IButtonControl.cs
new file mode 100644
index 0000000..33d9fc8
--- /dev/null
+++ b/source/ShiftUI/Internal/IButtonControl.cs
@@ -0,0 +1,40 @@
+//
+// ShiftUI.IButtonWidget.cs
+//
+// 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.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+//
+//
+
+
+// COMPLETE
+
+namespace ShiftUI
+{
+
+ public interface IButtonWidget
+ {
+ DialogResult DialogResult {get; set;}
+ void NotifyDefault (bool value);
+ void PerformClick ();
+ }
+}
diff --git a/source/ShiftUI/Internal/ICommandExecutor.cs b/source/ShiftUI/Internal/ICommandExecutor.cs
new file mode 100644
index 0000000..dfe1573
--- /dev/null
+++ b/source/ShiftUI/Internal/ICommandExecutor.cs
@@ -0,0 +1,34 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+
+// COMPLETE
+
+namespace ShiftUI {
+ public interface ICommandExecutor {
+ #region Public Instance Methods
+ void Execute();
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/IComponentEditorPageSite.cs b/source/ShiftUI/Internal/IComponentEditorPageSite.cs
new file mode 100644
index 0000000..fd9eaa9
--- /dev/null
+++ b/source/ShiftUI/Internal/IComponentEditorPageSite.cs
@@ -0,0 +1,34 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok ([email protected]);
+//
+
+// COMPLETE
+
+namespace ShiftUI {
+
+ public interface IComponentEditorPageSite {
+ Widget GetWidget();
+ void SetDirty();
+ }
+}
diff --git a/source/ShiftUI/Internal/IContainerControl.cs b/source/ShiftUI/Internal/IContainerControl.cs
new file mode 100644
index 0000000..da5cc19
--- /dev/null
+++ b/source/ShiftUI/Internal/IContainerControl.cs
@@ -0,0 +1,39 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+
+// COMPLETE
+
+namespace ShiftUI {
+ public interface IContainerWidget {
+ #region Public Instance Properties
+ Widget ActiveWidget {get; set;}
+ #endregion // Public Instance Properties
+
+ #region Public Instance Methods
+ bool ActivateWidget(Widget active);
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ICurrencyManagerProvider.cs b/source/ShiftUI/Internal/ICurrencyManagerProvider.cs
new file mode 100644
index 0000000..a3993cc
--- /dev/null
+++ b/source/ShiftUI/Internal/ICurrencyManagerProvider.cs
@@ -0,0 +1,32 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+
+
+namespace ShiftUI {
+
+ public interface ICurrencyManagerProvider {
+ CurrencyManager CurrencyManager { get; }
+
+ CurrencyManager GetRelatedCurrencyManager (string dataMember);
+ }
+
+}
diff --git a/source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs b/source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs
new file mode 100644
index 0000000..f55a6c6
--- /dev/null
+++ b/source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs
@@ -0,0 +1,35 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+namespace ShiftUI {
+ public interface IDataGridColumnStyleEditingNotificationService {
+ #region Public Instance Methods
+ void ColumnStartedEditing(Widget editingWidget);
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/IDataGridEditingService.cs b/source/ShiftUI/Internal/IDataGridEditingService.cs
new file mode 100644
index 0000000..41f9c9a
--- /dev/null
+++ b/source/ShiftUI/Internal/IDataGridEditingService.cs
@@ -0,0 +1,36 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+//
+// Peter Bartok [email protected]
+//
+
+// COMPLETE
+
+namespace ShiftUI {
+ public interface IDataGridEditingService {
+ #region Public Instance Methods
+ bool BeginEdit(DataGridColumnStyle gridColumn, int rowNumber);
+ bool EndEdit(DataGridColumnStyle gridColumn, int rowNumber, bool shouldAbort);
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/IDataGridViewEditingCell.cs b/source/ShiftUI/Internal/IDataGridViewEditingCell.cs
new file mode 100644
index 0000000..30fc6e4
--- /dev/null
+++ b/source/ShiftUI/Internal/IDataGridViewEditingCell.cs
@@ -0,0 +1,41 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Author:
+// Pedro Martínez Juliá <[email protected]>
+//
+
+
+namespace ShiftUI {
+
+ public interface IDataGridViewEditingCell {
+
+ object EditingCellFormattedValue { get; set; }
+
+ bool EditingCellValueChanged { get; set; }
+
+ object GetEditingCellFormattedValue (DataGridViewDataErrorContexts context);
+
+ void PrepareEditingCellForEdit (bool selectAll);
+
+ }
+
+}
diff --git a/source/ShiftUI/Internal/IDataGridViewEditingControl.cs b/source/ShiftUI/Internal/IDataGridViewEditingControl.cs
new file mode 100644
index 0000000..8b102d0
--- /dev/null
+++ b/source/ShiftUI/Internal/IDataGridViewEditingControl.cs
@@ -0,0 +1,53 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Author:
+// Pedro Martínez Juliá <[email protected]>
+//
+
+
+namespace ShiftUI {
+
+ public interface IDataGridViewEditingWidget {
+
+ DataGridView EditingWidgetDataGridView {get; set;}
+
+ object EditingWidgetFormattedValue {get; set;}
+
+ int EditingWidgetRowIndex {get; set;}
+
+ bool EditingWidgetValueChanged {get; set;}
+
+ Cursor EditingPanelCursor {get;}
+
+ bool RepositionEditingWidgetOnValueChange {get;}
+
+ void ApplyCellStyleToEditingWidget (DataGridViewCellStyle dataGridViewCellStyle);
+
+ bool EditingWidgetWantsInputKey (Keys keyData, bool dataGridViewWantsInputKey);
+
+ object GetEditingWidgetFormattedValue (DataGridViewDataErrorContexts context);
+
+ void PrepareEditingWidgetForEdit (bool selectAll);
+
+ }
+
+}
diff --git a/source/ShiftUI/Internal/IDataObject.cs b/source/ShiftUI/Internal/IDataObject.cs
new file mode 100644
index 0000000..7ce0d80
--- /dev/null
+++ b/source/ShiftUI/Internal/IDataObject.cs
@@ -0,0 +1,54 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+
+// COMPLETE
+
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI {
+ [ComVisible(true)]
+ public interface IDataObject {
+ #region Public Instance Methods
+ object GetData(string format);
+ object GetData(string format, bool autoConvert);
+ object GetData(Type format);
+
+ bool GetDataPresent(string format);
+ bool GetDataPresent(string format, bool autoConvert);
+ bool GetDataPresent(Type format);
+
+ string[] GetFormats();
+ string[] GetFormats(bool autoConvert);
+
+ void SetData(object data);
+ void SetData(string format, bool autoConvert, object data);
+ void SetData(string format, object data);
+ void SetData(Type format, object data);
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/IDropTarget.cs b/source/ShiftUI/Internal/IDropTarget.cs
new file mode 100644
index 0000000..2589634
--- /dev/null
+++ b/source/ShiftUI/Internal/IDropTarget.cs
@@ -0,0 +1,36 @@
+// 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) 2006 Novell, Inc.
+//
+
+using System;
+using System.Drawing;
+using System.ComponentModel;
+
+namespace ShiftUI {
+
+ public interface IDropTarget {
+ void OnDragDrop (DragEventArgs e);
+ void OnDragEnter (DragEventArgs e);
+ void OnDragLeave (EventArgs e);
+ void OnDragOver (DragEventArgs e);
+ }
+
+}
diff --git a/source/ShiftUI/Internal/IEventHandler.cs b/source/ShiftUI/Internal/IEventHandler.cs
new file mode 100644
index 0000000..e46175e
--- /dev/null
+++ b/source/ShiftUI/Internal/IEventHandler.cs
@@ -0,0 +1,33 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+
+namespace ShiftUI.CarbonInternal {
+ internal interface IEventHandler {
+ bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg);
+ }
+}
diff --git a/source/ShiftUI/Internal/IFeatureSupport.cs b/source/ShiftUI/Internal/IFeatureSupport.cs
new file mode 100644
index 0000000..748b510
--- /dev/null
+++ b/source/ShiftUI/Internal/IFeatureSupport.cs
@@ -0,0 +1,38 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+using System;
+
+namespace ShiftUI {
+ public interface IFeatureSupport {
+ #region Public Instance Methods
+ Version GetVersionPresent(object feature);
+ bool IsPresent(object feature);
+ bool IsPresent(object feature, Version minimumVersion);
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/IFileReaderService.cs b/source/ShiftUI/Internal/IFileReaderService.cs
new file mode 100644
index 0000000..abee90e
--- /dev/null
+++ b/source/ShiftUI/Internal/IFileReaderService.cs
@@ -0,0 +1,37 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System.IO;
+
+namespace ShiftUI {
+ public interface IFileReaderService {
+ #region Public Instance Methods
+ Stream OpenFileFromSource(string relativePath);
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/IKeyFilter.cs b/source/ShiftUI/Internal/IKeyFilter.cs
new file mode 100644
index 0000000..ecc2396
--- /dev/null
+++ b/source/ShiftUI/Internal/IKeyFilter.cs
@@ -0,0 +1,32 @@
+// 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) 2008 Novell, Inc.
+//
+// Authors:
+// Mike Gorse [email protected]
+//
+//
+
+
+namespace ShiftUI {
+ internal interface IKeyFilter {
+ bool PreFilterKey(KeyFilterData data);
+ }
+}
diff --git a/source/ShiftUI/Internal/IMessageFilter.cs b/source/ShiftUI/Internal/IMessageFilter.cs
new file mode 100644
index 0000000..d55394f
--- /dev/null
+++ b/source/ShiftUI/Internal/IMessageFilter.cs
@@ -0,0 +1,34 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+
+// COMPLETE
+
+namespace ShiftUI {
+ public interface IMessageFilter {
+ bool PreFilterMessage(ref Message m);
+ }
+}
diff --git a/source/ShiftUI/Internal/IToolStripData.cs b/source/ShiftUI/Internal/IToolStripData.cs
new file mode 100644
index 0000000..c01afd3
--- /dev/null
+++ b/source/ShiftUI/Internal/IToolStripData.cs
@@ -0,0 +1,41 @@
+//
+// IToolStripData.cs
+//
+// 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) 2008 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+
+namespace ShiftUI
+{
+ interface IToolStripData
+ {
+ bool IsCurrentlyDragging { get; }
+ bool Stretch { get; set; }
+ }
+}
diff --git a/source/ShiftUI/Internal/IWin32Window.cs b/source/ShiftUI/Internal/IWin32Window.cs
new file mode 100644
index 0000000..73bfc31
--- /dev/null
+++ b/source/ShiftUI/Internal/IWin32Window.cs
@@ -0,0 +1,44 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+
+// COMPLETE
+
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI {
+ [ComVisible(true)]
+ [Guid("458AB8A2-A1EA-4d7b-8EBE-DEE5D3D9442C")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IWin32Window {
+ #region Public Instance Properties
+ IntPtr Handle {
+ get;
+ }
+ #endregion // Public Instance Properties
+ }
+}
diff --git a/source/ShiftUI/Internal/IWindowTarget.cs b/source/ShiftUI/Internal/IWindowTarget.cs
new file mode 100644
index 0000000..0157773
--- /dev/null
+++ b/source/ShiftUI/Internal/IWindowTarget.cs
@@ -0,0 +1,34 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+using System;
+
+namespace ShiftUI {
+ public interface IWindowTarget {
+ #region Public Instance Methods
+ void OnHandleChange(IntPtr newHandle);
+ void OnMessage(ref Message m);
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ImageIndexConverter.cs b/source/ShiftUI/Internal/ImageIndexConverter.cs
new file mode 100644
index 0000000..b2783e9
--- /dev/null
+++ b/source/ShiftUI/Internal/ImageIndexConverter.cs
@@ -0,0 +1,102 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Ravindra [email protected]
+//
+
+
+// COMPLETE
+
+using System;
+using System.Drawing;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI
+{
+ public class ImageIndexConverter : Int32Converter
+ {
+ #region Constructors
+
+ public ImageIndexConverter () { }
+
+ #endregion Constructors
+
+ #region Protected Properties
+
+ protected virtual bool IncludeNoneAsStandardValue {
+ get { return true; }
+ }
+
+ #endregion Protected Properties
+
+ #region Public Methods
+
+ public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ string indexStr;
+ if (value != null && value is string) {
+ indexStr = (string) value;
+ if (indexStr == "(none)")
+ return -1;
+ else
+ return Int32.Parse (indexStr);
+ }
+ else
+ return base.ConvertFrom (context, culture, value);
+ }
+
+ public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture,
+ object value, Type destinationType)
+ {
+ if (value != null && destinationType == typeof (string)) {
+ if (value is int && (int) value == -1)
+ return "(none)";
+ else
+ return value.ToString ();
+ }
+ else
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context)
+ {
+ int [] stdVal = new int [] {-1};
+ return new TypeConverter.StandardValuesCollection (stdVal);
+ }
+
+ public override bool GetStandardValuesExclusive (ITypeDescriptorContext context)
+ {
+ return false;
+ }
+
+ public override bool GetStandardValuesSupported (ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ #endregion Public Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ImageKeyConverter.cs b/source/ShiftUI/Internal/ImageKeyConverter.cs
new file mode 100644
index 0000000..e70b5e1
--- /dev/null
+++ b/source/ShiftUI/Internal/ImageKeyConverter.cs
@@ -0,0 +1,97 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst [email protected]
+//
+
+using System.Drawing;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI
+{
+ public class ImageKeyConverter : StringConverter
+ {
+ #region Constructors
+ public ImageKeyConverter () { }
+ #endregion Constructors
+
+ #region Protected Properties
+ protected virtual bool IncludeNoneAsStandardValue {
+ get { return true; }
+ }
+ #endregion Protected Properties
+
+ #region Public Methods
+ public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof (string))
+ return true;
+
+ return false;
+ }
+
+ public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value != null && value is string)
+ return (string) value;
+ else
+ return base.ConvertFrom (context, culture, value);
+ }
+
+ public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture,
+ object value, Type destinationType)
+ {
+ if (value == null)
+ return "(none)";
+ else if (destinationType == typeof (string)) {
+ if (value is string && (string) value == string.Empty)
+ return "(none)";
+ else
+ return value.ToString ();
+ }
+ else
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context)
+ {
+ string[] stdVal = new string[] { string.Empty };
+ return new TypeConverter.StandardValuesCollection (stdVal);
+ }
+
+ public override bool GetStandardValuesExclusive (ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override bool GetStandardValuesSupported (ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ #endregion Public Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ImageList.cs b/source/ShiftUI/Internal/ImageList.cs
new file mode 100644
index 0000000..b983455
--- /dev/null
+++ b/source/ShiftUI/Internal/ImageList.cs
@@ -0,0 +1,1073 @@
+//
+// ShiftUI.ImageList.cs
+//
+// Authors:
+// Peter Bartok <[email protected]>
+// Kornél Pál <http://www.kornelpal.hu/>
+//
+// Copyright (C) 2004-2005 Novell, Inc.
+// Copyright (C) 2005 Kornél Pál
+//
+
+//
+// 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.
+//
+
+// COMPLETE
+
+//
+// Differences between MS.NET ImageList and this implementation:
+//
+// This is a fully managed image list implementation.
+//
+// Images are stored as Format32bppArgb internally but ColorDepth is applied
+// to the colors of images. Images[index] returns a Format32bppArgb copy of
+// the image so this difference is only internal.
+//
+// MS.NET has no alpha channel support (except for icons in 32-bit mode with
+// comctl32.dll version 6.0) but this implementation has full alpha channel
+// support in 32-bit mode.
+//
+// Handle should be an HIMAGELIST returned by ImageList_Create. This
+// implementation uses (IntPtr)(-1) that is a non-zero but invalid handle.
+//
+// MS.NET destroys handles using the garbage collector this implementation
+// does the same with Image objects stored in an ArrayList.
+//
+// MS.NET 1.x shares the same HIMAGELIST between ImageLists that were
+// initialized from the same ImageListStreamer and doesn't update ImageSize
+// and ColorDepth that are treated as bugs and MS.NET 2.0 behavior is
+// implemented.
+//
+// MS.NET 2.0 does not clear keys when handle is destroyed that is treated as
+// a bug.
+//
+
+using System.Collections;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.ComponentModel.Design.Serialization;
+using System.Drawing;
+using System.Drawing.Design;
+using System.Drawing.Imaging;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI
+{
+ [DefaultProperty("Images")]
+ //[Designer("ShiftUI.Design.ImageListDesigner, " + Consts.AssemblySystem_Design)]
+ //[DesignerSerializer("ShiftUI.Design.ImageListCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
+ [ToolboxItemFilter("ShiftUI")]
+ [TypeConverter(typeof(ImageListConverter))]
+ public sealed class ImageList : System.ComponentModel.Component
+ {
+ #region Private Fields
+ private const ColorDepth DefaultColorDepth = ColorDepth.Depth8Bit;
+ private static readonly Size DefaultImageSize = new Size(16, 16);
+ private static readonly Color DefaultTransparentColor = Color.Transparent;
+ private object tag;
+ private readonly ImageCollection images;
+ #endregion // Private Fields
+
+ #region Sub-classes
+ //[Editor("ShiftUI.Design.ImageCollectionEditor, " + Consts.AssemblySystem_Design, typeof(UITypeEditor))]
+ public sealed class ImageCollection : IList, ICollection, IEnumerable
+ {
+ private const int AlphaMask = unchecked((int)0xFF000000);
+
+ private static class IndexedColorDepths
+ {
+ internal static readonly ColorPalette Palette4Bit;
+ internal static readonly ColorPalette Palette8Bit;
+ private static readonly int[] squares;
+
+ static IndexedColorDepths()
+ {
+ Bitmap bitmap;
+ int index;
+
+ bitmap = new Bitmap(1, 1, PixelFormat.Format4bppIndexed);
+ Palette4Bit = bitmap.Palette;
+ bitmap.Dispose();
+
+ bitmap = new Bitmap(1, 1, PixelFormat.Format8bppIndexed);
+ Palette8Bit = bitmap.Palette;
+ bitmap.Dispose();
+
+ squares = new int[511];
+ for (index = 0; index < 256; index++)
+ squares[255 + index] = squares[255 - index] = index * index;
+ }
+
+ internal static int GetNearestColor(Color[] palette, int color)
+ {
+ int index;
+ int count;
+ int red;
+ int green;
+ int blue;
+ int nearestColor;
+ int minDistance;
+ int distance;
+
+ count = palette.Length;
+ for (index = 0; index < count; index++)
+ if (palette[index].ToArgb() == color)
+ return color;
+
+ red = unchecked((int)(unchecked((uint)color) >> 16) & 0xFF);
+ green = unchecked((int)(unchecked((uint)color) >> 8) & 0xFF);
+ blue = color & 0xFF;
+ nearestColor = AlphaMask;
+ minDistance = int.MaxValue;
+
+ for (index = 0; index < count; index++)
+ if ((distance = squares[255 + palette[index].R - red] + squares[255 + palette[index].G - green] + squares[255 + palette[index].B - blue]) < minDistance) {
+ nearestColor = palette[index].ToArgb();
+ minDistance = distance;
+ }
+
+ return nearestColor;
+ }
+ }
+
+ [Flags()]
+ private enum ItemFlags
+ {
+ None = 0,
+ UseTransparentColor = 1,
+ ImageStrip = 2
+ }
+
+ private sealed class ImageListItem
+ {
+ internal readonly object Image;
+ internal readonly ItemFlags Flags;
+ internal readonly Color TransparentColor;
+ internal readonly int ImageCount = 1;
+
+ internal ImageListItem(Icon value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ // Icons are cloned.
+ this.Image = (Icon)value.Clone();
+ }
+
+ internal ImageListItem(Image value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (!(value is Bitmap))
+ throw new ArgumentException("Image must be a Bitmap.");
+
+ // Images are not cloned.
+ this.Image = value;
+ }
+
+ internal ImageListItem(Image value, Color transparentColor) : this(value)
+ {
+ this.Flags = ItemFlags.UseTransparentColor;
+ this.TransparentColor = transparentColor;
+ }
+
+ internal ImageListItem(Image value, int imageCount) : this(value)
+ {
+ this.Flags = ItemFlags.ImageStrip;
+ this.ImageCount = imageCount;
+ }
+ }
+
+ #region ImageCollection Private Fields
+ private ColorDepth colorDepth = DefaultColorDepth;
+ private Size imageSize = DefaultImageSize;
+ private Color transparentColor = DefaultTransparentColor;
+ private ArrayList list = new ArrayList();
+ private ArrayList keys = new ArrayList();
+ private int count;
+ private bool handleCreated;
+ private int lastKeyIndex = -1;
+ private readonly ImageList owner;
+ #endregion // ImageCollection Private Fields
+
+ #region ImageCollection Internal Constructors
+ // For use in ImageList
+ internal ImageCollection(ImageList owner)
+ {
+ this.owner = owner;
+ }
+ #endregion // ImageCollection Internal Constructor
+
+ #region ImageCollection Internal Instance Properties
+ // For use in ImageList
+ internal ColorDepth ColorDepth {
+ get {
+ return this.colorDepth;
+ }
+
+ set {
+ if (!Enum.IsDefined(typeof(ColorDepth), value))
+ throw new InvalidEnumArgumentException("value", (int)value, typeof(ColorDepth));
+
+ if (this.colorDepth != value) {
+ this.colorDepth = value;
+ RecreateHandle();
+ }
+ }
+ }
+
+ // For use in ImageList
+ internal IntPtr Handle {
+ get {
+ CreateHandle();
+ return (IntPtr)(-1);
+ }
+ }
+
+ // For use in ImageList
+ internal bool HandleCreated {
+ get {
+ return this.handleCreated;
+ }
+ }
+
+ // For use in ImageList
+ internal Size ImageSize {
+ get {
+ return this.imageSize;
+ }
+
+ set {
+ if (value.Width < 1 || value.Width > 256 || value.Height < 1 || value.Height > 256)
+ throw new ArgumentException("ImageSize.Width and Height must be between 1 and 256", "value");
+
+ if (this.imageSize != value) {
+ this.imageSize = value;
+ RecreateHandle();
+ }
+ }
+ }
+
+ // For use in ImageList
+ internal ImageListStreamer ImageStream {
+ get {
+ return this.Empty ? null : new ImageListStreamer(this);
+ }
+
+ set {
+ int index;
+ Image[] streamImages;
+
+ if (value == null) {
+ if (this.handleCreated)
+ DestroyHandle();
+ else
+ this.Clear();
+ }
+ // Only deserialized ImageListStreamers are used.
+ else if ((streamImages = value.Images) != null) {
+ this.list = new ArrayList(streamImages.Length);
+ this.count = 0;
+ this.handleCreated = true;
+ this.keys = new ArrayList(streamImages.Length);
+
+ for (index = 0; index < streamImages.Length; index++) {
+ list.Add((Image)streamImages[index].Clone());
+ keys.Add(null);
+ }
+
+ // Invalid ColorDepth values are ignored.
+ if (Enum.IsDefined(typeof(ColorDepth), value.ColorDepth))
+ this.colorDepth = (ColorDepth)value.ColorDepth;
+ this.imageSize = value.ImageSize;
+
+ // Event is raised even when handle was not created yet.
+ owner.OnRecreateHandle();
+ }
+ }
+ }
+
+ // For use in ImageList
+ internal Color TransparentColor {
+ get {
+ return this.transparentColor;
+ }
+
+ set {
+ this.transparentColor = value;
+ }
+ }
+ #endregion // ImageCollection Internal Instance Properties
+
+ #region ImageCollection Public Instance Properties
+ [Browsable(false)]
+ public int Count {
+ get {
+ return this.handleCreated ? list.Count : this.count;
+ }
+ }
+
+ public bool Empty {
+ get {
+ return this.Count == 0;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return false;
+ }
+ }
+
+ [Browsable(false)]
+ //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public Image this[int index] {
+ get {
+ return (Image)GetImage(index).Clone();
+ }
+
+ set {
+ Image image;
+
+ if (index < 0 || index >= this.Count)
+ throw new ArgumentOutOfRangeException("index");
+
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (!(value is Bitmap))
+ throw new ArgumentException("Image must be a Bitmap.");
+
+ image = CreateImage(value, this.transparentColor);
+ CreateHandle();
+ list[index] = image;
+ }
+ }
+
+ public Image this[string key] {
+ get {
+ int index;
+
+ return (index = IndexOfKey(key)) == -1 ? null : this[index];
+ }
+ }
+
+ public StringCollection Keys {
+ get {
+ int index;
+ string key;
+ StringCollection keyCollection;
+
+ // Returns all keys even when there are more keys than
+ // images. Null keys are returned as empty strings.
+
+ keyCollection = new StringCollection();
+ for (index = 0; index < keys.Count; index++)
+ keyCollection.Add(((key = (string)keys[index]) == null || key.Length == 0) ? string.Empty : key);
+
+ return keyCollection;
+ }
+ }
+ #endregion // ImageCollection Public Instance Properties
+
+ #region ImageCollection Private Static Methods
+ private static bool CompareKeys(string key1, string key2)
+ {
+ // Keys are case-insensitive and keys with different length
+ // are not equal even when string.Compare treats them equal.
+
+ if (key1 == null || key2 == null || key1.Length != key2.Length)
+ return false;
+
+ return string.Compare(key1, key2, true, CultureInfo.InvariantCulture) == 0;
+ }
+ #endregion // ImageCollection Private Static Methods
+
+ #region ImageCollection Private Instance Methods
+ private int AddItem(string key, ImageListItem item)
+ {
+ int itemIndex;
+ int index;
+
+ if (this.handleCreated)
+ itemIndex = AddItemInternal(item);
+ else {
+ // Image strips are counted as a single item in the return
+ // value of Add and AddStrip until handle is created.
+
+ itemIndex = list.Add(item);
+ this.count += item.ImageCount;
+ }
+
+ if ((item.Flags & ItemFlags.ImageStrip) == 0)
+ keys.Add(key);
+ else
+ for (index = 0; index < item.ImageCount; index++)
+ keys.Add(null);
+
+ return itemIndex;
+ }
+
+ internal event EventHandler Changed;
+
+ private int AddItemInternal(ImageListItem item)
+ {
+ if (Changed != null)
+ Changed (this, EventArgs.Empty);
+
+ if (item.Image is Icon) {
+ int imageWidth;
+ int imageHeight;
+ Bitmap bitmap;
+ Graphics graphics;
+
+ bitmap = new Bitmap(imageWidth = this.imageSize.Width, imageHeight = this.imageSize.Height, PixelFormat.Format32bppArgb);
+ graphics = Graphics.FromImage(bitmap);
+ graphics.DrawIcon((Icon)item.Image, new Rectangle(0, 0, imageWidth, imageHeight));
+ graphics.Dispose();
+
+ ReduceColorDepth(bitmap);
+ return list.Add(bitmap);
+ }
+ else if ((item.Flags & ItemFlags.ImageStrip) == 0)
+ return list.Add(CreateImage((Image)item.Image, (item.Flags & ItemFlags.UseTransparentColor) == 0 ? this.transparentColor : item.TransparentColor));
+ else {
+ int imageX;
+ int width;
+ int imageWidth;
+ int imageHeight;
+ int index;
+ Image image;
+ Bitmap bitmap;
+ Graphics graphics;
+ Rectangle imageRect;
+ ImageAttributes imageAttributes;
+
+ // When ImageSize was changed after adding image strips
+ // Count will return invalid values based on old ImageSize
+ // but when creating handle either ArgumentException will
+ // be thrown or image strip will be added according to the
+ // new ImageSize. This can result in image count
+ // difference that can result in exceptions in methods
+ // that use Count before creating handle. In addition this
+ // can result in the loss of sync with keys. When doing
+ // the same after handle was created there are no problems
+ // as handle will be recreated after changing ImageSize
+ // that results in the loss of images added previously.
+
+ if ((width = (image = (Image)item.Image).Width) == 0 || (width % (imageWidth = this.imageSize.Width)) != 0)
+ throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value");
+
+ if (image.Height != (imageHeight = this.imageSize.Height))
+ throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value");
+
+ imageRect = new Rectangle(0, 0, imageWidth, imageHeight);
+ if (this.transparentColor.A == 0)
+ imageAttributes = null;
+ else {
+ imageAttributes = new ImageAttributes();
+ imageAttributes.SetColorKey(this.transparentColor, this.transparentColor);
+ }
+
+ index = list.Count;
+ for (imageX = 0; imageX < width; imageX += imageWidth) {
+ bitmap = new Bitmap(imageWidth, imageHeight, PixelFormat.Format32bppArgb);
+ graphics = Graphics.FromImage(bitmap);
+ graphics.DrawImage(image, imageRect, imageX, 0, imageWidth, imageHeight, GraphicsUnit.Pixel, imageAttributes);
+ graphics.Dispose();
+
+ ReduceColorDepth(bitmap);
+ list.Add(bitmap);
+ }
+
+ if (imageAttributes != null)
+ imageAttributes.Dispose();
+
+ return index;
+ }
+ }
+
+ private void CreateHandle()
+ {
+ int index;
+ ArrayList items;
+
+ if (!this.handleCreated) {
+ items = this.list;
+ this.list = new ArrayList(this.count);
+ this.count = 0;
+ this.handleCreated = true;
+
+ for (index = 0; index < items.Count; index++)
+ AddItemInternal((ImageListItem)items[index]);
+ }
+ }
+
+ private Image CreateImage(Image value, Color transparentColor)
+ {
+ int imageWidth;
+ int imageHeight;
+ ImageAttributes imageAttributes;
+
+ if (transparentColor.A == 0)
+ imageAttributes = null;
+ else {
+ imageAttributes = new ImageAttributes();
+ imageAttributes.SetColorKey (transparentColor, transparentColor);
+ }
+
+ var bitmap = new Bitmap (imageWidth = this.imageSize.Width, imageHeight = this.imageSize.Height, PixelFormat.Format32bppArgb);
+ using (var graphics = Graphics.FromImage (bitmap))
+ graphics.DrawImage (value, new Rectangle(0, 0, imageWidth, imageHeight), 0, 0, value.Width, value.Height, GraphicsUnit.Pixel, imageAttributes);
+
+ if (imageAttributes != null)
+ imageAttributes.Dispose ();
+
+ ReduceColorDepth (bitmap);
+ return bitmap;
+ }
+
+ private void RecreateHandle()
+ {
+ if (this.handleCreated) {
+ DestroyHandle();
+ this.handleCreated = true;
+ owner.OnRecreateHandle();
+ }
+ }
+
+ private unsafe void ReduceColorDepth(Bitmap bitmap)
+ {
+ byte* pixelPtr;
+ byte* lineEndPtr;
+ byte* linePtr;
+ int line;
+ int pixel;
+ int height;
+ int widthBytes;
+ int stride;
+ BitmapData bitmapData;
+ Color[] palette;
+
+ if (this.colorDepth < ColorDepth.Depth32Bit) {
+ bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
+ try {
+ linePtr = (byte*)bitmapData.Scan0;
+ height = bitmapData.Height;
+ widthBytes = bitmapData.Width << 2;
+ stride = bitmapData.Stride;
+
+ if (this.colorDepth < ColorDepth.Depth16Bit) {
+ palette = (this.colorDepth < ColorDepth.Depth8Bit ? IndexedColorDepths.Palette4Bit : IndexedColorDepths.Palette8Bit).Entries;
+
+ for (line = 0; line < height; line++) {
+ lineEndPtr = linePtr + widthBytes;
+ for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
+ *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : IndexedColorDepths.GetNearestColor(palette, pixel | AlphaMask);
+ linePtr += stride;
+ }
+ }
+ else if (this.colorDepth < ColorDepth.Depth24Bit) {
+ for (line = 0; line < height; line++) {
+ lineEndPtr = linePtr + widthBytes;
+ for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
+ *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : (pixel & 0x00F8F8F8) | AlphaMask;
+ linePtr += stride;
+ }
+ }
+ else {
+ for (line = 0; line < height; line++) {
+ lineEndPtr = linePtr + widthBytes;
+ for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
+ *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : pixel | AlphaMask;
+ linePtr += stride;
+ }
+ }
+ }
+ finally {
+ bitmap.UnlockBits(bitmapData);
+ }
+ }
+ }
+ #endregion // ImageCollection Private Instance Methods
+
+ #region ImageCollection Internal Instance Methods
+ // For use in ImageList
+ internal void DestroyHandle()
+ {
+ if (this.handleCreated) {
+ this.list = new ArrayList();
+ this.count = 0;
+ this.handleCreated = false;
+ keys = new ArrayList();
+ }
+ }
+
+ // For use in ImageList
+ internal Image GetImage(int index)
+ {
+ if (index < 0 || index >= this.Count)
+ throw new ArgumentOutOfRangeException("index");
+
+ CreateHandle();
+ return (Image)list[index];
+ }
+
+ // For use in ImageListStreamer
+ internal Image[] ToArray()
+ {
+ Image[] images;
+
+ // Handle is created even when the list is empty.
+ CreateHandle();
+ images = new Image[list.Count];
+ list.CopyTo(images);
+ return images;
+ }
+ #endregion // ImageCollection Internal Instance Methods
+
+ #region ImageCollection Public Instance Methods
+ public void Add(Icon value)
+ {
+ Add(null, value);
+ }
+
+ public void Add(Image value)
+ {
+ Add(null, value);
+ }
+
+ public int Add(Image value, Color transparentColor)
+ {
+ return AddItem(null, new ImageListItem(value, transparentColor));
+ }
+
+ public void Add(string key, Icon icon)
+ {
+ // Argument has name icon but exceptions use name value.
+ AddItem(key, new ImageListItem(icon));
+ }
+
+ public void Add(string key, Image image)
+ {
+ // Argument has name image but exceptions use name value.
+ AddItem(key, new ImageListItem(image));
+ }
+
+ public void AddRange(Image[] images)
+ {
+ int index;
+
+ if (images == null)
+ throw new ArgumentNullException("images");
+
+ for (index = 0; index < images.Length; index++)
+ Add(images[index]);
+ }
+
+ public int AddStrip(Image value)
+ {
+ int width;
+ int imageWidth;
+
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if ((width = value.Width) == 0 || (width % (imageWidth = this.imageSize.Width)) != 0)
+ throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value");
+
+ if (value.Height != this.imageSize.Height)
+ throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value");
+
+ return AddItem(null, new ImageListItem(value, width / imageWidth));
+ }
+
+ public void Clear()
+ {
+ list.Clear();
+ if (!this.handleCreated)
+ this.count = 0;
+ keys.Clear();
+ }
+
+ //[EditorBrowsable(EditorBrowsableState.Never)]
+ public bool Contains(Image image)
+ {
+ throw new NotSupportedException();
+ }
+
+ public bool ContainsKey(string key)
+ {
+ return IndexOfKey(key) != -1;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ Image[] images = new Image[this.Count];
+ int index;
+
+ if (images.Length != 0) {
+ // Handle is created only when there are images.
+ CreateHandle();
+
+ for (index = 0; index < images.Length; index++)
+ images[index] = (Image)((Image)list[index]).Clone();
+ }
+
+ return images.GetEnumerator();
+ }
+
+ //[EditorBrowsable(EditorBrowsableState.Never)]
+ public int IndexOf(Image image)
+ {
+ throw new NotSupportedException();
+ }
+
+ public int IndexOfKey(string key)
+ {
+ int index;
+
+ if (key != null && key.Length != 0) {
+ // When last IndexOfKey was successful and the same key was
+ // assigned to an image with a lower index than the last
+ // result and the key of the last result equals to key
+ // argument the last result is returned.
+
+ if (this.lastKeyIndex >= 0 && this.lastKeyIndex < this.Count && CompareKeys((string)keys[this.lastKeyIndex], key))
+ return this.lastKeyIndex;
+
+ // Duplicate keys are allowed and first match is returned.
+ for (index = 0; index < this.Count; index++)
+ if (CompareKeys((string)keys[index], key))
+ return this.lastKeyIndex = index;
+ }
+
+ return this.lastKeyIndex = -1;
+ }
+
+ //[EditorBrowsable(EditorBrowsableState.Never)]
+ public void Remove(Image image)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void RemoveAt(int index)
+ {
+ if (index < 0 || index >= this.Count)
+ throw new ArgumentOutOfRangeException("index");
+
+ CreateHandle();
+ list.RemoveAt(index);
+ keys.RemoveAt(index);
+ if (Changed != null)
+ Changed (this, EventArgs.Empty);
+ }
+
+ public void RemoveByKey(string key)
+ {
+ int index;
+
+ if ((index = IndexOfKey(key)) != -1)
+ RemoveAt(index);
+ }
+
+ public void SetKeyName(int index, string name)
+ {
+ // Only SetKeyName throws IndexOutOfRangeException.
+ if (index < 0 || index >= this.Count)
+ throw new IndexOutOfRangeException();
+
+ keys[index] = name;
+ }
+ #endregion // ImageCollection Public Instance Methods
+
+ #region ImageCollection Interface Properties
+ object IList.this[int index] {
+ get {
+ return this[index];
+ }
+
+ set {
+ if (!(value is Image))
+ throw new ArgumentException("value");
+
+ this[index] = (Image)value;
+ }
+ }
+
+ bool IList.IsFixedSize {
+ get {
+ return false;
+ }
+ }
+
+ bool ICollection.IsSynchronized {
+ get {
+ return false;
+ }
+ }
+
+ object ICollection.SyncRoot {
+ get {
+ return this;
+ }
+ }
+ #endregion // ImageCollection Interface Properties
+
+ #region ImageCollection Interface Methods
+ int IList.Add(object value)
+ {
+ int index;
+
+ if (!(value is Image))
+ throw new ArgumentException("value");
+
+ index = this.Count;
+ this.Add((Image)value);
+ return index;
+ }
+
+ bool IList.Contains(object image)
+ {
+ return image is Image ? this.Contains ((Image) image) : false;
+ }
+
+ int IList.IndexOf (object image)
+ {
+ return image is Image ? this.IndexOf ((Image) image) : -1;
+ }
+
+ void IList.Insert(int index, object value)
+ {
+ throw new NotSupportedException();
+ }
+
+ void IList.Remove (object image)
+ {
+ if (image is Image)
+ this.Remove ((Image) image);
+ }
+
+ void ICollection.CopyTo(Array dest, int index)
+ {
+ for (int imageIndex = 0; imageIndex < this.Count; imageIndex++)
+ dest.SetValue (this[imageIndex], index++);
+ }
+ #endregion // ImageCollection Interface Methods
+ }
+ #endregion // Sub-classes
+
+ #region Public Constructors
+ public ImageList()
+ {
+ images = new ImageCollection(this);
+ }
+
+ public ImageList(System.ComponentModel.IContainer container) : this()
+ {
+ container.Add(this);
+ }
+ #endregion // Public Constructors
+
+ #region Private Instance Methods
+ private void OnRecreateHandle()
+ {
+ EventHandler eh = (EventHandler)(Events [RecreateHandleEvent]);
+ if (eh != null)
+ eh (this, EventArgs.Empty);
+ }
+
+ // MS's TypeDescriptor stuff apparently uses
+ // non-public ShouldSerialize* methods, because it
+ // picks up this behavior even though the methods
+ // aren't public. we can't make them private, though,
+ // without adding compiler warnings. so, make then
+ // internal instead.
+
+ internal bool ShouldSerializeTransparentColor ()
+ {
+ return this.TransparentColor != Color.LightGray;
+ }
+
+ internal bool ShouldSerializeColorDepth()
+ {
+ // ColorDepth is serialized in ImageStream when non-empty.
+ // It is serialized even if it has its default value when empty.
+ return images.Empty;
+ }
+
+ internal bool ShouldSerializeImageSize()
+ {
+ // ImageSize is serialized in ImageStream when non-empty.
+ // It is serialized even if it has its default value when empty.
+ return images.Empty;
+ }
+
+ internal void ResetColorDepth ()
+ {
+ this.ColorDepth = DefaultColorDepth;
+ }
+
+ internal void ResetImageSize ()
+ {
+ this.ImageSize = DefaultImageSize;
+ }
+
+ internal void ResetTransparentColor ()
+ {
+ this.TransparentColor = Color.LightGray;
+ }
+ #endregion // Private Instance Methods
+
+ #region Public Instance Properties
+ public ColorDepth ColorDepth {
+ get {
+ return images.ColorDepth;
+ }
+
+ set {
+ images.ColorDepth = value;
+ }
+ }
+
+ [Browsable(false)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public IntPtr Handle {
+ get {
+ return images.Handle;
+ }
+ }
+
+ [Browsable(false)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public bool HandleCreated {
+ get {
+ return images.HandleCreated;
+ }
+ }
+
+ [DefaultValue(null)]
+ [MergableProperty(false)]
+ //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public ImageCollection Images {
+ get {
+ return this.images;
+ }
+ }
+
+ [Localizable(true)]
+ public Size ImageSize {
+ get {
+ return images.ImageSize;
+ }
+
+ set {
+ images.ImageSize = value;
+ }
+ }
+
+ [Browsable(false)]
+ [DefaultValue(null)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ public ImageListStreamer ImageStream {
+ get {
+ return images.ImageStream;
+ }
+
+ set {
+ images.ImageStream = value;
+ }
+ }
+
+ [Bindable(true)]
+ [DefaultValue(null)]
+ [Localizable(false)]
+ [TypeConverter(typeof(StringConverter))]
+ public object Tag {
+ get {
+ return this.tag;
+ }
+
+ set {
+ this.tag = value;
+ }
+ }
+
+ public Color TransparentColor {
+ get {
+ return images.TransparentColor;
+ }
+
+ set {
+ images.TransparentColor = value;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Instance Methods
+ public void Draw(Graphics g, Point pt, int index)
+ {
+ this.Draw(g, pt.X, pt.Y, index);
+ }
+
+ public void Draw(Graphics g, int x, int y, int index)
+ {
+ g.DrawImage(images.GetImage(index), x, y);
+ }
+
+ public void Draw(Graphics g, int x, int y, int width, int height, int index)
+ {
+ g.DrawImage(images.GetImage(index), x, y, width, height);
+ }
+
+ public override string ToString()
+ {
+ return base.ToString() + " Images.Count: " + images.Count.ToString() + ", ImageSize: " + this.ImageSize.ToString();
+ }
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ images.DestroyHandle();
+
+ base.Dispose(disposing);
+ }
+ #endregion // Protected Instance Methods
+
+ #region Events
+ static object RecreateHandleEvent = new object ();
+
+ [Browsable(false)]
+ //[EditorBrowsable(EditorBrowsableState.Advanced)]
+ public event EventHandler RecreateHandle {
+ add { Events.AddHandler (RecreateHandleEvent, value); }
+ remove { Events.RemoveHandler (RecreateHandleEvent, value); }
+ }
+ #endregion // Events
+ }
+}
diff --git a/source/ShiftUI/Internal/ImageListConverter.cs b/source/ShiftUI/Internal/ImageListConverter.cs
new file mode 100644
index 0000000..8074d03
--- /dev/null
+++ b/source/ShiftUI/Internal/ImageListConverter.cs
@@ -0,0 +1,44 @@
+// 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) 2005 Novell, Inc.
+//
+// Authors:
+// Matthias Felgner [email protected]
+//
+
+// COMPLETE
+
+using System.ComponentModel;
+
+
+namespace ShiftUI {
+ internal class ImageListConverter : ComponentConverter {
+ #region Constructors
+ public ImageListConverter() : base(typeof(ImageList)) {
+ }
+ #endregion Constructors
+
+ #region Public Methods
+ public override bool GetPropertiesSupported(ITypeDescriptorContext context){
+ return true;
+ }
+ #endregion Public Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ImageListStreamer.cs b/source/ShiftUI/Internal/ImageListStreamer.cs
new file mode 100644
index 0000000..3186747
--- /dev/null
+++ b/source/ShiftUI/Internal/ImageListStreamer.cs
@@ -0,0 +1,338 @@
+// 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) 2002-2006 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+// Gonzalo Paniagua Javier ([email protected])
+//
+// Based on work done by:
+// Dennis Hayes ([email protected])
+// Aleksey Ryabchuk ([email protected])
+
+using System.IO;
+using System.Drawing;
+using System.Collections;
+using System.Drawing.Imaging;
+using System.Runtime.Serialization;
+using System.Runtime.InteropServices;
+using System;
+
+
+namespace ShiftUI {
+ [Serializable]
+ public sealed class ImageListStreamer : ISerializable {
+ readonly ImageList.ImageCollection imageCollection;
+ Image [] images;
+ Size image_size;
+ Color back_color;
+
+ internal ImageListStreamer (ImageList.ImageCollection imageCollection)
+ {
+ this.imageCollection = imageCollection;
+ }
+
+ private ImageListStreamer (SerializationInfo info, StreamingContext context)
+ {
+ byte [] data = (byte []) info.GetValue ("Data", typeof (byte []));
+ if (data == null || data.Length <= 4) { // 4 is the signature
+ return;
+ }
+
+ // check the signature ( 'MSFt' )
+ if (data [0] != 77 || data [1] != 83 || data [2] != 70 || data [3] != 116) {
+ return;
+ }
+
+ MemoryStream decoded = GetDecodedStream (data, 4, data.Length - 4);
+ decoded.Position = 4; // jumps over 'magic' and 'version', which are 16-bits each
+
+ BinaryReader reader = new BinaryReader (decoded);
+ ushort nimages = reader.ReadUInt16 ();
+ reader.ReadUInt16 (); // cMaxImage
+ ushort grow = reader.ReadUInt16 (); // cGrow
+ ushort cx = reader.ReadUInt16 ();
+ ushort cy = reader.ReadUInt16 ();
+ uint bkcolor = reader.ReadUInt32 ();
+ back_color = Color.FromArgb ((int) bkcolor);
+ reader.ReadUInt16 (); // flags
+
+ short [] ovls = new short [4];
+ for (int i = 0; i < 4; i++) {
+ ovls[i] = reader.ReadInt16 ();
+ }
+
+ byte [] decoded_buffer = decoded.GetBuffer ();
+ int bmp_offset = 28;
+ // FileSize field from the bitmap file header
+ int filesize = decoded_buffer [bmp_offset + 2] + (decoded_buffer [bmp_offset + 3] << 8) +
+ (decoded_buffer [bmp_offset + 4] << 16) + (decoded_buffer [bmp_offset + 5] << 24);
+ // ImageSize field from the info header (can be 0)
+ int imagesize = decoded_buffer [bmp_offset + 34] + (decoded_buffer [bmp_offset + 35] << 8) +
+ (decoded_buffer [bmp_offset + 36] << 16) + (decoded_buffer [bmp_offset + 37] << 24);
+
+ int bmp_length = imagesize + filesize;
+ MemoryStream bmpms = new MemoryStream (decoded_buffer, bmp_offset, bmp_length);
+ Bitmap bmp = null;
+ Bitmap mask = null;
+ bmp = new Bitmap (bmpms);
+ MemoryStream mask_stream = new MemoryStream (decoded_buffer,
+ bmp_offset + bmp_length,
+ (int) (decoded.Length - bmp_offset - bmp_length));
+
+ if (mask_stream.Length > 0)
+ mask = new Bitmap (mask_stream);
+
+ if (bkcolor == 0xFFFFFFFF)
+ back_color = bmp.GetPixel (0, 0);
+
+ if (mask != null) {
+ int width = bmp.Width;
+ int height = bmp.Height;
+ Bitmap newbmp = new Bitmap (bmp);
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ Color mcolor = mask.GetPixel (x, y);
+ if (mcolor.B != 0) {
+ newbmp.SetPixel (x, y, Color.Transparent);
+ }
+ }
+ }
+ bmp.Dispose ();
+ bmp = newbmp;
+ mask.Dispose ();
+ mask = null;
+ }
+ images = new Image [nimages];
+ image_size = new Size (cx, cy);
+ Rectangle dest_rect = new Rectangle (0, 0, cx, cy);
+ if (grow * bmp.Width > cx) // Some images store a wrong 'grow' factor
+ grow = (ushort) (bmp.Width / cx);
+
+ for (int r = 0 ; r < nimages ; r++) {
+ int col = r % grow;
+ int row = r / grow;
+ Rectangle area = new Rectangle (col * cx, row * cy, cx, cy);
+ Bitmap b = new Bitmap (cx, cy);
+ using (Graphics g = Graphics.FromImage (b)) {
+ g.DrawImage (bmp, dest_rect, area, GraphicsUnit.Pixel);
+ }
+
+ images [r] = b;
+ }
+ bmp.Dispose ();
+ }
+
+ /*
+ static void WriteToFile (MemoryStream st)
+ {
+ st.Position = 0;
+ FileStream fs = File.OpenWrite (Path.GetTempFileName ());
+ Console.WriteLine ("Writing to {0}", fs.Name);
+ st.WriteTo (fs);
+ fs.Close ();
+ }
+ */
+
+ static byte [] header = new byte []{ 77, 83, 70, 116, 73, 76, 1, 1 };
+ public void GetObjectData (SerializationInfo si, StreamingContext context)
+ {
+ MemoryStream stream = new MemoryStream ();
+ BinaryWriter writer = new BinaryWriter (stream);
+ writer.Write (header);
+
+ Image [] images = (imageCollection != null) ? imageCollection.ToArray () : this.images;
+ int cols = 4;
+ int rows = images.Length / cols;
+ if (images.Length % cols > 0)
+ ++rows;
+
+ writer.Write ((ushort) images.Length);
+ writer.Write ((ushort) images.Length);
+ writer.Write ((ushort) 0x4);
+ writer.Write ((ushort) (images [0].Width));
+ writer.Write ((ushort) (images [0].Height));
+ writer.Write (0xFFFFFFFF); //BackColor.ToArgb ()); //FIXME: should set the right one here.
+ writer.Write ((ushort) 0x21);
+ for (int i = 0; i < 4; i++)
+ writer.Write ((short) -1);
+
+ Bitmap main = new Bitmap (cols * ImageSize.Width, rows * ImageSize.Height);
+ using (Graphics g = Graphics.FromImage (main)) {
+ g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), 0, 0,
+ main.Width, main.Height);
+ for (int i = 0; i < images.Length; i++) {
+ g.DrawImage (images [i], (i % cols) * ImageSize.Width,
+ (i / cols) * ImageSize.Height);
+ }
+ }
+
+ MemoryStream tmp = new MemoryStream ();
+ main.Save (tmp, ImageFormat.Bmp);
+ tmp.WriteTo (stream);
+
+ Bitmap mask = Get1bppMask (main);
+ main.Dispose ();
+ main = null;
+
+ tmp = new MemoryStream ();
+ mask.Save (tmp, ImageFormat.Bmp);
+ tmp.WriteTo (stream);
+ mask.Dispose ();
+
+ stream = GetRLEStream (stream, 4);
+ si.AddValue ("Data", stream.ToArray (), typeof (byte []));
+ }
+
+ unsafe Bitmap Get1bppMask (Bitmap main)
+ {
+ Rectangle rect = new Rectangle (0, 0, main.Width, main.Height);
+ Bitmap result = new Bitmap (main.Width, main.Height, PixelFormat.Format1bppIndexed);
+ BitmapData dresult = result.LockBits (rect, ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
+
+ int w = images [0].Width;
+ int h = images [0].Height;
+ byte *scan = (byte *) dresult.Scan0.ToPointer ();
+ int stride = dresult.Stride;
+ Bitmap current = null;
+ for (int idx = 0; idx < images.Length; idx++) {
+ current = (Bitmap) images [idx];
+ // Hack for newly added images.
+ // Probably has to be done somewhere else.
+ Color c1 = current.GetPixel (0, 0);
+ if (c1.A != 0 && c1 == back_color)
+ current.MakeTransparent (back_color);
+ //
+ }
+
+ int yidx = 0;
+ int imgidx = 0;
+ int localy = 0;
+ int localx = 0;
+ int factor_y = 0;
+ int factor_x = 0;
+ for (int y = 0; y < main.Height; y++) {
+ if (localy == h) {
+ localy = 0;
+ factor_y += 4;
+ }
+ factor_x = 0;
+ localx = 0;
+ for (int x = 0; x < main.Width; x++) {
+ if (localx == w) {
+ localx = 0;
+ factor_x++;
+ }
+ imgidx = factor_y + factor_x;
+ if (imgidx >= images.Length)
+ break;
+ current = (Bitmap) images [imgidx];
+ Color color = current.GetPixel (localx, localy);
+ if (color.A == 0) {
+ int ptridx = yidx + (x >> 3);
+ scan [ptridx] |= (byte) (0x80 >> (x & 7));
+ }
+ localx++;
+ }
+ if (imgidx >= images.Length)
+ break;
+ yidx += stride;
+ localy++;
+ }
+ result.UnlockBits (dresult);
+
+ return result;
+ }
+
+ static MemoryStream GetDecodedStream (byte [] bytes, int offset, int size)
+ {
+ byte [] buffer = new byte [512];
+ int position = 0;
+ int count, data;
+ MemoryStream result = new MemoryStream ();
+ while (size > 0) {
+ count = (int) bytes [offset++];
+ data = (int) bytes [offset++];
+ if ((512 - count) < position) {
+ result.Write (buffer, 0, position);
+ position = 0;
+ }
+
+ for (int i = 0; i < count; i++)
+ buffer [position++] = (byte) data;
+ size -= 2;
+ }
+
+ if (position > 0)
+ result.Write (buffer, 0, position);
+
+ result.Position = 0;
+ return result;
+ }
+
+ //TODO: OptimizeMe
+ static MemoryStream GetRLEStream (MemoryStream input, int start)
+ {
+ MemoryStream result = new MemoryStream ();
+ byte [] ibuffer = input.GetBuffer ();
+ result.Write (ibuffer, 0, start);
+ input.Position = start;
+
+ int prev = -1;
+ int count = 0;
+ int current;
+ while ((current = input.ReadByte ()) != -1) {
+ if (prev != current || count == 255) {
+ if (prev != -1) {
+ result.WriteByte ((byte) count);
+ result.WriteByte ((byte) prev);
+ }
+ prev = current;
+ count = 0;
+ }
+ count++;
+ }
+
+ if (count > 0) {
+ result.WriteByte ((byte) count);
+ result.WriteByte ((byte) current);
+ }
+
+ return result;
+ }
+
+ internal Image [] Images {
+ get { return images; }
+ }
+
+ internal Size ImageSize {
+ get { return image_size; }
+ }
+
+ internal ColorDepth ColorDepth {
+ get { return ColorDepth.Depth32Bit; }
+ }
+
+ internal Color BackColor {
+ get { return back_color; }
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/InternalWindowManager.cs b/source/ShiftUI/Internal/InternalWindowManager.cs
new file mode 100644
index 0000000..95fae49
--- /dev/null
+++ b/source/ShiftUI/Internal/InternalWindowManager.cs
@@ -0,0 +1,1211 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Jackson Harper ([email protected])
+//
+//
+
+
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+
+namespace ShiftUI {
+
+ internal abstract class InternalWindowManager {
+ private TitleButtons title_buttons;
+ internal Form form;
+
+ // moving windows
+ internal Point start;
+ internal State state;
+ protected Point clicked_point;
+ private FormPos sizing_edge;
+ internal Rectangle virtual_position;
+
+ private Rectangle normal_bounds;
+ private Rectangle iconic_bounds;
+
+
+ public enum State {
+ Idle,
+ Moving,
+ Sizing,
+ }
+
+ [Flags]
+ public enum FormPos {
+ None,
+
+ TitleBar = 1,
+
+ Top = 2,
+ Left = 4,
+ Right = 8,
+ Bottom = 16,
+
+ TopLeft = Top | Left,
+ TopRight = Top | Right,
+
+ BottomLeft = Bottom | Left,
+ BottomRight = Bottom | Right,
+
+ AnyEdge = Top | Left | Right | Bottom,
+ }
+
+ public InternalWindowManager (Form form)
+ {
+ this.form = form;
+
+ form.SizeChanged += new EventHandler (FormSizeChangedHandler);
+
+ title_buttons = new TitleButtons (form);
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ }
+
+ public Form Form {
+ get { return form; }
+ }
+
+ public int IconWidth {
+ get { return TitleBarHeight - 5; }
+ }
+
+ public TitleButtons TitleButtons {
+ get {
+ return title_buttons;
+ }
+ }
+ internal Rectangle NormalBounds {
+ get {
+ return normal_bounds;
+ }
+ set {
+ normal_bounds = value;
+ }
+ }
+ internal Size IconicSize {
+ get {
+ return SystemInformation.MinimizedWindowSize;
+ }
+ }
+
+ internal Rectangle IconicBounds {
+ get {
+ if (iconic_bounds == Rectangle.Empty)
+ return Rectangle.Empty;
+ Rectangle result = iconic_bounds;
+ result.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
+ return result;
+ }
+ set {
+ iconic_bounds = value;
+ iconic_bounds.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
+ }
+ }
+
+ internal virtual Rectangle MaximizedBounds {
+ get {
+ return Form.Parent.ClientRectangle;
+ }
+ }
+
+ public virtual void UpdateWindowState (FormWindowState old_window_state, FormWindowState new_window_state, bool force)
+ {
+ if (old_window_state == FormWindowState.Normal) {
+ NormalBounds = form.Bounds;
+ } else if (old_window_state == FormWindowState.Minimized) {
+ IconicBounds = form.Bounds;
+ }
+
+ switch (new_window_state) {
+ case FormWindowState.Minimized:
+ if (IconicBounds == Rectangle.Empty) {
+ Size size = IconicSize;
+ Point location = new Point (0, Form.Parent.ClientSize.Height - size.Height);
+ IconicBounds = new Rectangle (location, size);
+ }
+ form.Bounds = IconicBounds;
+ break;
+ case FormWindowState.Maximized:
+ form.Bounds = MaximizedBounds;
+ break;
+ case FormWindowState.Normal:
+ form.Bounds = NormalBounds;
+ break;
+ }
+
+ UpdateWindowDecorations (new_window_state);
+ form.ResetCursor ();
+ }
+
+ public virtual void UpdateWindowDecorations (FormWindowState window_state)
+ {
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ if (form.IsHandleCreated)
+ XplatUI.RequestNCRecalc (form.Handle);
+ }
+
+ public virtual bool WndProc (ref Message m)
+ {
+#if debug
+ Console.WriteLine(DateTime.Now.ToLongTimeString () + " " + this.GetType () .Name + " (Handle={0},Text={1}) received message {2}", form.IsHandleCreated ? form.Handle : IntPtr.Zero, form.Text, m.ToString ());
+#endif
+
+ switch ((Msg)m.Msg) {
+
+
+ // The mouse handling messages are actually
+ // not WM_NC* messages except for the first button and NCMOVEs
+ // down because we capture on the form
+
+ case Msg.WM_MOUSEMOVE:
+ return HandleMouseMove (form, ref m);
+
+ case Msg.WM_LBUTTONUP:
+ HandleLButtonUp (ref m);
+ break;
+
+ case Msg.WM_RBUTTONDOWN:
+ return HandleRButtonDown (ref m);
+
+ case Msg.WM_LBUTTONDOWN:
+ return HandleLButtonDown (ref m);
+
+ case Msg.WM_LBUTTONDBLCLK:
+ return HandleLButtonDblClick (ref m);
+
+ case Msg.WM_PARENTNOTIFY:
+ if (Widget.LowOrder(m.WParam.ToInt32()) == (int) Msg.WM_LBUTTONDOWN)
+ Activate ();
+ break;
+
+ case Msg.WM_NCHITTEST:
+ return HandleNCHitTest (ref m);
+
+ // Return true from these guys, otherwise win32 will mess up z-order
+ case Msg.WM_NCLBUTTONUP:
+ HandleNCLButtonUp (ref m);
+ return true;
+
+ case Msg.WM_NCLBUTTONDOWN:
+ HandleNCLButtonDown (ref m);
+ return true;
+
+ case Msg.WM_NCMOUSEMOVE:
+ HandleNCMouseMove (ref m);
+ return true;
+
+ case Msg.WM_NCLBUTTONDBLCLK:
+ HandleNCLButtonDblClick (ref m);
+ break;
+
+ case Msg.WM_NCMOUSELEAVE:
+ HandleNCMouseLeave (ref m);
+ break;
+
+ case Msg.WM_MOUSELEAVE:
+ HandleMouseLeave (ref m);
+ break;
+
+ case Msg.WM_NCCALCSIZE:
+ return HandleNCCalcSize (ref m);
+
+ case Msg.WM_NCPAINT:
+ return HandleNCPaint (ref m);
+ }
+
+ return false;
+ }
+
+ protected virtual bool HandleNCPaint (ref Message m)
+ {
+ PaintEventArgs pe = XplatUI.PaintEventStart (ref m, form.Handle, false);
+
+ Rectangle clip;
+
+ if (form.ActiveMenu != null) {
+ Point pnt;
+
+ pnt = GetMenuOrigin ();
+
+ // The entire menu has to be in the clip rectangle because the
+ // control buttons are right-aligned and otherwise they would
+ // stay painted when the window gets resized.
+ clip = new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0);
+ clip = Rectangle.Union (clip, pe.ClipRectangle);
+ pe.SetClip (clip);
+ pe.Graphics.SetClip (clip);
+
+ form.ActiveMenu.Draw (pe, new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0));
+ }
+ if (HasBorders || IsMinimized && !(Form.IsMdiChild && IsMaximized)) {
+ // clip region is not correct on win32.
+ // use the entire form's area.
+ clip = new Rectangle (0, 0, form.Width, form.Height);
+ ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this);
+ }
+ XplatUI.PaintEventEnd (ref m, form.Handle, false);
+ return true;
+ }
+
+ protected virtual bool HandleNCCalcSize (ref Message m)
+ {
+ XplatUIWin32.NCCALCSIZE_PARAMS ncp;
+ XplatUIWin32.RECT rect;
+
+ if (m.WParam == (IntPtr)1) {
+ ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam,
+ typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
+
+ ncp.rgrc1 = NCCalcSize (ncp.rgrc1);
+
+ Marshal.StructureToPtr (ncp, m.LParam, true);
+ } else {
+ rect = (XplatUIWin32.RECT) Marshal.PtrToStructure (m.LParam, typeof (XplatUIWin32.RECT));
+
+ rect = NCCalcSize (rect);
+
+ Marshal.StructureToPtr (rect, m.LParam, true);
+ }
+
+ return true;
+ }
+
+ protected virtual XplatUIWin32.RECT NCCalcSize (XplatUIWin32.RECT proposed_window_rect)
+ {
+ int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
+
+ if (HasBorders) {
+ proposed_window_rect.top += TitleBarHeight + bw;
+ proposed_window_rect.bottom -= bw;
+ proposed_window_rect.left += bw;
+ proposed_window_rect.right -= bw;
+ }
+
+ if (XplatUI.RequiresPositiveClientAreaSize) {
+ // This is necessary for Linux, can't handle <= 0-sized
+ // client areas correctly.
+ if (proposed_window_rect.right <= proposed_window_rect.left) {
+ proposed_window_rect.right += proposed_window_rect.left - proposed_window_rect.right + 1;
+ }
+ if (proposed_window_rect.top >= proposed_window_rect.bottom) {
+ proposed_window_rect.bottom += proposed_window_rect.top - proposed_window_rect.bottom + 1;
+ }
+ }
+
+ return proposed_window_rect;
+ }
+
+ protected virtual bool HandleNCHitTest (ref Message m)
+ {
+
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ NCPointToClient (ref x, ref y);
+
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos == FormPos.TitleBar) {
+ m.Result = new IntPtr ((int)HitTest.HTCAPTION);
+ return true;
+ }
+
+ if (!IsSizable)
+ return false;
+
+ switch (pos) {
+ case FormPos.Top:
+ m.Result = new IntPtr ((int)HitTest.HTTOP);
+ break;
+ case FormPos.Left:
+ m.Result = new IntPtr ((int)HitTest.HTLEFT);
+ break;
+ case FormPos.Right:
+ m.Result = new IntPtr ((int)HitTest.HTRIGHT);
+ break;
+ case FormPos.Bottom:
+ m.Result = new IntPtr ((int)HitTest.HTBOTTOM);
+ break;
+ case FormPos.TopLeft:
+ m.Result = new IntPtr ((int)HitTest.HTTOPLEFT);
+ break;
+ case FormPos.TopRight:
+ m.Result = new IntPtr ((int)HitTest.HTTOPRIGHT);
+ break;
+ case FormPos.BottomLeft:
+ m.Result = new IntPtr ((int)HitTest.HTBOTTOMLEFT);
+ break;
+ case FormPos.BottomRight:
+ m.Result = new IntPtr ((int)HitTest.HTBOTTOMRIGHT);
+ break;
+ default:
+ // We return false so that DefWndProc handles things
+ return false;
+ }
+ return true;
+ }
+
+ public virtual void UpdateBorderStyle (FormBorderStyle border_style)
+ {
+ if (form.IsHandleCreated) {
+ XplatUI.SetBorderStyle (form.Handle, border_style);
+ }
+
+ if (ShouldRemoveWindowManager (border_style)) {
+ form.RemoveWindowManager ();
+ return;
+ }
+
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ }
+
+
+
+ public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state)
+ {
+ UpdateWindowState (old_state, window_state, false);
+ }
+
+ public virtual FormWindowState GetWindowState ()
+ {
+ return form.window_state;
+ }
+
+ public virtual void PointToClient (ref int x, ref int y)
+ {
+ // toolwindows stay in screencoords we just have to make sure
+ // they obey the working area
+ Rectangle working = SystemInformation.WorkingArea;
+
+ if (x > working.Right)
+ x = working.Right;
+ if (x < working.Left)
+ x = working.Left;
+
+ if (y < working.Top)
+ y = working.Top;
+ if (y > working.Bottom)
+ y = working.Bottom;
+ }
+
+ public virtual void PointToScreen (ref int x, ref int y)
+ {
+ XplatUI.ClientToScreen (form.Handle, ref x, ref y);
+ }
+
+ protected virtual bool ShouldRemoveWindowManager (FormBorderStyle style)
+ {
+ return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow;
+ }
+
+ public bool IconRectangleContains (int x, int y)
+ {
+ if (!ShowIcon)
+ return false;
+
+ Rectangle icon = ThemeEngine.Current.ManagedWindowGetTitleBarIconArea (this);
+ return icon.Contains (x, y);
+ }
+
+ public bool ShowIcon {
+ get {
+ if (!Form.ShowIcon)
+ return false;
+ if (!HasBorders)
+ return false;
+ if (IsMinimized)
+ return true;
+ if (IsToolWindow || Form.FormBorderStyle == FormBorderStyle.FixedDialog)
+ return false;
+ return true;
+ }
+ }
+
+ protected virtual void Activate ()
+ {
+ form.Invalidate (true);
+ form.Update ();
+ }
+
+ public virtual bool IsActive {
+ get {
+ return true;
+ }
+ }
+
+
+ private void FormSizeChangedHandler (object sender, EventArgs e)
+ {
+ if (form.IsHandleCreated) {
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ XplatUI.InvalidateNC (form.Handle);
+ }
+ }
+
+ protected virtual bool HandleRButtonDown (ref Message m)
+ {
+ Activate ();
+ return false;
+ }
+
+ protected virtual bool HandleLButtonDown (ref Message m)
+ {
+ Activate ();
+ return false;
+ }
+
+ protected virtual bool HandleLButtonDblClick(ref Message m)
+ {
+ return false;
+ }
+
+ protected virtual bool HandleNCMouseLeave (ref Message m)
+ {
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos != FormPos.TitleBar) {
+ HandleTitleBarLeave (x, y);
+ return true;
+ }
+
+ return true;
+ }
+
+ protected virtual bool HandleNCMouseMove (ref Message m)
+ {
+ int x = Widget.LowOrder((int)m.LParam.ToInt32( ));
+ int y = Widget.HighOrder((int)m.LParam.ToInt32( ));
+
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos == FormPos.TitleBar) {
+ HandleTitleBarMouseMove (x, y);
+ return true;
+ }
+
+ if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
+ MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y, 0);
+ form.ActiveMenu.OnMouseMove (form, mea);
+ }
+
+ return true;
+
+ }
+
+ protected virtual bool HandleNCLButtonDown (ref Message m)
+ {
+ Activate ();
+
+ start = Cursor.Position;
+ virtual_position = form.Bounds;
+
+ int x = Widget.LowOrder ((int) m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int) m.LParam.ToInt32 ());
+
+ // Need to adjust because we are in NC land
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
+ MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y - TitleBarHeight, 0);
+ form.ActiveMenu.OnMouseDown (form, mea);
+ }
+
+ if (pos == FormPos.TitleBar) {
+ HandleTitleBarDown (x, y);
+ return true;
+ }
+
+ if (IsSizable) {
+ if ((pos & FormPos.AnyEdge) == 0)
+ return false;
+
+ virtual_position = form.Bounds;
+ state = State.Sizing;
+ sizing_edge = pos;
+ form.Capture = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ protected virtual void HandleNCLButtonDblClick (ref Message m)
+ {
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ // Need to adjust because we are in NC land
+ NCPointToClient (ref x, ref y);
+
+ FormPos pos = FormPosForCoords (x, y);
+ if (pos == FormPos.TitleBar || pos == FormPos.Top)
+ HandleTitleBarDoubleClick (x, y);
+
+ }
+
+ protected virtual void HandleTitleBarDoubleClick (int x, int y)
+ {
+
+ }
+
+ protected virtual void HandleTitleBarLeave (int x, int y)
+ {
+ title_buttons.MouseLeave (x, y);
+ }
+
+ protected virtual void HandleTitleBarMouseMove (int x, int y)
+ {
+ if (title_buttons.MouseMove (x, y))
+ XplatUI.InvalidateNC (form.Handle);
+ }
+
+ protected virtual void HandleTitleBarUp (int x, int y)
+ {
+ title_buttons.MouseUp (x, y);
+
+ return;
+ }
+
+ protected virtual void HandleTitleBarDown (int x, int y)
+ {
+ title_buttons.MouseDown (x, y);
+
+ if (!TitleButtons.AnyPushedTitleButtons && !IsMaximized) {
+ state = State.Moving;
+ clicked_point = new Point (x, y);
+ if (form.Parent != null) {
+ form.CaptureWithConfine (form.Parent);
+ } else {
+ form.Capture = true;
+ }
+ }
+
+ XplatUI.InvalidateNC (form.Handle);
+ }
+
+ private bool HandleMouseMove (Form form, ref Message m)
+ {
+ switch (state) {
+ case State.Moving:
+ HandleWindowMove (m);
+ return true;
+ case State.Sizing:
+ HandleSizing (m);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void HandleMouseLeave (ref Message m)
+ {
+ form.ResetCursor ();
+ }
+
+ protected virtual void HandleWindowMove (Message m)
+ {
+ Point move = MouseMove (Cursor.Position);
+
+ UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y,
+ virtual_position.Width, virtual_position.Height);
+ }
+
+ private void HandleSizing (Message m)
+ {
+ Rectangle pos = virtual_position;
+ int mw;
+ int mh;
+ if (IsToolWindow) {
+ int border_width = BorderWidth;
+ mw = 2 * (border_width + Theme.ManagedWindowSpacingAfterLastTitleButton) + ThemeEngine.Current.ManagedWindowButtonSize (this).Width;
+ mh = 2 * border_width + TitleBarHeight;
+ } else {
+ Size minimum_size = SystemInformation.MinWindowTrackSize;
+ mw = minimum_size.Width;
+ mh = minimum_size.Height;
+ }
+ int x = Cursor.Position.X;
+ int y = Cursor.Position.Y;
+
+ PointToClient (ref x, ref y);
+
+ if ((sizing_edge & FormPos.Top) != 0) {
+ if (pos.Bottom - y < mh)
+ y = pos.Bottom - mh;
+ pos.Height = pos.Bottom - y;
+ pos.Y = y;
+ } else if ((sizing_edge & FormPos.Bottom) != 0) {
+ int height = y - pos.Top;
+ if (height <= mh)
+ height = mh;
+ pos.Height = height;
+ }
+
+ if ((sizing_edge & FormPos.Left) != 0) {
+ if (pos.Right - x < mw)
+ x = pos.Right - mw;
+ pos.Width = pos.Right - x;
+ pos.X = x;
+ } else if ((sizing_edge & FormPos.Right) != 0) {
+ int width = x - form.Left;
+ if (width <= mw)
+ width = mw;
+ pos.Width = width;
+ }
+
+ UpdateVP (pos);
+ }
+
+ public bool IsMaximized {
+ get { return GetWindowState () == FormWindowState.Maximized; }
+ }
+
+ public bool IsMinimized {
+ get { return GetWindowState () == FormWindowState.Minimized; }
+ }
+
+ public bool IsSizable {
+ get {
+ switch (form.FormBorderStyle) {
+ case FormBorderStyle.Sizable:
+ case FormBorderStyle.SizableToolWindow:
+ return (form.window_state != FormWindowState.Minimized);
+ default:
+ return false;
+ }
+ }
+ }
+
+ public bool HasBorders {
+ get {
+ return form.FormBorderStyle != FormBorderStyle.None;
+ }
+ }
+
+ public bool IsToolWindow {
+ get {
+ if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
+ form.FormBorderStyle == FormBorderStyle.FixedToolWindow ||
+ form.GetCreateParams().IsSet (WindowExStyles.WS_EX_TOOLWINDOW))
+ return true;
+ return false;
+ }
+ }
+
+ public int TitleBarHeight {
+ get {
+ return ThemeEngine.Current.ManagedWindowTitleBarHeight (this);
+ }
+ }
+
+ public int BorderWidth {
+ get {
+ return ThemeEngine.Current.ManagedWindowBorderWidth (this);
+ }
+ }
+
+ public virtual int MenuHeight {
+ get {
+ return (form.Menu != null ? ThemeEngine.Current.MenuHeight : 0);
+ }
+ }
+
+ protected void UpdateVP (Rectangle r)
+ {
+ UpdateVP (r.X, r.Y, r.Width, r.Height);
+ }
+
+ protected void UpdateVP (Point loc, int w, int h)
+ {
+ UpdateVP (loc.X, loc.Y, w, h);
+ }
+
+ protected void UpdateVP (int x, int y, int w, int h)
+ {
+ virtual_position.X = x;
+ virtual_position.Y = y;
+ virtual_position.Width = w;
+ virtual_position.Height = h;
+
+ DrawVirtualPosition (virtual_position);
+ }
+
+ protected virtual void HandleLButtonUp (ref Message m)
+ {
+ if (state == State.Idle)
+ return;
+
+ ClearVirtualPosition ();
+
+ form.Capture = false;
+ if (state == State.Moving && form.Location != virtual_position.Location)
+ form.Location = virtual_position.Location;
+ else if (state == State.Sizing && form.Bounds != virtual_position)
+ form.Bounds = virtual_position;
+ state = State.Idle;
+
+ OnWindowFinishedMoving ();
+ }
+
+ private bool HandleNCLButtonUp (ref Message m)
+ {
+ if (form.Capture) {
+ ClearVirtualPosition ();
+
+ form.Capture = false;
+ state = State.Idle;
+ if (form.MdiContainer != null)
+ form.MdiContainer.SizeScrollBars();
+ }
+
+ int x = Widget.LowOrder ((int) m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int) m.LParam.ToInt32 ());
+
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos == FormPos.TitleBar) {
+ HandleTitleBarUp (x, y);
+ return true;
+ }
+
+ return true;
+ }
+
+ protected void DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip)
+ {
+ if (!button.Rectangle.IntersectsWith (clip))
+ return;
+
+ ThemeEngine.Current.ManagedWindowDrawMenuButton (dc, button, clip, this);
+ }
+
+ public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe)
+ {
+ }
+
+ protected Point MouseMove (Point pos)
+ {
+ return new Point (pos.X - start.X, pos.Y - start.Y);
+ }
+
+ protected virtual void DrawVirtualPosition (Rectangle virtual_position)
+ {
+ form.Bounds = virtual_position;
+ start = Cursor.Position;
+ }
+
+ protected virtual void ClearVirtualPosition ()
+ {
+
+ }
+
+ protected virtual void OnWindowFinishedMoving ()
+ {
+ }
+
+ protected virtual void NCPointToClient(ref int x, ref int y) {
+ form.PointToClient(ref x, ref y);
+ NCClientToNC (ref x, ref y);
+ }
+
+ protected virtual void NCClientToNC (ref int x, ref int y) {
+ y += TitleBarHeight;
+ y += BorderWidth;
+ y += MenuHeight;
+ }
+
+ internal Point GetMenuOrigin ()
+ {
+ return new Point (BorderWidth, BorderWidth + TitleBarHeight);
+ }
+
+ protected FormPos FormPosForCoords (int x, int y)
+ {
+ int bw = BorderWidth;
+ if (y < TitleBarHeight + bw) {
+ // Console.WriteLine ("A");
+ if (y > bw && x > bw &&
+ x < form.Width - bw)
+ return FormPos.TitleBar;
+
+ if (x < bw || (x < 20 && y < bw))
+ return FormPos.TopLeft;
+
+ if (x > form.Width - bw ||
+ (x > form.Width - 20 && y < bw))
+ return FormPos.TopRight;
+
+ if (y < bw)
+ return FormPos.Top;
+
+ } else if (y > form.Height - 20) {
+ // Console.WriteLine ("B");
+ if (x < bw ||
+ (x < 20 && y > form.Height - bw))
+ return FormPos.BottomLeft;
+
+ if (x > form.Width - (bw * 2) ||
+ (x > form.Width - 20 &&
+ y > form.Height - bw))
+ return FormPos.BottomRight;
+
+ if (y > form.Height - (bw * 2))
+ return FormPos.Bottom;
+
+
+ } else if (x < bw) {
+ // Console.WriteLine ("C");
+ return FormPos.Left;
+ } else if (x > form.Width - (bw * 2)) {
+// Console.WriteLine ("D");
+ return FormPos.Right;
+ } else {
+ // Console.WriteLine ("E {0}", form.Width - bw);
+ }
+
+ return FormPos.None;
+ }
+ }
+ internal class TitleButton
+ {
+ public Rectangle Rectangle;
+ public ButtonState State;
+ public CaptionButton Caption;
+ private EventHandler Clicked;
+ public bool Visible;
+ bool entered;
+
+ public TitleButton (CaptionButton caption, EventHandler clicked)
+ {
+ Caption = caption;
+ Clicked = clicked;
+ }
+
+ public void OnClick ()
+ {
+ if (Clicked != null) {
+ Clicked (this, EventArgs.Empty);
+ }
+ }
+
+ public bool Entered {
+ get { return entered; }
+ set { entered = value; }
+ }
+ }
+
+ internal class TitleButtons : System.Collections.IEnumerable
+ {
+ public TitleButton MinimizeButton;
+ public TitleButton MaximizeButton;
+ public TitleButton RestoreButton;
+ public TitleButton CloseButton;
+ public TitleButton HelpButton;
+
+ public TitleButton [] AllButtons;
+ public bool Visible;
+
+ private ToolTip.ToolTipWindow tooltip;
+ private Timer tooltip_timer;
+ private TitleButton tooltip_hovered_button;
+ private TitleButton tooltip_hidden_button;
+ private const int tooltip_hide_interval = 3000;
+ private const int tooltip_show_interval = 1000;
+ private Form form;
+
+ public TitleButtons (Form frm)
+ {
+ this.form = frm;
+ this.Visible = true;
+
+ MinimizeButton = new TitleButton (CaptionButton.Minimize, new EventHandler (ClickHandler));
+ MaximizeButton = new TitleButton (CaptionButton.Maximize, new EventHandler (ClickHandler));
+ RestoreButton = new TitleButton (CaptionButton.Restore, new EventHandler (ClickHandler));
+ CloseButton = new TitleButton (CaptionButton.Close, new EventHandler (ClickHandler));
+ HelpButton = new TitleButton (CaptionButton.Help, new EventHandler (ClickHandler));
+
+ AllButtons = new TitleButton [] { MinimizeButton, MaximizeButton, RestoreButton, CloseButton, HelpButton };
+ }
+
+ private void ClickHandler (object sender, EventArgs e)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ TitleButton button = (TitleButton) sender;
+
+ switch (button.Caption) {
+ case CaptionButton.Close:
+ form.Close ();
+ break;
+ case CaptionButton.Help:
+ Console.WriteLine ("Help not implemented.");
+ break;
+ case CaptionButton.Maximize:
+ form.WindowState = FormWindowState.Maximized;
+ break;
+ case CaptionButton.Minimize:
+ form.WindowState = FormWindowState.Minimized;
+ break;
+ case CaptionButton.Restore:
+ form.WindowState = FormWindowState.Normal;
+ break;
+ }
+ }
+
+ public TitleButton FindButton (int x, int y)
+ {
+ if (!Visible) {
+ return null;
+ }
+
+ foreach (TitleButton button in AllButtons) {
+ if (button.Visible && button.Rectangle.Contains (x, y)) {
+ return button;
+ }
+ }
+ return null;
+ }
+
+ public bool AnyPushedTitleButtons {
+ get {
+ if (!Visible) {
+ return false;
+ }
+
+ foreach (TitleButton button in AllButtons) {
+ if (button.Visible && button.State == ButtonState.Pushed) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ #region IEnumerable Members
+
+ public System.Collections.IEnumerator GetEnumerator ()
+ {
+ return AllButtons.GetEnumerator ();
+ }
+ #endregion
+
+ #region ToolTip helpers
+ // Called from MouseMove if mouse is over a button
+ public void ToolTipStart (TitleButton button)
+ {
+ tooltip_hovered_button = button;
+
+ if (tooltip_hovered_button == tooltip_hidden_button)
+ return;
+ tooltip_hidden_button = null;
+
+ if (tooltip != null && tooltip.Visible)
+ ToolTipShow (true);
+
+ if (tooltip_timer == null) {
+
+ tooltip_timer = new Timer ();
+ tooltip_timer.Tick += new EventHandler (ToolTipTimerTick);
+ }
+
+ tooltip_timer.Interval = tooltip_show_interval;
+ tooltip_timer.Start ();
+ tooltip_hovered_button = button;
+ }
+
+ public void ToolTipTimerTick (object sender, EventArgs e)
+ {
+ if (tooltip_timer.Interval == tooltip_hide_interval) {
+ tooltip_hidden_button = tooltip_hovered_button;
+ ToolTipHide (false);
+ } else {
+ ToolTipShow (false);
+ }
+ }
+ // Called from timer (with only_refresh = false)
+ // Called from ToolTipStart if tooltip is already shown (with only_refresh = true)
+ public void ToolTipShow (bool only_refresh)
+ {
+ if (!form.Visible)
+ return;
+
+ string text = String.Format (tooltip_hovered_button.Caption.ToString ());
+
+ tooltip_timer.Interval = tooltip_hide_interval;
+ tooltip_timer.Enabled = true;
+
+ if (only_refresh && (tooltip == null || !tooltip.Visible)) {
+ return;
+ }
+
+ if (tooltip == null)
+ tooltip = new ToolTip.ToolTipWindow ();
+ else if (tooltip.Text == text && tooltip.Visible)
+ return;
+ else if (tooltip.Visible)
+ tooltip.Visible = false;
+
+ if (form.WindowState == FormWindowState.Maximized && form.MdiParent != null)
+ tooltip.Present (form.MdiParent, text);
+ else
+ tooltip.Present (form, text);
+
+ }
+
+ // Called from MouseLeave (with reset_hidden_button = true)
+ // Called from MouseDown (with reset_hidden_button = false)
+ // Called from MouseMove if mouse isn't over any button (with reset_hidden_button = false)
+ // Called from Timer if hiding (with reset_hidden_button = false)
+ public void ToolTipHide (bool reset_hidden_button)
+ {
+ if (tooltip_timer != null)
+ tooltip_timer.Enabled = false;
+ if (tooltip != null && tooltip.Visible)
+ tooltip.Visible = false;
+ if (reset_hidden_button)
+ tooltip_hidden_button = null;
+ }
+ #endregion
+
+ public bool MouseMove (int x, int y)
+ {
+ if (!Visible) {
+ return false;
+ }
+
+ bool any_change = false;
+ bool any_pushed_buttons = AnyPushedTitleButtons;
+ bool any_tooltip = false;
+ TitleButton over_button = FindButton (x, y);
+
+ foreach (TitleButton button in this) {
+ if (button == null)
+ continue;
+
+ if (button.State == ButtonState.Inactive)
+ continue;
+
+ if (button == over_button) {
+ if (any_pushed_buttons) {
+ any_change |= button.State != ButtonState.Pushed;
+ button.State = ButtonState.Pushed;
+ }
+ ToolTipStart (button);
+ any_tooltip = true;
+ if (!button.Entered) {
+ button.Entered = true;
+ if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form))
+ any_change = true;
+ }
+ } else {
+ if (any_pushed_buttons) {
+ any_change |= button.State != ButtonState.Normal;
+ button.State = ButtonState.Normal;
+ }
+ if (button.Entered) {
+ button.Entered = false;
+ if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form))
+ any_change = true;
+ }
+ }
+ }
+
+ if (!any_tooltip)
+ ToolTipHide (false);
+
+ return any_change;
+ }
+
+ public void MouseDown (int x, int y)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ ToolTipHide (false);
+
+ foreach (TitleButton button in this) {
+ if (button != null && button.State != ButtonState.Inactive) {
+ button.State = ButtonState.Normal;
+ }
+ }
+ TitleButton clicked_button = FindButton (x, y);
+ if (clicked_button != null && clicked_button.State != ButtonState.Inactive) {
+ clicked_button.State = ButtonState.Pushed;
+ }
+ }
+
+ public void MouseUp (int x, int y)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ TitleButton clicked_button = FindButton (x, y);
+ if (clicked_button != null && clicked_button.State != ButtonState.Inactive) {
+ clicked_button.OnClick ();
+ }
+
+ foreach (TitleButton button in this) {
+ if (button == null || button.State == ButtonState.Inactive)
+ continue;
+
+ button.State = ButtonState.Normal;
+ }
+
+ if (clicked_button == CloseButton && !form.closing)
+ XplatUI.InvalidateNC (form.Handle);
+
+ ToolTipHide (true);
+ }
+
+ internal void MouseLeave (int x, int y)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ foreach (TitleButton button in this) {
+ if (button == null || button.State == ButtonState.Inactive)
+ continue;
+
+ button.State = ButtonState.Normal;
+ }
+
+ ToolTipHide (true);
+ }
+ }
+}
+
+
diff --git a/source/ShiftUI/Internal/KeyboardHandler.cs b/source/ShiftUI/Internal/KeyboardHandler.cs
new file mode 100644
index 0000000..5122e7b
--- /dev/null
+++ b/source/ShiftUI/Internal/KeyboardHandler.cs
@@ -0,0 +1,329 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton ([email protected])
+//
+//
+using System;
+using System.Collections;
+using System.Text;
+using System.Globalization;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.CarbonInternal {
+ internal class KeyboardHandler : EventHandlerBase, IEventHandler {
+ internal const uint kEventRawKeyDown = 1;
+ internal const uint kEventRawKeyRepeat = 2;
+ internal const uint kEventRawKeyUp = 3;
+ internal const uint kEventRawKeyModifiersChanged = 4;
+ internal const uint kEventHotKeyPressed = 5;
+ internal const uint kEventHotKeyReleased = 6;
+
+ internal const uint kEventParamKeyMacCharCodes = 1801676914;
+ internal const uint kEventParamKeyCode = 1801678692;
+ internal const uint kEventParamKeyModifiers = 1802334052;
+ internal const uint kEventTextInputUnicodeForKeyEvent = 2;
+ internal const uint kEventParamTextInputSendText = 1953723512;
+
+ internal const uint typeChar = 1413830740;
+ internal const uint typeUInt32 = 1835100014;
+ internal const uint typeUnicodeText = 1970567284;
+
+ internal static byte [] key_filter_table;
+ internal static byte [] key_modifier_table;
+ internal static byte [] key_translation_table;
+ internal static byte [] char_translation_table;
+
+ internal static bool translate_modifier = false;
+
+ internal string ComposedString;
+
+ static KeyboardHandler () {
+ // our key filter table is a 256 byte array - if the corresponding byte
+ // is set the key should be filtered from WM_CHAR (apple pushes unicode events
+ // for some keys which win32 only handles as KEYDOWN
+ // currently filtered:
+ // fn+f* == 16
+ // left == 28
+ // right == 29
+ // up == 30
+ // down == 31
+ // Please update this list as well as the table as more keys are found
+ key_filter_table = new byte [256] {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ // our char translation table is a set of translations from mac char codes
+ // to win32 vkey codes
+ // most things map directly
+ char_translation_table = new byte [256] {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0x25, 0x27, 0x26, 0x28,
+32, 49, 34, 51, 52, 53, 55, 222, 57, 48, 56, 187, 188, 189, 190, 191,
+48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 186, 60, 61, 62, 63,
+50, 65, 66, 67, 68, 187, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 219, 220, 221, 54, 189,
+192, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 0x2e,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+ };
+ key_translation_table = new byte [256] {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+0x74, 0x75, 0x76, 0x72, 0x77, 0x78, 0x79, 103, 104, 105, 106, 107, 108, 109, 0x7a, 0x7b,
+112, 113, 114, 115, 116, 117, 0x73, 119, 0x71, 121, 0x70, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+ };
+ // the key modifier table is a state table of the possible modifier keys
+ // apple currently only goes up to 1 << 14 keys, we've extended this to 32
+ // bytes as thats the size that apple uses
+ key_modifier_table = new byte [32];
+ }
+
+ internal KeyboardHandler (XplatUICarbon driver) : base (driver) {}
+
+ private void ModifierToVirtualKey (int i, ref MSG msg, bool down) {
+ msg.hwnd = XplatUICarbon.FocusWindow;
+
+ if (i == 9 || i == 13) {
+ msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP);
+ msg.wParam = (IntPtr) VirtualKeys.VK_SHIFT;
+ msg.lParam = IntPtr.Zero;
+ return;
+ }
+ if (i == 12 || i == 14) {
+ msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP);
+ msg.wParam = (IntPtr) VirtualKeys.VK_CONTROL;
+ msg.lParam = IntPtr.Zero;
+ return;
+ }
+ if (i == 8) {
+ msg.message = (down ? Msg.WM_SYSKEYDOWN : Msg.WM_SYSKEYUP);
+ msg.wParam = (IntPtr) VirtualKeys.VK_MENU;
+ msg.lParam = new IntPtr (0x20000000);
+ return;
+ }
+
+ return;
+ }
+
+ public void ProcessModifiers (IntPtr eventref, ref MSG msg) {
+ // we get notified when modifiers change, but not specifically what changed
+ UInt32 modifiers = 0;
+
+ GetEventParameter (eventref, kEventParamKeyModifiers, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt32)), IntPtr.Zero, ref modifiers);
+
+ for (int i = 0; i < 32; i++) {
+ if (key_modifier_table [i] == 0x01 && (modifiers & (1 << i)) == 0) {
+ ModifierToVirtualKey (i, ref msg, false);
+ key_modifier_table [i] = 0x00;
+ return;
+ } else if (key_modifier_table [i] == 0x00 && (modifiers & (1 << i)) == (1 << i)) {
+ ModifierToVirtualKey (i, ref msg, true);
+ key_modifier_table [i] = 0x01;
+ return;
+ }
+ }
+
+ return;
+ }
+
+ public void ProcessText (IntPtr eventref, ref MSG msg) {
+ UInt32 size = 0;
+ IntPtr buffer = IntPtr.Zero;
+ byte [] bdata;
+
+ // get the size of the unicode buffer
+ GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, 0, ref size, IntPtr.Zero);
+
+ buffer = Marshal.AllocHGlobal ((int) size);
+ bdata = new byte [size];
+
+ // get the actual text buffer
+ GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, size, IntPtr.Zero, buffer);
+
+ Marshal.Copy (buffer, bdata, 0, (int) size);
+ Marshal.FreeHGlobal (buffer);
+
+ if (key_filter_table [bdata [0]] == 0x00) {
+ if (size == 1) {
+ msg.message = Msg.WM_CHAR;
+ msg.wParam = BitConverter.IsLittleEndian ? (IntPtr) bdata [0] : (IntPtr) bdata [size-1];
+ msg.lParam = IntPtr.Zero;
+ msg.hwnd = XplatUICarbon.FocusWindow;
+ } else {
+ msg.message = Msg.WM_IME_COMPOSITION;
+ Encoding enc = BitConverter.IsLittleEndian ? Encoding.Unicode : Encoding.BigEndianUnicode;
+ ComposedString = enc.GetString (bdata);
+ msg.hwnd = XplatUICarbon.FocusWindow;
+ }
+ }
+ }
+
+ public void ProcessKeyPress (IntPtr eventref, ref MSG msg) {
+ byte charCode = 0x0;
+ byte keyCode = 0x0;
+
+ GetEventParameter (eventref, kEventParamKeyMacCharCodes, typeChar, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref charCode);
+ GetEventParameter (eventref, kEventParamKeyCode, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref keyCode);
+
+ msg.lParam = (IntPtr) charCode;
+ msg.wParam = charCode == 0x10 ? (IntPtr) key_translation_table [keyCode] : (IntPtr) char_translation_table [charCode];
+ msg.hwnd = XplatUICarbon.FocusWindow;
+ }
+
+ public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
+ uint klass = EventHandler.GetEventClass (eventref);
+ bool result = true;
+
+ if (klass == EventHandler.kEventClassTextInput) {
+ switch (kind) {
+ case kEventTextInputUnicodeForKeyEvent:
+ ProcessText (eventref, ref msg);
+ break;
+ default:
+ Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
+ break;
+ }
+ } else if (klass == EventHandler.kEventClassKeyboard) {
+ switch (kind) {
+ case kEventRawKeyDown:
+ case kEventRawKeyRepeat:
+ msg.message = Msg.WM_KEYDOWN;
+ ProcessKeyPress (eventref, ref msg);
+ break;
+ case kEventRawKeyUp:
+ msg.message = Msg.WM_KEYUP;
+ ProcessKeyPress (eventref, ref msg);
+ break;
+ case kEventRawKeyModifiersChanged:
+ ProcessModifiers (eventref, ref msg);
+ break;
+ default:
+ Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassKeyboard should not be reached");
+ break;
+ }
+ } else {
+ Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
+ }
+
+ return result;
+ }
+
+ public bool TranslateMessage (ref MSG msg) {
+ bool res = false;
+
+ if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
+ res = true;
+
+ if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN && msg.message != Msg.WM_KEYUP && msg.message != Msg.WM_SYSKEYUP && msg.message != Msg.WM_CHAR && msg.message != Msg.WM_SYSCHAR)
+ return res;
+
+ if (key_modifier_table [8] == 0x01 && key_modifier_table [12] == 0x00 && key_modifier_table [14] == 0x00) {
+ if (msg.message == Msg.WM_KEYDOWN) {
+ msg.message = Msg.WM_SYSKEYDOWN;
+ } else if (msg.message == Msg.WM_CHAR) {
+ msg.message = Msg.WM_SYSCHAR;
+ translate_modifier = true;
+ } else if (msg.message == Msg.WM_KEYUP) {
+ msg.message = Msg.WM_SYSKEYUP;
+ } else {
+ return res;
+ }
+
+ msg.lParam = new IntPtr (0x20000000);
+ } else if (msg.message == Msg.WM_SYSKEYUP && translate_modifier && msg.wParam == (IntPtr) 18) {
+ msg.message = Msg.WM_KEYUP;
+
+ msg.lParam = IntPtr.Zero;
+ translate_modifier = false;
+ }
+
+ return res;
+ }
+
+ internal Keys ModifierKeys {
+ get {
+ Keys keys = Keys.None;
+ if (key_modifier_table [9] == 0x01 || key_modifier_table [13] == 0x01) { keys |= Keys.Shift; }
+ if (key_modifier_table [8] == 0x01) { keys |= Keys.Alt; }
+ if (key_modifier_table [12] == 0x01 || key_modifier_table [14] == 0x01) { keys |= Keys.Widget; }
+ return keys;
+ }
+ }
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, ref UInt32 outsize, IntPtr data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, IntPtr data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref byte data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref UInt32 data);
+ }
+
+ internal enum KeyboardModifiers : uint {
+ activeFlag = 1 << 0,
+ btnState = 1 << 7,
+ cmdKey = 1 << 8,
+ shiftKey = 1 << 9,
+ alphaLock = 1 << 10,
+ optionKey = 1 << 11,
+ WidgetKey = 1 << 12,
+ rightShiftKey = 1 << 13,
+ rightOptionKey = 1 << 14,
+ rightWidgetKey = 1 << 14,
+ }
+}
diff --git a/source/ShiftUI/Internal/KeysConverter.cs b/source/ShiftUI/Internal/KeysConverter.cs
new file mode 100644
index 0000000..6f24eae
--- /dev/null
+++ b/source/ShiftUI/Internal/KeysConverter.cs
@@ -0,0 +1,139 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System.Collections;
+using System.ComponentModel;
+using System.Text;
+using System;
+
+namespace ShiftUI {
+ public class KeysConverter : TypeConverter, IComparer {
+ #region Public Constructors
+ public KeysConverter() {
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Methods
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
+ if (sourceType == typeof(string)) {
+ return true;
+ }
+ return false;
+ }
+
+ public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof (Enum[]))
+ return true;
+
+ return base.CanConvertTo (context, destinationType);
+ }
+
+ public int Compare(object a, object b) {
+ if (a is string && b is string) {
+ return String.Compare((string) a, (string)b);
+ }
+ return String.Compare(a.ToString(), b.ToString());
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
+ if (value is string) {
+ string[] keys;
+ Keys key;
+
+ keys = ((string)value).Split(new char[] {'+'});
+ key = Keys.None;
+
+ if (keys.Length > 1) {
+ for (int i = 0; i < keys.Length - 1; i++) {
+ if (keys[i].Equals("Ctrl")) {
+ key |= Keys.Widget;
+ } else {
+ key |= (Keys)Enum.Parse(typeof(Keys), keys[i], true);
+ }
+ }
+ }
+ if (keys [keys.Length - 1].Equals ("Ctrl"))
+ key |= Keys.Widget;
+ else
+ key |= (Keys)Enum.Parse(typeof(Keys), keys[keys.Length - 1], true);
+ return key;
+ }
+ return base.ConvertFrom (context, culture, value);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
+ if (destinationType == typeof(string)) {
+ StringBuilder sb;
+ Keys key;
+
+ sb = new StringBuilder();
+ key = (Keys)value;
+
+ // Modifiers first
+ if ((key & Keys.Widget) != 0) {
+ sb.Append("Ctrl+");
+ }
+
+ if ((key & Keys.Alt) != 0) {
+ sb.Append("Alt+");
+ }
+
+ if ((key & Keys.Shift) != 0) {
+ sb.Append("Shift+");
+ }
+
+ // Keycode last
+ sb.Append(Enum.GetName(typeof(Keys), key & Keys.KeyCode));
+
+ return sb.ToString();
+ }
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
+ Keys [] stdVal = new Keys [] { Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6, Keys.D7,
+ Keys.D8, Keys.D9, Keys.Alt, Keys.Back, Keys.Widget, Keys.Delete, Keys.End, Keys.Return, Keys.F1,
+ Keys.F10, Keys.F11, Keys.F12, Keys.F2, Keys.F3, Keys.F4, Keys.F5, Keys.F6, Keys.F7, Keys.F8, Keys.F9,
+ Keys.Home, Keys.Insert, Keys.Next, Keys.PageUp, Keys.Shift };
+
+ return new TypeConverter.StandardValuesCollection (stdVal);
+ }
+
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
+
+ return false;
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
+ return true;
+ }
+
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/LayoutEngine.cs b/source/ShiftUI/Internal/LayoutEngine.cs
new file mode 100644
index 0000000..7b2ce71
--- /dev/null
+++ b/source/ShiftUI/Internal/LayoutEngine.cs
@@ -0,0 +1,43 @@
+// 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.
+//
+//
+// Author:
+// Miguel de Icaza ([email protected])
+//
+// (C) 2004 Novell, Inc.
+//
+
+using System;
+using System.ComponentModel;
+
+namespace ShiftUI.Layout {
+
+ public abstract class LayoutEngine {
+
+ public virtual void InitLayout (object child, BoundsSpecified specified)
+ {
+ }
+
+ public virtual bool Layout (object container, LayoutEventArgs layoutEventArgs)
+ {
+ return false;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/LayoutSettings.cs b/source/ShiftUI/Internal/LayoutSettings.cs
new file mode 100644
index 0000000..a97d744
--- /dev/null
+++ b/source/ShiftUI/Internal/LayoutSettings.cs
@@ -0,0 +1,40 @@
+// 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.
+//
+//
+// Author:
+// Miguel de Icaza ([email protected])
+//
+// (C) 2004 Novell, Inc.
+//
+
+using System;
+using System.ComponentModel;
+using ShiftUI.Layout;
+
+namespace ShiftUI {
+
+ public abstract class LayoutSettings {
+ public virtual LayoutEngine LayoutEngine {
+ get {
+ return null;
+ }
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/Line.cs b/source/ShiftUI/Internal/Line.cs
new file mode 100644
index 0000000..a523047
--- /dev/null
+++ b/source/ShiftUI/Internal/Line.cs
@@ -0,0 +1,811 @@
+// 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-2006 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Drawing.Text;
+using System.Text;
+
+namespace ShiftUI
+{
+ internal class Line : ICloneable, IComparable
+ {
+ #region Local Variables
+
+ internal Document document;
+ // Stuff that matters for our line
+ internal StringBuilder text; // Characters for the line
+ internal float[] widths; // Width of each character; always one larger than text.Length
+ internal int space; // Number of elements in text and widths
+ internal int line_no; // Line number
+ internal LineTag tags; // Tags describing the text
+ internal int offset; // Baseline can be on the X or Y axis depending if we are in multiline mode or not
+ internal int height; // Height of the line (height of tallest tag)
+ internal int ascent; // Ascent of the line (ascent of the tallest tag)
+ internal HorizontalAlignment alignment; // Alignment of the line
+ internal int align_shift; // Pixel shift caused by the alignment
+ internal int indent; // Left indent for the first line
+ internal int hanging_indent; // Hanging indent (left indent for all but the first line)
+ internal int right_indent; // Right indent for all lines
+ internal LineEnding ending;
+
+ // Stuff that's important for the tree
+ internal Line parent; // Our parent line
+ internal Line left; // Line with smaller line number
+ internal Line right; // Line with higher line number
+ internal LineColor color; // We're doing a black/red tree. this is the node color
+ static int DEFAULT_TEXT_LEN = 0; //
+ internal bool recalc; // Line changed
+
+ private static Hashtable kerning_fonts = new Hashtable (); // record which fonts use kerning
+ #endregion // Local Variables
+
+ #region Constructors
+ internal Line (Document document, LineEnding ending)
+ {
+ this.document = document;
+ color = LineColor.Red;
+ left = null;
+ right = null;
+ parent = null;
+ text = null;
+ recalc = true;
+ alignment = document.alignment;
+
+ this.ending = ending;
+ }
+
+ internal Line (Document document, int LineNo, string Text, Font font, Color color, LineEnding ending) : this (document, ending)
+ {
+ space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
+
+ text = new StringBuilder (Text, space);
+ line_no = LineNo;
+ this.ending = ending;
+
+ widths = new float[space + 1];
+
+
+ tags = new LineTag(this, 1);
+ tags.Font = font;
+ tags.Color = color;
+ }
+
+ internal Line (Document document, int LineNo, string Text, HorizontalAlignment align, Font font, Color color, LineEnding ending) : this(document, ending)
+ {
+ space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
+
+ text = new StringBuilder (Text, space);
+ line_no = LineNo;
+ this.ending = ending;
+ alignment = align;
+
+ widths = new float[space + 1];
+
+
+ tags = new LineTag(this, 1);
+ tags.Font = font;
+ tags.Color = color;
+ }
+
+ internal Line (Document document, int LineNo, string Text, LineTag tag, LineEnding ending) : this(document, ending)
+ {
+ space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
+
+ text = new StringBuilder (Text, space);
+ this.ending = ending;
+ line_no = LineNo;
+
+ widths = new float[space + 1];
+ tags = tag;
+ }
+
+ #endregion // Constructors
+
+ #region Internal Properties
+ internal HorizontalAlignment Alignment {
+ get { return alignment; }
+ set {
+ if (alignment != value) {
+ alignment = value;
+ recalc = true;
+ }
+ }
+ }
+
+ internal int HangingIndent {
+ get { return hanging_indent; }
+ set {
+ hanging_indent = value;
+ recalc = true;
+ }
+ }
+
+ // UIA: Method used via reflection in TextRangeProvider
+ internal int Height {
+ get { return height; }
+ set { height = value; }
+ }
+
+ internal int Indent {
+ get { return indent; }
+ set {
+ indent = value;
+ recalc = true;
+ }
+ }
+
+ internal int LineNo {
+ get { return line_no; }
+ set { line_no = value; }
+ }
+
+ internal int RightIndent {
+ get { return right_indent; }
+ set {
+ right_indent = value;
+ recalc = true;
+ }
+ }
+
+ // UIA: Method used via reflection in TextRangeProvider
+ internal int Width {
+ get {
+ int res = (int) widths [text.Length];
+ return res;
+ }
+ }
+
+ internal string Text {
+ get { return text.ToString(); }
+ set {
+ int prev_length = text.Length;
+ text = new StringBuilder(value, value.Length > DEFAULT_TEXT_LEN ? value.Length + 1 : DEFAULT_TEXT_LEN);
+
+ if (text.Length > prev_length)
+ Grow (text.Length - prev_length);
+ }
+ }
+
+ // UIA: Method used via reflection in TextRangeProvider
+ internal int X {
+ get {
+ if (document.multiline)
+ return align_shift;
+ return offset + align_shift;
+ }
+ }
+
+ // UIA: Method used via reflection in TextRangeProvider
+ internal int Y {
+ get {
+ if (!document.multiline)
+ return document.top_margin;
+ return document.top_margin + offset;
+ }
+ }
+ #endregion // Internal Properties
+
+ #region Internal Methods
+
+ /// <summary>
+ /// Builds a simple code to record which tags are links and how many tags
+ /// used to compare lines before and after to see if the scan for links
+ /// process has changed anything.
+ /// </summary>
+ internal void LinkRecord (StringBuilder linkRecord)
+ {
+ LineTag tag = tags;
+
+ while (tag != null) {
+ if (tag.IsLink)
+ linkRecord.Append ("L");
+ else
+ linkRecord.Append ("N");
+
+ tag = tag.Next;
+ }
+ }
+
+ /// <summary>
+ /// Clears all link properties from tags
+ /// </summary>
+ internal void ClearLinks ()
+ {
+ LineTag tag = tags;
+
+ while (tag != null) {
+ tag.IsLink = false;
+ tag = tag.Next;
+ }
+ }
+
+ public void DeleteCharacters(int pos, int count)
+ {
+ LineTag tag;
+ bool streamline = false;
+
+ // Can't delete more than the line has
+ if (pos >= text.Length)
+ return;
+
+ // Find the first tag that we are deleting from
+ tag = FindTag (pos + 1);
+
+ // Remove the characters from the line
+ text.Remove (pos, count);
+
+ if (tag == null)
+ return;
+
+ // Check if we're crossing tag boundaries
+ if ((pos + count) > (tag.Start + tag.Length - 1)) {
+ int left;
+
+ // We have to delete cross tag boundaries
+ streamline = true;
+ left = count;
+
+ left -= tag.Start + tag.Length - pos - 1;
+ tag = tag.Next;
+
+ // Update the start of each tag
+ while ((tag != null) && (left > 0)) {
+ // Cache tag.Length as is will be indireclty modified
+ // by changes to tag.Start
+ int tag_length = tag.Length;
+ tag.Start -= count - left;
+
+ if (tag_length > left) {
+ left = 0;
+ } else {
+ left -= tag_length;
+ tag = tag.Next;
+ }
+
+ }
+ } else {
+ // We got off easy, same tag
+
+ if (tag.Length == 0)
+ streamline = true;
+ }
+
+ // Delete empty orphaned tags at the end
+ LineTag walk = tag;
+ while (walk != null && walk.Next != null && walk.Next.Length == 0) {
+ LineTag t = walk;
+ walk.Next = walk.Next.Next;
+ if (walk.Next != null)
+ walk.Next.Previous = t;
+ walk = walk.Next;
+ }
+
+ // Adjust the start point of any tags following
+ if (tag != null) {
+ tag = tag.Next;
+ while (tag != null) {
+ tag.Start -= count;
+ tag = tag.Next;
+ }
+ }
+
+ recalc = true;
+
+ if (streamline)
+ Streamline (document.Lines);
+ }
+
+ // This doesn't do exactly what you would think, it just pulls off the \n part of the ending
+ internal void DrawEnding (Graphics dc, float y)
+ {
+ if (document.multiline)
+ return;
+ LineTag last = tags;
+ while (last.Next != null)
+ last = last.Next;
+
+ string end_str = null;
+ switch (document.LineEndingLength (ending)) {
+ case 0:
+ return;
+ case 1:
+ end_str = "\u0013";
+ break;
+ case 2:
+ end_str = "\u0013\u0013";
+ break;
+ case 3:
+ end_str = "\u0013\u0013\u0013";
+ break;
+ }
+
+ TextBoxTextRenderer.DrawText (dc, end_str, last.Font, last.Color, X + widths [TextLengthWithoutEnding ()] - document.viewport_x + document.OffsetX, y, true);
+ }
+
+ /// <summary> Find the tag on a line based on the character position, pos is 0-based</summary>
+ internal LineTag FindTag (int pos)
+ {
+ LineTag tag;
+
+ if (pos == 0)
+ return tags;
+
+ tag = this.tags;
+
+ if (pos >= text.Length)
+ pos = text.Length - 1;
+
+ while (tag != null) {
+ if (((tag.Start - 1) <= pos) && (pos <= (tag.Start + tag.Length - 1)))
+ return LineTag.GetFinalTag (tag);
+
+ tag = tag.Next;
+ }
+
+ return null;
+ }
+
+ public override int GetHashCode ()
+ {
+ return base.GetHashCode ();
+ }
+
+ // Get the tag that contains this x coordinate
+ public LineTag GetTag (int x)
+ {
+ LineTag tag = tags;
+
+ // Coord is to the left of the first character
+ if (x < tag.X)
+ return LineTag.GetFinalTag (tag);
+
+ // All we have is a linked-list of tags, so we have
+ // to do a linear search. But there shouldn't be
+ // too many tags per line in general.
+ while (true) {
+ if (x >= tag.X && x < (tag.X + tag.Width))
+ return tag;
+
+ if (tag.Next != null)
+ tag = tag.Next;
+ else
+ return LineTag.GetFinalTag (tag);
+ }
+ }
+
+ // Make sure we always have enoughs space in text and widths
+ internal void Grow (int minimum)
+ {
+ int length;
+ float[] new_widths;
+
+ length = text.Length;
+
+ if ((length + minimum) > space) {
+ // We need to grow; double the size
+
+ if ((length + minimum) > (space * 2)) {
+ new_widths = new float[length + minimum * 2 + 1];
+ space = length + minimum * 2;
+ } else {
+ new_widths = new float[space * 2 + 1];
+ space *= 2;
+ }
+ widths.CopyTo (new_widths, 0);
+
+ widths = new_widths;
+ }
+ }
+ public void InsertString (int pos, string s)
+ {
+ InsertString (pos, s, FindTag (pos));
+ }
+
+ // Inserts a string at the given position
+ public void InsertString (int pos, string s, LineTag tag)
+ {
+ int len = s.Length;
+
+ // Insert the text into the StringBuilder
+ text.Insert (pos, s);
+
+ // Update the start position of every tag after this one
+ tag = tag.Next;
+
+ while (tag != null) {
+ tag.Start += len;
+ tag = tag.Next;
+ }
+
+ // Make sure we have room in the widths array
+ Grow (len);
+
+ // This line needs to be recalculated
+ recalc = true;
+ }
+
+ /// <summary>
+ /// Go through all tags on a line and recalculate all size-related values;
+ /// returns true if lineheight changed
+ /// </summary>
+ internal bool RecalculateLine (Graphics g, Document doc)
+ {
+ return RecalculateLine (g, doc, kerning_fonts.ContainsKey (tags.Font.GetHashCode ()));
+ }
+
+ private bool RecalculateLine (Graphics g, Document doc, bool handleKerning)
+ {
+ LineTag tag;
+ int pos;
+ int len;
+ SizeF size;
+ float w;
+ int prev_offset;
+ bool retval;
+ bool wrapped;
+ Line line;
+ int wrap_pos;
+ int prev_height;
+ int prev_ascent;
+
+ pos = 0;
+ len = this.text.Length;
+ tag = this.tags;
+ prev_offset = this.offset; // For drawing optimization calculations
+ prev_height = this.height;
+ prev_ascent = this.ascent;
+ this.height = 0; // Reset line height
+ this.ascent = 0; // Reset the ascent for the line
+ tag.Shift = 0; // Reset shift (which should be stored as pixels, not as points)
+
+ if (ending == LineEnding.Wrap)
+ widths[0] = document.left_margin + hanging_indent;
+ else
+ widths[0] = document.left_margin + indent;
+
+ this.recalc = false;
+ retval = false;
+ wrapped = false;
+
+ wrap_pos = 0;
+
+ while (pos < len) {
+
+ while (tag.Length == 0) { // We should always have tags after a tag.length==0 unless len==0
+ //tag.Ascent = 0;
+ tag.Shift = (tag.Line.ascent - tag.Ascent) / 72;
+ tag = tag.Next;
+ }
+
+ // kerning is a problem. The original code in this method assumed that the
+ // width of a string equals the sum of the widths of its characters. This is
+ // not true when kerning takes place during the display process. Since it's
+ // impossible to find out easily whether a font does kerning, and with which
+ // characters, we just detect that kerning must have happened and use a slower
+ // (but accurate) measurement for those fonts henceforth. Without handling
+ // kerning, many fonts for English become unreadable during typing for many
+ // input strings, and text in many other languages is even worse trying to
+ // type in TextBoxes.
+ // See https://bugzilla.xamarin.com/show_bug.cgi?id=26478 for details.
+ float newWidth;
+ if (handleKerning && !Char.IsWhiteSpace(text[pos]))
+ {
+ // MeasureText doesn't measure trailing spaces, so we do the best we can for those
+ // in the else branch.
+ size = TextBoxTextRenderer.MeasureText (g, text.ToString (0, pos + 1), tag.Font);
+ newWidth = widths[0] + size.Width;
+ }
+ else
+ {
+ size = tag.SizeOfPosition (g, pos);
+ w = size.Width;
+ newWidth = widths[pos] + w;
+ }
+
+ if (Char.IsWhiteSpace (text[pos]))
+ wrap_pos = pos + 1;
+
+ if (doc.wrap) {
+ if ((wrap_pos > 0) && (wrap_pos != len) && (newWidth + 5) > (doc.viewport_width - this.right_indent)) {
+ // Make sure to set the last width of the line before wrapping
+ widths[pos + 1] = newWidth;
+
+ pos = wrap_pos;
+ len = text.Length;
+ doc.Split (this, tag, pos);
+ ending = LineEnding.Wrap;
+ len = this.text.Length;
+
+ retval = true;
+ wrapped = true;
+ } else if (pos > 1 && newWidth > (doc.viewport_width - this.right_indent)) {
+ // No suitable wrap position was found so break right in the middle of a word
+
+ // Make sure to set the last width of the line before wrapping
+ widths[pos + 1] = newWidth;
+
+ doc.Split (this, tag, pos);
+ ending = LineEnding.Wrap;
+ len = this.text.Length;
+ retval = true;
+ wrapped = true;
+ }
+ }
+
+ // Contract all wrapped lines that follow back into our line
+ if (!wrapped) {
+ pos++;
+
+ widths[pos] = newWidth;
+
+ if (pos == len) {
+ line = doc.GetLine (this.line_no + 1);
+ if ((line != null) && (ending == LineEnding.Wrap || ending == LineEnding.None)) {
+ // Pull the two lines together
+ doc.Combine (this.line_no, this.line_no + 1);
+ len = this.text.Length;
+ retval = true;
+ }
+ }
+ }
+
+ if (pos == (tag.Start - 1 + tag.Length)) {
+ // We just found the end of our current tag
+ tag.Height = tag.MaxHeight ();
+
+ // Check if we're the tallest on the line (so far)
+ if (tag.Height > this.height)
+ this.height = tag.Height; // Yep; make sure the line knows
+
+ if (tag.Ascent > this.ascent) {
+ LineTag t;
+
+ // We have a tag that has a taller ascent than the line;
+ t = tags;
+ while (t != null && t != tag) {
+ t.Shift = (tag.Ascent - t.Ascent) / 72;
+ t = t.Next;
+ }
+
+ // Save on our line
+ this.ascent = tag.Ascent;
+ } else {
+ tag.Shift = (this.ascent - tag.Ascent) / 72;
+ }
+
+ tag = tag.Next;
+ if (tag != null) {
+ tag.Shift = 0;
+ wrap_pos = pos;
+ }
+ }
+ }
+
+ var fullText = text.ToString();
+ if (!handleKerning && fullText.Length > 1 && !wrapped)
+ {
+ // Check whether kerning takes place for this string and font.
+ var realSize = TextBoxTextRenderer.MeasureText(g, fullText, tags.Font);
+ float realWidth = realSize.Width + widths[0];
+ // MeasureText ignores trailing whitespace, so we will too at this point.
+ int length = fullText.TrimEnd().Length;
+ float sumWidth = widths[length];
+ if (realWidth != sumWidth)
+ {
+ kerning_fonts.Add(tags.Font.GetHashCode (), true);
+ // Using a slightly incorrect width this time around isn't that bad. All that happens
+ // is that the cursor is a pixel or two off until the next character is typed. It's
+ // the accumulation of pixel after pixel that causes display problems.
+ }
+ }
+
+ while (tag != null) {
+ tag.Shift = (tag.Line.ascent - tag.Ascent) / 72;
+ tag = tag.Next;
+ }
+
+ if (this.height == 0) {
+ this.height = tags.Font.Height;
+ tags.Height = this.height;
+ tags.Shift = 0;
+ }
+
+ if (prev_offset != offset || prev_height != this.height || prev_ascent != this.ascent)
+ retval = true;
+
+ return retval;
+ }
+
+ /// <summary>
+ /// Recalculate a single line using the same char for every character in the line
+ /// </summary>
+ internal bool RecalculatePasswordLine (Graphics g, Document doc)
+ {
+ LineTag tag;
+ int pos;
+ int len;
+ float w;
+ bool ret;
+
+ pos = 0;
+ len = this.text.Length;
+ tag = this.tags;
+ ascent = 0;
+ tag.Shift = 0;
+
+ this.recalc = false;
+ widths[0] = document.left_margin + indent;
+
+ w = TextBoxTextRenderer.MeasureText (g, doc.password_char, tags.Font).Width;
+
+ if (this.height != (int)tag.Font.Height)
+ ret = true;
+ else
+ ret = false;
+
+ this.height = (int)tag.Font.Height;
+ tag.Height = this.height;
+
+ this.ascent = tag.Ascent;
+
+ while (pos < len) {
+ pos++;
+ widths[pos] = widths[pos - 1] + w;
+ }
+
+ return ret;
+ }
+
+ internal void Streamline (int lines)
+ {
+ LineTag current;
+ LineTag next;
+
+ current = this.tags;
+ next = current.Next;
+
+ //
+ // Catch what the loop below wont; eliminate 0 length
+ // tags, but only if there are other tags after us
+ // We only eliminate text tags if there is another text tag
+ // after it. Otherwise we wind up trying to type on picture tags
+ //
+ while ((current.Length == 0) && (next != null) && (next.IsTextTag)) {
+ tags = next;
+ tags.Previous = null;
+ current = next;
+ next = current.Next;
+ }
+
+
+ if (next == null)
+ return;
+
+ while (next != null) {
+ // Take out 0 length tags unless it's the last tag in the document
+ if (current.IsTextTag && next.Length == 0 && next.IsTextTag) {
+ if ((next.Next != null) || (line_no != lines)) {
+ current.Next = next.Next;
+ if (current.Next != null) {
+ current.Next.Previous = current;
+ }
+ next = current.Next;
+ continue;
+ }
+ }
+
+ if (current.Combine (next)) {
+ next = current.Next;
+ continue;
+ }
+
+ current = current.Next;
+ next = current.Next;
+ }
+ }
+
+ internal int TextLengthWithoutEnding ()
+ {
+ return text.Length - document.LineEndingLength (ending);
+ }
+
+ internal string TextWithoutEnding ()
+ {
+ return text.ToString (0, text.Length - document.LineEndingLength (ending));
+ }
+ #endregion // Internal Methods
+
+ #region Administrative
+ public object Clone ()
+ {
+ Line clone;
+
+ clone = new Line (document, ending);
+
+ clone.text = text;
+
+ if (left != null)
+ clone.left = (Line)left.Clone();
+
+ if (left != null)
+ clone.left = (Line)left.Clone();
+
+ return clone;
+ }
+
+ internal object CloneLine ()
+ {
+ Line clone;
+
+ clone = new Line (document, ending);
+
+ clone.text = text;
+
+ return clone;
+ }
+
+ public int CompareTo (object obj)
+ {
+ if (obj == null)
+ return 1;
+
+ if (! (obj is Line))
+ throw new ArgumentException("Object is not of type Line", "obj");
+
+ if (line_no < ((Line)obj).line_no)
+ return -1;
+ else if (line_no > ((Line)obj).line_no)
+ return 1;
+ else
+ return 0;
+ }
+
+ public override bool Equals (object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (!(obj is Line))
+ return false;
+
+ if (obj == this)
+ return true;
+
+ if (line_no == ((Line)obj).line_no)
+ return true;
+
+ return false;
+ }
+
+ public override string ToString()
+ {
+ return string.Format ("Line {0}", line_no);
+ }
+ #endregion // Administrative
+ }
+}
diff --git a/source/ShiftUI/Internal/LineTag.cs b/source/ShiftUI/Internal/LineTag.cs
new file mode 100644
index 0000000..e34132c
--- /dev/null
+++ b/source/ShiftUI/Internal/LineTag.cs
@@ -0,0 +1,618 @@
+// 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-2006 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Drawing.Text;
+using System.Text;
+
+namespace ShiftUI
+{
+ internal class LineTag
+ {
+ #region Local Variables
+ // Formatting
+ private Font font; // System.Drawing.Font object for this tag
+ private Color color; // The font color for this tag
+ private Color back_color; // In 2.0 tags can have background colours.
+ private Font link_font; // Cached font used for link if IsLink
+ private bool is_link; // Whether this tag is a link
+ private string link_text; // The full link text e.g. this might be
+ // word-wrapped to "w" but this would be
+ // "www.mono-project.com"
+
+ // Payload; text
+ private int start; // start, in chars; index into Line.text
+ // 1 based!!
+
+ // Drawing support
+ private int height; // Height in pixels of the text this tag describes
+ private int ascent; // Ascent of the font for this tag
+ private int descent; // Descent of the font for this tag
+ private int shift; // Shift down for this tag, to stay on baseline
+
+ // Administrative
+ private Line line; // The line we're on
+ private LineTag next; // Next tag on the same line
+ private LineTag previous; // Previous tag on the same line
+ #endregion
+
+ #region Constructors
+ public LineTag (Line line, int start)
+ {
+ this.line = line;
+ Start = start;
+ link_font = null;
+ is_link = false;
+ link_text = null;
+ }
+ #endregion // Constructors
+
+ #region Public Properties
+ public int Ascent {
+ get { return ascent; }
+ }
+
+ public Color BackColor {
+ get { return back_color; }
+ set { back_color = value; }
+ }
+
+ public Color ColorToDisplay {
+ get {
+ if (IsLink == true)
+ return Color.Blue;
+
+ return color;
+ }
+ }
+
+ public Color Color {
+ get { return color; }
+ set { color = value; }
+ }
+
+ public int Descent {
+ get { return descent; }
+ }
+
+ public int End {
+ get { return start + Length; }
+ }
+
+ public Font FontToDisplay {
+ get {
+ if (IsLink) {
+ if (link_font == null)
+ link_font = new Font (font.FontFamily, font.Size, font.Style | FontStyle.Underline);
+
+ return link_font;
+ }
+
+ return font;
+ }
+ }
+
+ public Font Font {
+ get { return font; }
+ set {
+ if (font != value) {
+ link_font = null;
+ font = value;
+
+ height = Font.Height;
+ XplatUI.GetFontMetrics (Hwnd.GraphicsContext, Font, out ascent, out descent);
+ line.recalc = true;
+ }
+ }
+ }
+
+ public int Height {
+ get { return height; }
+ set { height = value; }
+ }
+
+ public virtual bool IsTextTag {
+ get { return true; }
+ }
+
+ public int Length {
+ get {
+ int res = 0;
+ if (next != null)
+ res = next.start - start;
+ else
+ res = line.text.Length - (start - 1);
+
+ return res > 0 ? res : 0;
+ }
+ }
+
+ public Line Line {
+ get { return line; }
+ set { line = value; }
+ }
+
+ public LineTag Next {
+ get { return next; }
+ set { next = value; }
+ }
+
+ public LineTag Previous {
+ get { return previous; }
+ set { previous = value; }
+ }
+
+ public int Shift {
+ get { return shift; }
+ set { shift = value; }
+ }
+
+ public int Start {
+ get { return start; }
+ set {
+#if DEBUG
+ if (value <= 0)
+ throw new Exception("Start of tag must be 1 or higher!");
+
+ if (this.Previous != null) {
+ if (this.Previous.Start == value)
+ System.Console.Write("Creating empty tag");
+ if (this.Previous.Start > value)
+ throw new Exception("New tag makes an insane tag");
+ }
+#endif
+ start = value;
+ }
+ }
+
+ public int TextEnd {
+ get { return start + TextLength; }
+ }
+
+ public int TextLength {
+ get {
+ int res = 0;
+ if (next != null)
+ res = next.start - start;
+ else
+ res = line.TextLengthWithoutEnding () - (start - 1);
+
+ return res > 0 ? res : 0;
+ }
+ }
+
+ public float Width {
+ get {
+ if (Length == 0)
+ return 0;
+ return line.widths [start + Length - 1] - (start != 0 ? line.widths [start - 1] : 0);
+ }
+ }
+
+ public float X {
+ get {
+ if (start == 0)
+ return line.X;
+ return line.X + line.widths [start - 1];
+ }
+ }
+
+ public bool IsLink {
+ get { return is_link; }
+ set { is_link = value; }
+ }
+
+ public string LinkText {
+ get { return link_text; }
+ set { link_text = value; }
+ }
+ #endregion
+
+ #region Public Methods
+ ///<summary>Break a tag into two with identical attributes; pos is 1-based; returns tag starting at &gt;pos&lt; or null if end-of-line</summary>
+ public LineTag Break (int pos)
+ {
+ LineTag new_tag;
+
+#if DEBUG
+ // Sanity
+ if (pos < this.Start)
+ throw new Exception ("Breaking at a negative point");
+#endif
+
+#if DEBUG
+ if (pos > End)
+ throw new Exception ("Breaking past the end of a line");
+#endif
+
+ new_tag = new LineTag(line, pos);
+ new_tag.CopyFormattingFrom (this);
+
+ new_tag.next = this.next;
+ this.next = new_tag;
+ new_tag.previous = this;
+
+ if (new_tag.next != null)
+ new_tag.next.previous = new_tag;
+
+ return new_tag;
+ }
+
+ /// <summary>Combines 'this' tag with 'other' tag</summary>
+ public bool Combine (LineTag other)
+ {
+ if (!this.Equals (other))
+ return false;
+
+ this.next = other.next;
+
+ if (this.next != null)
+ this.next.previous = this;
+
+ return true;
+ }
+
+ public void CopyFormattingFrom (LineTag other)
+ {
+ Font = other.font;
+ color = other.color;
+ back_color = other.back_color;
+ }
+
+ public void Delete ()
+ {
+ // If we are the only tag, we can't be deleted
+ if (previous == null && next == null)
+ return;
+
+ // If we are the last tag, deletion is easy
+ if (next == null) {
+ previous.next = null;
+ return;
+ }
+
+ // Easy cases gone, little tougher, delete ourself
+ // Update links, and start
+ next.previous = null;
+
+ LineTag loop = next;
+
+ while (loop != null) {
+ loop.Start -= Length;
+ loop = loop.next;
+ }
+
+ return;
+ }
+
+ public virtual void Draw (Graphics dc, Color color, float x, float y, int start, int end)
+ {
+ TextBoxTextRenderer.DrawText (dc, line.text.ToString (start, end).Replace ("\r", string.Empty), FontToDisplay, color, x, y, false);
+ }
+
+ public virtual void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, string text)
+ {
+ Rectangle measured_text;
+ Draw (dc, color, xoff, y, start, end, text, out measured_text, false);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="drawStart">0 based start index</param>
+ public virtual void Draw (Graphics dc, Color color, float xoff, float y, int drawStart, int drawEnd,
+ string text, out Rectangle measuredText, bool measureText)
+ {
+ if (measureText) {
+ int xstart = (int)line.widths [drawStart] + (int)xoff;
+ int xend = (int)line.widths [drawEnd] - (int)line.widths [drawStart];
+ int ystart = (int)y;
+ int yend = (int)TextBoxTextRenderer.MeasureText (dc, Text (), FontToDisplay).Height;
+
+ measuredText = new Rectangle (xstart, ystart, xend, yend);
+ } else {
+ measuredText = new Rectangle ();
+ }
+
+ while (drawStart < drawEnd) {
+ int tab_index = text.IndexOf ("\t", drawStart);
+
+ if (tab_index == -1)
+ tab_index = drawEnd;
+
+ TextBoxTextRenderer.DrawText (dc, text.Substring (drawStart, tab_index - drawStart).Replace ("\r", string.Empty), FontToDisplay, color, xoff + line.widths [drawStart], y, false);
+
+ // non multilines get the unknown char
+ if (!line.document.multiline && tab_index != drawEnd)
+ TextBoxTextRenderer.DrawText (dc, "\u0013", FontToDisplay, color, xoff + line.widths [tab_index], y, true);
+
+ drawStart = tab_index + 1;
+ }
+ }
+
+ /// <summary>Checks if 'this' tag describes the same formatting options as 'obj'</summary>
+ public override bool Equals (object obj)
+ {
+ LineTag other;
+
+ if (obj == null)
+ return false;
+
+ if (!(obj is LineTag))
+ return false;
+
+ if (obj == this)
+ return true;
+
+ other = (LineTag)obj;
+
+ if (other.IsTextTag != IsTextTag)
+ return false;
+
+ if (this.IsLink != other.IsLink)
+ return false;
+
+ if (this.LinkText != other.LinkText)
+ return false;
+
+ if (this.font.Equals (other.font) && this.color.Equals (other.color))
+ return true;
+
+ return false;
+ }
+
+ /// <summary>Finds the tag that describes the character at position 'pos' (0 based) on 'line'</summary>
+ public static LineTag FindTag (Line line, int pos)
+ {
+ LineTag tag = line.tags;
+
+ // Beginning of line is a bit special
+ if (pos == 0)
+ return tag; // Not sure if we should get the final tag here
+
+ while (tag != null) {
+ // [H e][l][l o _ W][o r] Text
+ // [1 2][3][4 5 6 7][8 9] Start
+ // 3 4 8 10 End
+ // 0 1 2 3 4 5 6 7 8 9 Pos
+ if ((tag.start <= pos) && (pos < tag.End))
+ return GetFinalTag (tag);
+
+ tag = tag.next;
+ }
+
+ return null;
+ }
+
+ /// <summary>Applies 'font' and 'brush' to characters starting at 'start' for 'length' chars;
+ /// Removes any previous tags overlapping the same area;
+ /// returns true if lineheight has changed</summary>
+ /// <param name="formatStart">1-based character position on line</param>
+ public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor, FormatSpecified specified)
+ {
+ LineTag tag;
+ LineTag start_tag;
+ LineTag end_tag;
+ int end;
+ bool retval = false; // Assume line-height doesn't change
+
+ // Too simple?
+ if (((FormatSpecified.Font & specified) == FormatSpecified.Font) && font.Height != line.height)
+ retval = true;
+
+ line.recalc = true; // This forces recalculation of the line in RecalculateDocument
+
+ // A little sanity, not sure if it's needed, might be able to remove for speed
+ if (length > line.text.Length)
+ length = line.text.Length;
+
+ tag = line.tags;
+ end = formatStart + length;
+
+ // Common special case
+ if ((formatStart == 1) && (length == tag.Length)) {
+ SetFormat (tag, font, color, backColor, specified);
+ return retval;
+ }
+
+ // empty selection style at begining of line means
+ // we only need one new tag
+ if (formatStart == 1 && length == 0) {
+ line.tags.Break (1);
+ SetFormat (line.tags, font, color, backColor, specified);
+ return retval;
+ }
+
+ start_tag = FindTag (line, formatStart - 1);
+
+ // we are at an empty tag already!
+ // e.g. [Tag 0 - "He"][Tag 1 = 0 length][Tag 2 "llo world"]
+ // Find Tag will return tag 0 at position 3, but we should just
+ // use the empty tag after..
+ if (start_tag.End == formatStart && length == 0 && start_tag.Next != null && start_tag.Next.Length == 0) {
+ SetFormat (start_tag.Next, font, color, backColor, specified);
+ return retval;
+ }
+
+ // if we are at the end of a tag, we want to move to the next tag
+ while (start_tag.End == formatStart && start_tag.Next != null)
+ start_tag = start_tag.Next;
+
+ tag = start_tag.Break (formatStart);
+
+ // empty selection style at end of line - its the only situation
+ // where the rest of the tag would be empty, since we moved to the
+ // begining of next non empty tag
+ if (tag.Length == 0) {
+ SetFormat (tag, font, color, backColor, specified);
+ return retval;
+ }
+
+ // empty - so we just create another tag for
+ // after our new (now) empty one..
+ if (length == 0) {
+ tag.Break (formatStart);
+ SetFormat (tag, font, color, backColor, specified);
+ return retval;
+ }
+
+ while (tag != null && tag.End <= end) {
+ SetFormat (tag, font, color, backColor, specified);
+ tag = tag.next;
+ }
+
+ // did the last tag conveniently fit?
+ if (tag != null && tag.End == end)
+ return retval;
+
+ /// Now do the last tag
+ end_tag = FindTag (line, end-1);
+
+ if (end_tag != null) {
+ end_tag.Break (end);
+ SetFormat (end_tag, font, color, backColor, specified);
+ }
+
+ return retval;
+ }
+
+ // Gets the character at the x-coordinate. Index is based from the
+ // line, not the start of the tag.
+ // returns 0 based index (0 means before character at 1, 1 means at character 1)
+ public int GetCharIndex (int x)
+ {
+ int low = start;
+ int high = low + Length;
+ int length_no_ending = line.TextLengthWithoutEnding ();
+
+ if (Length == 0)
+ return low-1;
+
+ if (length_no_ending == 0)
+ return 0;
+
+ if (x < line.widths [low]) {
+ if (low == 1 && x > (line.widths [1] / 2))
+ return low;
+ return low - 1;
+ }
+
+ if (x > line.widths[length_no_ending])
+ return length_no_ending;
+
+ while (low < high - 1) {
+ int mid = (high + low) / 2;
+ float width = line.widths[mid];
+
+ if (width < x)
+ low = mid;
+ else
+ high = mid;
+ }
+
+ float char_width = line.widths[high] - line.widths[low];
+
+ if ((x - line.widths[low]) >= (char_width / 2))
+ return high;
+ else
+ return low;
+ }
+
+ // There can be multiple tags at the same position, we want to make
+ // sure we are using the very last tag at the given position
+ // Empty tags are necessary if style is set at a position with
+ // no length.
+ public static LineTag GetFinalTag (LineTag tag)
+ {
+ LineTag res = tag;
+
+ while (res.Length == 0 && res.next != null && res.next.Length == 0)
+ res = res.next;
+
+ return res;
+ }
+
+ public override int GetHashCode ()
+ {
+ return base.GetHashCode ();
+ }
+
+ internal virtual int MaxHeight ()
+ {
+ return font.Height;
+ }
+
+ private static void SetFormat (LineTag tag, Font font, Color color, Color back_color, FormatSpecified specified)
+ {
+ if ((FormatSpecified.Font & specified) == FormatSpecified.Font) {
+ tag.Font = font;
+ }
+ if ((FormatSpecified.Color & specified) == FormatSpecified.Color)
+ tag.color = color;
+ if ((FormatSpecified.BackColor & specified) == FormatSpecified.BackColor) {
+ tag.back_color = back_color;
+ }
+ // Console.WriteLine ("setting format: {0} {1} new color {2}", color.Color, specified, tag.color.Color);
+ }
+
+ public virtual SizeF SizeOfPosition (Graphics dc, int pos)
+ {
+ if (pos >= line.TextLengthWithoutEnding () && line.document.multiline)
+ return SizeF.Empty;
+
+ string text = line.text.ToString (pos, 1);
+ switch ((int) text [0]) {
+ case '\t':
+ if (!line.document.multiline)
+ goto case 10;
+ SizeF res = TextBoxTextRenderer.MeasureText (dc, " ", font);
+ res.Width *= 8.0F;
+ return res;
+ case 10:
+ case 13:
+ return TextBoxTextRenderer.MeasureText (dc, "\u000D", font);
+ }
+
+ return TextBoxTextRenderer.MeasureText (dc, text, font);
+ }
+
+ public virtual string Text ()
+ {
+ return line.text.ToString (start - 1, Length);
+ }
+
+ public override string ToString ()
+ {
+ if (Length > 0)
+ return string.Format ("{0} Tag starts at index: {1}, length: {2}, text: {3}, font: {4}", GetType (), start, Length, Text (), font.ToString ());
+
+ return string.Format ("Zero Length tag at index: {0}", start);
+ }
+ #endregion // Internal Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ListBindingConverter.cs b/source/ShiftUI/Internal/ListBindingConverter.cs
new file mode 100644
index 0000000..46f39e5
--- /dev/null
+++ b/source/ShiftUI/Internal/ListBindingConverter.cs
@@ -0,0 +1,60 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// NOT COMPLETE
+
+using System.ComponentModel;
+using System;
+
+namespace ShiftUI {
+ public class ListBindingConverter : TypeConverter {
+ #region Public Constructors
+ public ListBindingConverter() {
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Methods
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
+ if (destinationType == typeof(string)) {
+ return true;
+ }
+ return base.CanConvertTo (context, destinationType);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues) {
+ return new Binding((string)propertyValues["PropertyName"], (object)propertyValues["DataSource"], (string)propertyValues["DataMember"]);
+ }
+
+ public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
+ return true;
+ }
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ListBindingHelper.cs b/source/ShiftUI/Internal/ListBindingHelper.cs
new file mode 100644
index 0000000..2615a33
--- /dev/null
+++ b/source/ShiftUI/Internal/ListBindingHelper.cs
@@ -0,0 +1,189 @@
+// 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) 2007 Novell, Inc.
+//
+// Author:
+// Carlos Alberto Cortez <[email protected]>
+// Ivan Zlatev <[email protected]>
+//
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Reflection;
+using System.Collections.Generic;
+
+namespace ShiftUI
+{
+
+ public static class ListBindingHelper
+ {
+ public static object GetList (object list)
+ {
+ if (list is IListSource)
+ return ((IListSource) list).GetList ();
+ return list;
+ }
+
+ public static object GetList (object dataSource, string dataMember)
+ {
+ dataSource = GetList (dataSource);
+ if (dataSource == null || dataMember == null || dataMember.Length == 0)
+ return dataSource;
+
+ PropertyDescriptor property = GetListItemProperties (dataSource).Find (dataMember, true);
+ if (property == null)
+ throw new ArgumentException ("dataMember");
+
+ object item = null;
+
+ ICurrencyManagerProvider currencyManagerProvider = dataSource as ICurrencyManagerProvider;
+ if (currencyManagerProvider != null && currencyManagerProvider.CurrencyManager != null) {
+ CurrencyManager currencyManager = currencyManagerProvider.CurrencyManager;
+ if (currencyManager != null && currencyManager.Count > 0 && currencyManager.Current != null)
+ item = currencyManager.Current;
+ }
+
+ if (item == null) {
+ if (dataSource is IEnumerable) {
+ if (dataSource is IList) {
+ IList list = (IList) dataSource;
+ item = list.Count > 0 ? list[0] : null;
+ } else {
+ IEnumerator e = ((IEnumerable) dataSource).GetEnumerator ();
+ if (e != null && e.MoveNext ())
+ item = e.Current;
+ }
+ } else {
+ item = dataSource;
+ }
+ }
+
+ if (item != null)
+ return property.GetValue (item);
+ return null;
+ }
+
+ public static Type GetListItemType (object list)
+ {
+ return GetListItemType (list, String.Empty);
+ }
+
+ public static Type GetListItemType (object dataSource, string dataMember)
+ {
+ if (dataSource == null)
+ return null;
+
+ if (dataMember != null && dataMember.Length > 0) {
+ PropertyDescriptor property = GetProperty (dataSource, dataMember);
+ if (property == null)
+ return typeof (object);
+
+ return property.PropertyType;
+ }
+
+ if (dataSource is Array)
+ return dataSource.GetType ().GetElementType ();
+
+ // IEnumerable seems to have higher precedence over IList
+ if (dataSource is IEnumerable) {
+ IEnumerator enumerator = ((IEnumerable) dataSource).GetEnumerator ();
+ if (enumerator.MoveNext () && enumerator.Current != null)
+ return enumerator.Current.GetType ();
+
+ if (dataSource is IList || dataSource.GetType () == typeof (IList<>)) {
+ PropertyInfo property = GetPropertyByReflection (dataSource.GetType (), "Item");
+ if (property != null) // `Item' could be interface-explicit, and thus private
+ return property.PropertyType;
+ }
+
+ // fallback to object
+ return typeof (object);
+ }
+
+ return dataSource.GetType ();
+ }
+
+ public static PropertyDescriptorCollection GetListItemProperties (object list)
+ {
+ return GetListItemProperties (list, null);
+ }
+
+ public static PropertyDescriptorCollection GetListItemProperties (object list, PropertyDescriptor [] listAccessors)
+ {
+ list = GetList (list);
+
+ if (list == null)
+ return new PropertyDescriptorCollection (null);
+
+ if (list is ITypedList)
+ return ((ITypedList)list).GetItemProperties (listAccessors);
+
+ if (listAccessors == null || listAccessors.Length == 0) {
+ Type item_type = GetListItemType (list);
+ return TypeDescriptor.GetProperties (item_type,
+ new Attribute [] { new BrowsableAttribute (true) });
+ }
+
+ // Take into account only the first property
+ Type property_type = listAccessors [0].PropertyType;
+ if (typeof (IList).IsAssignableFrom (property_type) || typeof (IList<>).IsAssignableFrom (property_type)) {
+
+ PropertyInfo property = GetPropertyByReflection (property_type, "Item");
+ return TypeDescriptor.GetProperties (property.PropertyType);
+ }
+
+ return new PropertyDescriptorCollection (new PropertyDescriptor [0]);
+ }
+
+ public static PropertyDescriptorCollection GetListItemProperties (object dataSource, string dataMember,
+ PropertyDescriptor [] listAccessors)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static string GetListName (object list, PropertyDescriptor [] listAccessors)
+ {
+ if (list == null)
+ return String.Empty;
+
+ Type item_type = GetListItemType (list);
+ return item_type.Name;
+ }
+
+ static PropertyDescriptor GetProperty (object obj, string property_name)
+ {
+ return TypeDescriptor.GetProperties (obj,
+ new Attribute [] { new BrowsableAttribute (true) })[property_name];
+ }
+
+ //
+ // Need to use reflection as we need to bypass the TypeDescriptor.GetProperties () limitations
+ //
+ static PropertyInfo GetPropertyByReflection (Type type, string property_name)
+ {
+ foreach (PropertyInfo prop in type.GetProperties (BindingFlags.Public | BindingFlags.Instance))
+ if (prop.Name == property_name)
+ return prop;
+
+ return null;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/MONO-NOTES b/source/ShiftUI/Internal/MONO-NOTES
new file mode 100644
index 0000000..2775bb9
--- /dev/null
+++ b/source/ShiftUI/Internal/MONO-NOTES
@@ -0,0 +1,28 @@
+Application.Idle is invoked on the same thread used to add the event
+
+our hacky double buffering only works on the client area, not the nc
+area. need to move to a more XplatUI solution involving server-side
+drawing surfaces (pixmaps in the X case).
+
+right now the expose/configure event aggregating is done in the
+XEventThread (in the hwnd code, but in the thread running the x event
+loop). There is probably a way to get it to run in the thread doing
+GetMessage, probably by making GetMessage know about both the xevent
+and paint queue's, and having it consume the x queue until there's
+nothing left, doing the AddExpose stuff there. then, once the xqueue
+is empty, consume the paint queue. This has the added benefit of
+making the paint queue a ThreadQueue local thing - no locking will be
+needed on it, since the only thing touching it will be the thread
+running the message pump.
+
+why do we /nowarn:108? we lose tons of possibly important warnings due to that...
+
+more event work:
+
+CheckedListBox: nothing done.
+DataGridView*: nothing done.
+GridColumnStylesCollection: nothing done, no Component inheritance
+GridTableStylesCollection: nothing done, no Component inheritance
+MenuItem: what do we do about CloneMenu? we can't have assignment of events like that (look for the #if notyet)
+MonthCalendar: nothing done.
+Panel: nothing done. see whether the events should be "new" or now..
diff --git a/source/ShiftUI/Internal/MONO-TODO b/source/ShiftUI/Internal/MONO-TODO
new file mode 100644
index 0000000..76397d0
--- /dev/null
+++ b/source/ShiftUI/Internal/MONO-TODO
@@ -0,0 +1,112 @@
+plans for XplatUIX11.cs:
+
+ - 1 thread watching X socket, doing nothing but
+ XNextEvent/hwnd.Queue.Enqueue (with minimal motion
+ compression/key repeat detection)
+
+ - figure out how to deal with the selection events, since they
+ busy loop waiting on a response from the X socket. maybe
+ block that thread with an event and wake it up when the
+ event thread get enough info?
+
+ - Idle event raised once regardless of how many thread queues
+ we have (should it come from the X event thread?)
+
+ - X11Hwnd which caches (amongst other things) the properties
+ for the toplevel window so we can avoid doing all those
+ XChangeProperty things on every single UpdateStyle call.
+
+ - have RULES for things (like "do not call this function
+ except from ...", etc) and make sure they're enforced.
+
+ - SendMessage.. can't we just insert the right message on the
+ hwnd's queue instead of using SendAsyncMethod?
+
+ - what's the difference between PostMessage and SendMessage?
+
+ - clean up the MESS that is:
+ GetWindowState
+ SetWindowState
+
+ and especially:
+ SetHwndStyles
+ SetWMStyles
+ DeriveStyles
+ the Style handling in CreateWindow
+
+ - multiple screens? do we care? xinerama foo?
+
+ - fix the mostly static, somewhat instance nature of
+ XplatUIX11.cs. Either make it static, or make it an
+ instance.
+
+ - we need to rethink the expose event handling. right now
+ expose events are only handled once all the other events in
+ the queue are handled. So, if you're resizing quickly you
+ get no redraws until you're done. maybe look at the
+ _NET_WM_SYNC_REQUEST protocol (for the resize/redraw case
+ specifically). Also, the current expose handling has us
+ accessing the invalid list/rectangle from multiple threads.
+
+ - factor out ALL knowledge of the multiple windows
+ (client/whole) into the X11Hwnd class, so we can try to
+ factor it out.
+
+ - clean up the systray icon stuff - right now it destroys (!)
+ the client_window and sets client_window == whole_window.
+ ugh.
+
+ - hwnds should keep track of the width/height they report to
+ SWF as well as the x window's width/height. That is, we
+ should allow hwnds with 0,0 width/height even though X
+ doesn't allow it. There's some "zero_size" stuff in Hwnd,
+ but it still appears impossible to have 0,0 sized Widgets.
+
+ - window (subwindow, really) destruction should move to Hwnd
+ if possible.
+
+ - remove 90% of "lock (XlibLock)" usage. It's not really
+ needed at all, except perhaps to synchronize the
+ XEventThread and the PeekMessage/GetMessage methods.
+
+ - the big synchronization problem now is the XEventQueue
+ class. I think all queue operations need to be done while
+ holding a lock, as the events are queued from the
+ XEventThread and dequeued from GetMessage.
+
+possible classes:
+
+ - XplatUIX11 (creates the first (only?) X11Display class.
+ Most calls should just get the hwnd/display and make a
+ method call)
+
+ - X11Display (manages the display handle, creates the event
+ thread, keeps ref to an X11Atoms and the X11RootHwnd)
+
+ - XEventThread (does this need to be a separate class? can
+ probably just be a method in X11Display)
+
+ - X11Hwnd (move all the style translation here? handles
+ property changes and caches them. window title here too)
+
+ - X11RootHwnd (add the special root window property stuff
+ here)
+
+ - X11Atoms (per display atom list. should these be properties
+ or fields? fields probably, with the builtins as constants).
+
+ - Xlib (the pinvoke wrapper for Xlib calls)
+
+window managers we need to test again:
+
+ - metacity on SLED/SUSE
+ - metacity on ubuntu edgy
+ - compiz on SLED
+ - compiz HEAD
+ - beryl? or should compiz be enough?
+
+specs:
+
+Extended Window Manager Hints: http://standards.freedesktop.org/wm-spec/wm-spec-latest.html
+XEmbed spec: http://standards.freedesktop.org/xembed-spec/latest/
+Systray spec: http://standards.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html
diff --git a/source/ShiftUI/Internal/MWFCategoryAttribute.cs b/source/ShiftUI/Internal/MWFCategoryAttribute.cs
new file mode 100644
index 0000000..5e348f1
--- /dev/null
+++ b/source/ShiftUI/Internal/MWFCategoryAttribute.cs
@@ -0,0 +1,50 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System.ComponentModel;
+using ShiftUI;
+
+namespace System {
+ [AttributeUsage (AttributeTargets.All, AllowMultiple=false)]
+ internal sealed class MWFCategoryAttribute : System.ComponentModel.CategoryAttribute {
+ #region Constructors
+ public MWFCategoryAttribute() : base() {
+ }
+
+ public MWFCategoryAttribute(string category) : base(category) {
+ }
+ #endregion // Constructors
+
+ #region Methods
+ protected override string GetLocalizedString(string value) {
+ return String.Format(value);
+ }
+
+ #endregion // Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/MWFDescriptionAttribute.cs b/source/ShiftUI/Internal/MWFDescriptionAttribute.cs
new file mode 100644
index 0000000..38ac348
--- /dev/null
+++ b/source/ShiftUI/Internal/MWFDescriptionAttribute.cs
@@ -0,0 +1,51 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System.ComponentModel;
+using ShiftUI;
+
+namespace System {
+ [AttributeUsage (AttributeTargets.All, AllowMultiple=false)]
+ internal sealed class MWFDescriptionAttribute : System.ComponentModel.DescriptionAttribute {
+ #region Constructors
+ public MWFDescriptionAttribute() : base() {
+ }
+
+ public MWFDescriptionAttribute(string category) : base(category) {
+ }
+ #endregion // Constructors
+
+ #region Properties
+ public override string Description {
+ get {
+ return String.Format(base.Description);
+ }
+ }
+ #endregion // Properties
+ }
+}
diff --git a/source/ShiftUI/Internal/MainMenu.cs b/source/ShiftUI/Internal/MainMenu.cs
new file mode 100644
index 0000000..2bb0f3f
--- /dev/null
+++ b/source/ShiftUI/Internal/MainMenu.cs
@@ -0,0 +1,216 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+//
+//
+
+// COMPLETE
+
+using System.ComponentModel;
+using System.Drawing;
+using System;
+
+namespace ShiftUI
+{
+ [ToolboxItemFilter("ShiftUI.MainMenu", ToolboxItemFilterType.Allow)]
+ public class MainMenu : Menu
+ {
+ private RightToLeft right_to_left = RightToLeft.Inherit;
+ private Form form = null;
+
+ public MainMenu () : base (null)
+ {
+
+ }
+
+ public MainMenu (MenuItem[] items) : base (items)
+ {
+
+ }
+
+ public MainMenu (IContainer container) : this ()
+ {
+ container.Add (this);
+ }
+
+ #region Events
+
+ static object CollapseEvent = new object ();
+
+ public event EventHandler Collapse {
+ add { Events.AddHandler (CollapseEvent, value); }
+ remove { Events.RemoveHandler (CollapseEvent, value); }
+ }
+
+ #endregion Events
+
+ #region Public Properties
+ [Localizable(true)]
+ [AmbientValue (RightToLeft.Inherit)]
+ public virtual RightToLeft RightToLeft {
+ get { return right_to_left;}
+ set { right_to_left = value; }
+ }
+
+ #endregion Public Properties
+
+ #region Public Methods
+
+ public virtual MainMenu CloneMenu ()
+ {
+ MainMenu new_menu = new MainMenu ();
+ new_menu.CloneMenu (this);
+ return new_menu;
+ }
+
+ protected override IntPtr CreateMenuHandle ()
+ {
+ return IntPtr.Zero;
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ base.Dispose (disposing);
+ }
+
+ public Form GetForm ()
+ {
+ return form;
+ }
+
+ public override string ToString ()
+ {
+ return base.ToString () + ", GetForm: " + form;
+ }
+
+ protected internal virtual void OnCollapse (EventArgs e)
+ {
+ EventHandler eh = (EventHandler) (Events [CollapseEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ #endregion Public Methods
+
+ #region Private Methods
+
+ internal void Draw ()
+ {
+ Message m = Message.Create (Wnd.window.Handle, (int) Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+ PaintEventArgs pe = XplatUI.PaintEventStart (ref m, Wnd.window.Handle, false);
+ Draw (pe, Rect);
+ }
+
+ internal void Draw (Rectangle rect)
+ {
+ if (Wnd.IsHandleCreated) {
+ Point pt = XplatUI.GetMenuOrigin (Wnd.window.Handle);
+ Message m = Message.Create (Wnd.window.Handle, (int)Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+ PaintEventArgs pevent = XplatUI.PaintEventStart (ref m, Wnd.window.Handle, false);
+ pevent.Graphics.SetClip (new Rectangle (rect.X + pt.X, rect.Y + pt.Y, rect.Width, rect.Height));
+ Draw (pevent, Rect);
+ XplatUI.PaintEventEnd (ref m, Wnd.window.Handle, false);
+ }
+ }
+
+ internal void Draw (PaintEventArgs pe)
+ {
+ Draw (pe, Rect);
+ }
+
+ internal void Draw (PaintEventArgs pe, Rectangle rect)
+ {
+ if (!Wnd.IsHandleCreated)
+ return;
+
+ X = rect.X;
+ Y = rect.Y;
+ Height = Rect.Height;
+
+ ThemeEngine.Current.DrawMenuBar (pe.Graphics, this, rect);
+
+ PaintEventHandler eh = (PaintEventHandler)(Events [PaintEvent]);
+ if (eh != null)
+ eh (this, pe);
+ }
+
+ internal override void InvalidateItem (MenuItem item)
+ {
+ Draw (item.bounds);
+ }
+
+ internal void SetForm (Form form)
+ {
+ this.form = form;
+ Wnd = form;
+
+ if (tracker == null) {
+ tracker = new MenuTracker (this);
+ tracker.GrabControl = form;
+ }
+ }
+
+ internal override void OnMenuChanged (EventArgs e)
+ {
+ base.OnMenuChanged (EventArgs.Empty);
+ if (form == null)
+ return;
+
+ Rectangle clip = Rect;
+ Height = 0; /* need this so the theme code will re-layout the menu items
+ (why is the theme code doing the layout? argh) */
+
+ if (!Wnd.IsHandleCreated)
+ return;
+
+ Message m = Message.Create (Wnd.window.Handle, (int) Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+ PaintEventArgs pevent = XplatUI.PaintEventStart (ref m, Wnd.window.Handle, false);
+ pevent.Graphics.SetClip (clip);
+
+ Draw (pevent, clip);
+ }
+
+ /* Mouse events from the form */
+ internal void OnMouseDown (object window, MouseEventArgs args)
+ {
+ tracker.OnMouseDown (args);
+ }
+
+ internal void OnMouseMove (object window, MouseEventArgs e)
+ {
+ MouseEventArgs args = new MouseEventArgs (e.Button, e.Clicks, Widget.MousePosition.X, Widget.MousePosition.Y, e.Delta);
+ tracker.OnMotion (args);
+ }
+
+ static object PaintEvent = new object ();
+
+ internal event PaintEventHandler Paint {
+ add { Events.AddHandler (PaintEvent, value); }
+ remove { Events.RemoveHandler (PaintEvent, value); }
+ }
+
+ #endregion Private Methods
+ }
+}
+
+
diff --git a/source/ShiftUI/Internal/MdiClient.cs b/source/ShiftUI/Internal/MdiClient.cs
new file mode 100644
index 0000000..8c2cf8c
--- /dev/null
+++ b/source/ShiftUI/Internal/MdiClient.cs
@@ -0,0 +1,1003 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+// NOT COMPLETE
+
+using System.Collections;
+using System.ComponentModel;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI {
+ [ComVisible (true)]
+ [ClassInterface(ClassInterfaceType.AutoDispatch)]
+ [DesignTimeVisible(false)]
+ [ToolboxItem(false)]
+ public sealed class MdiClient : Widget {
+ #region Local Variables
+ private int mdi_created;
+ private ImplicitHScrollBar hbar;
+ private ImplicitVScrollBar vbar;
+ private SizeGrip sizegrip;
+ private int hbar_value;
+ private int vbar_value;
+ private bool lock_sizing;
+ private bool initializing_scrollbars;
+ private int prev_bottom;
+ private bool setting_windowstates = false;
+ internal ArrayList mdi_child_list;
+ private string form_text;
+ private bool setting_form_text;
+ private Form active_child;
+
+ #endregion // Local Variables
+
+ #region Public Classes
+ [ComVisible (false)]
+ public new class WidgetCollection : Widget.WidgetCollection {
+
+ private MdiClient owner;
+
+ public WidgetCollection(MdiClient owner) : base(owner) {
+ this.owner = owner;
+ }
+
+ public override void Add(Widget value) {
+ if ((value is Form) == false || !(((Form)value).IsMdiChild)) {
+ throw new ArgumentException("Form must be MdiChild");
+ }
+ owner.mdi_child_list.Add (value);
+ base.Add (value);
+
+ // newest member is the active one
+ Form form = (Form) value;
+ owner.ActiveMdiChild = form;
+ }
+
+ public override void Remove(Widget value)
+ {
+ Form form = value as Form;
+ if (form != null) {
+ MdiWindowManager wm = form.WindowManager as MdiWindowManager;
+ if (wm != null) {
+ form.Closed -= wm.form_closed_handler;
+ }
+ }
+
+ owner.mdi_child_list.Remove (value);
+ base.Remove (value);
+ }
+ }
+ #endregion // Public Classes
+
+ #region Public Constructors
+ public MdiClient()
+ {
+ mdi_child_list = new ArrayList ();
+ BackColor = SystemColors.AppWorkspace;
+ Dock = DockStyle.Fill;
+ SetStyle (Widgetstyles.Selectable, false);
+ }
+ #endregion // Public Constructors
+
+ internal void SendFocusToActiveChild ()
+ {
+ Form active = this.ActiveMdiChild;
+ if (active == null) {
+ ParentForm.SendWidgetFocus (this);
+ } else {
+ active.SendWidgetFocus (active);
+ ParentForm.ActiveWidget = active;
+ }
+ }
+
+ internal bool HorizontalScrollbarVisible {
+ get { return hbar != null && hbar.Visible; }
+ }
+ internal bool VerticalScrollbarVisible {
+ get { return vbar != null && vbar.Visible; }
+ }
+
+ internal void SetParentText(bool text_changed)
+ {
+ if (setting_form_text)
+ return;
+
+ setting_form_text = true;
+
+ if (text_changed)
+ form_text = ParentForm.Text;
+
+ if (ParentForm.ActiveMaximizedMdiChild == null) {
+ ParentForm.Text = form_text;
+ } else {
+ string childText = ParentForm.ActiveMaximizedMdiChild.form.Text;
+ if (childText.Length > 0) {
+ ParentForm.Text = form_text + " - [" + ParentForm.ActiveMaximizedMdiChild.form.Text + "]";
+ } else {
+ ParentForm.Text = form_text;
+ }
+ }
+
+ setting_form_text = false;
+ }
+
+ internal override void OnPaintBackgroundInternal (PaintEventArgs pe)
+ {
+ if (BackgroundImage != null)
+ return;
+
+ if (Parent == null || Parent.BackgroundImage == null)
+ return;
+ Parent.PaintWidgetBackground (pe);
+ }
+
+ internal Form ParentForm {
+ get { return (Form) Parent; }
+ }
+
+ protected override Widget.WidgetCollection CreateWidgetsInstance ()
+ {
+ return new MdiClient.WidgetCollection (this);
+ }
+
+ protected override void WndProc(ref Message m) {
+ switch ((Msg)m.Msg) {
+ case Msg.WM_NCPAINT:
+ PaintEventArgs pe = XplatUI.PaintEventStart (ref m, Handle, false);
+
+ Rectangle clip;
+ clip = new Rectangle (0, 0, Width, Height);
+
+ WidgetPaint.DrawBorder3D (pe.Graphics, clip, Border3DStyle.Sunken);
+ XplatUI.PaintEventEnd (ref m, Handle, false);
+ m.Result = IntPtr.Zero;
+ return ;
+ }
+
+ base.WndProc (ref m);
+ }
+
+ protected override void OnResize (EventArgs e)
+ {
+ base.OnResize (e);
+
+ if (Parent != null && Parent.IsHandleCreated)
+ XplatUI.InvalidateNC (Parent.Handle);
+ // Should probably make this into one loop
+ SizeScrollBars ();
+ ArrangeWindows ();
+ }
+
+ protected override void ScaleWidget (SizeF factor, BoundsSpecified specified)
+ {
+ // Never change the MdiClient's location
+ specified &= ~BoundsSpecified.Location;
+
+ base.ScaleWidget (factor, specified);
+ }
+
+ [System.ComponentModel.EditorBrowsable (EditorBrowsableState.Never)]
+ protected override void ScaleCore (float dx, float dy)
+ {
+ base.ScaleCore (dx, dy);
+ }
+
+ protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
+ {
+ base.SetBoundsCore (x, y, width, height, specified);
+ }
+
+ #region Public Instance Properties
+ [Localizable(true)]
+ public override System.Drawing.Image BackgroundImage {
+ get {
+ return base.BackgroundImage;
+ }
+ set {
+ base.BackgroundImage = value;
+ }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ public override ImageLayout BackgroundImageLayout {
+ get {
+ return base.BackgroundImageLayout;
+ }
+ set {
+ base.BackgroundImageLayout = value;
+ }
+ }
+
+ public Form [] MdiChildren {
+ get {
+ if (mdi_child_list == null)
+ return new Form [0];
+ return (Form []) mdi_child_list.ToArray (typeof (Form));
+ }
+ }
+ #endregion // Public Instance Properties
+
+#region Protected Instance Properties
+ protected override CreateParams CreateParams {
+ get {
+ CreateParams result = base.CreateParams;
+ result.ExStyle |= (int) WindowExStyles.WS_EX_CLIENTEDGE;
+ return result;
+ }
+ }
+ #endregion // Protected Instance Properties
+
+ #region Public Instance Methods
+ public void LayoutMdi (MdiLayout value) {
+
+ // Don't forget to always call ArrangeIconicWindows
+ ArrangeIconicWindows (true);
+
+ switch (value) {
+ case MdiLayout.Cascade: {
+ int i = 0;
+ for (int c = Widgets.Count - 1; c >= 0; c--) {
+ Form form = (Form) Widgets [c];
+
+ if (form.WindowState == FormWindowState.Minimized)
+ continue;
+
+ if (form.WindowState == FormWindowState.Maximized)
+ form.WindowState = FormWindowState.Normal;
+
+ form.Width = System.Convert.ToInt32 (ClientSize.Width * 0.8);
+ form.Height = Math.Max (
+ System.Convert.ToInt32 (ClientSize.Height * 0.8),
+ SystemInformation.MinimumWindowSize.Height + 2);
+
+ int l = 22 * i;
+ int t = 22 * i;
+
+ if (i != 0 && (l + form.Width > ClientSize.Width || t + form.Height > ClientSize.Height)) {
+ i = 0;
+ l = 22 * i;
+ t = 22 * i;
+ }
+
+ form.Left = l;
+ form.Top = t;
+
+ i++;
+ }
+ break;
+ }
+ case MdiLayout.TileHorizontal:
+ case MdiLayout.TileVertical: {
+ // First count number of windows to tile
+ int total = 0;
+
+ // And space used by iconic windows
+ int clientHeight = ClientSize.Height;
+
+ for (int i = 0; i < Widgets.Count; i++) {
+ Form form = Widgets [i] as Form;
+
+ if (form == null)
+ continue;
+
+ if (!form.Visible)
+ continue;
+
+ if (form.WindowState == FormWindowState.Maximized)
+ form.WindowState = FormWindowState.Normal;
+ else if (form.WindowState == FormWindowState.Minimized) {
+ if (form.Bounds.Top < clientHeight)
+ clientHeight = form.Bounds.Top;
+ continue;
+ }
+
+ total++;
+ }
+ if (total <= 0)
+ return;
+
+ // Calculate desired height and width
+ Size newSize;
+ Size offset;
+
+ if (value == MdiLayout.TileHorizontal) {
+ newSize = new Size(ClientSize.Width, clientHeight / total);
+ offset = new Size (0, newSize.Height);
+ } else {
+ newSize = new Size(ClientSize.Width / total, clientHeight);
+ offset = new Size (newSize.Width, 0);
+ }
+
+ // Loop again and set the size and location.
+ Point nextLocation = Point.Empty;
+
+ for (int i = 0; i < Widgets.Count; i++) {
+ Form form = Widgets [i] as Form;
+
+ if (form == null)
+ continue;
+
+ if (!form.Visible)
+ continue;
+
+ if (form.WindowState == FormWindowState.Minimized)
+ continue;
+
+ form.Size = newSize;
+ form.Location = nextLocation;
+ nextLocation += offset;
+ }
+
+ break;
+ }
+ }
+ }
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+ #endregion // Protected Instance Methods
+
+ internal void SizeScrollBars ()
+ {
+ if (lock_sizing)
+ return;
+
+ if (!IsHandleCreated)
+ return;
+
+ if (Widgets.Count == 0 || ((Form) Widgets [0]).WindowState == FormWindowState.Maximized) {
+ if (hbar != null)
+ hbar.Visible = false;
+ if (vbar != null)
+ vbar.Visible = false;
+ if (sizegrip != null)
+ sizegrip.Visible = false;
+ return;
+ }
+
+ int right = 0;
+ int left = 0;
+ int top = 0;
+ int bottom = 0;
+
+ foreach (Form child in Widgets) {
+ if (!child.Visible)
+ continue;
+ if (child.Right > right)
+ right = child.Right;
+ if (child.Left < left) {
+ left = child.Left;
+ }
+
+ if (child.Bottom > bottom)
+ bottom = child.Bottom;
+ if (child.Top < 0) {
+ top = child.Top;
+ }
+ }
+
+ int available_width = ClientSize.Width;
+ int available_height = ClientSize.Height;
+
+ bool need_hbar = false;
+ bool need_vbar = false;
+
+ if (right - left > available_width || left < 0) {
+ need_hbar = true;
+ available_height -= SystemInformation.HorizontalScrollBarHeight;
+ }
+ if (bottom - top > available_height || top < 0) {
+ need_vbar = true;
+ available_width -= SystemInformation.VerticalScrollBarWidth;
+
+ if (!need_hbar && (right - left > available_width || left < 0)) {
+ need_hbar = true;
+ available_height -= SystemInformation.HorizontalScrollBarHeight;
+ }
+ }
+
+ if (need_hbar) {
+ if (hbar == null) {
+ hbar = new ImplicitHScrollBar ();
+ Widgets.AddImplicit (hbar);
+ }
+ hbar.Visible = true;
+ CalcHBar (left, right, need_vbar);
+ } else if (hbar != null)
+ hbar.Visible = false;
+
+ if (need_vbar) {
+ if (vbar == null) {
+ vbar = new ImplicitVScrollBar ();
+ Widgets.AddImplicit (vbar);
+ }
+ vbar.Visible = true;
+ CalcVBar (top, bottom, need_hbar);
+ } else if (vbar != null)
+ vbar.Visible = false;
+
+ if (need_hbar && need_vbar) {
+ if (sizegrip == null) {
+ sizegrip = new SizeGrip (this.ParentForm);
+ Widgets.AddImplicit (sizegrip);
+ }
+ sizegrip.Location = new Point (hbar.Right, vbar.Bottom);
+ sizegrip.Visible = true;
+ XplatUI.SetZOrder (sizegrip.Handle, vbar.Handle, false, false);
+ } else if (sizegrip != null) {
+ sizegrip.Visible = false;
+ }
+
+ XplatUI.InvalidateNC (Handle);
+ }
+
+ private void CalcHBar (int left, int right, bool vert_vis)
+ {
+ initializing_scrollbars = true;
+
+ hbar.Left = 0;
+ hbar.Top = ClientRectangle.Bottom - hbar.Height;
+ hbar.Width = ClientRectangle.Width - (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0);
+ hbar.LargeChange = 50;
+ hbar.Minimum = Math.Min (left, 0);
+ hbar.Maximum = Math.Max (right - ClientSize.Width + 51 + (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0), 0);
+ hbar.Value = 0;
+ hbar_value = 0;
+ hbar.ValueChanged += new EventHandler (HBarValueChanged);
+ XplatUI.SetZOrder (hbar.Handle, IntPtr.Zero, true, false);
+
+ initializing_scrollbars = false;
+ }
+
+ private void CalcVBar (int top, int bottom, bool horz_vis)
+ {
+ initializing_scrollbars = true;
+
+ vbar.Top = 0;
+ vbar.Left = ClientRectangle.Right - vbar.Width;
+ vbar.Height = ClientRectangle.Height - (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0);
+ vbar.LargeChange = 50;
+ vbar.Minimum = Math.Min (top, 0);
+ vbar.Maximum = Math.Max (bottom - ClientSize.Height + 51 + (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0), 0);
+ vbar.Value = 0;
+ vbar_value = 0;
+ vbar.ValueChanged += new EventHandler (VBarValueChanged);
+ XplatUI.SetZOrder (vbar.Handle, IntPtr.Zero, true, false);
+
+ initializing_scrollbars = false;
+ }
+
+ private void HBarValueChanged (object sender, EventArgs e)
+ {
+ if (initializing_scrollbars)
+ return;
+
+ if (hbar.Value == hbar_value)
+ return;
+
+ lock_sizing = true;
+
+ try {
+ int diff = hbar_value - hbar.Value;
+ foreach (Form child in Widgets) {
+ child.Left += diff;
+ }
+ } finally {
+ lock_sizing = false;
+ }
+
+ hbar_value = hbar.Value;
+ }
+
+ private void VBarValueChanged (object sender, EventArgs e)
+ {
+ if (initializing_scrollbars)
+ return;
+
+ if (vbar.Value == vbar_value)
+ return;
+
+ lock_sizing = true;
+
+ try {
+ int diff = vbar_value - vbar.Value;
+ foreach (Form child in Widgets) {
+ child.Top += diff;
+ }
+ } finally {
+ lock_sizing = false;
+ }
+
+ vbar_value = vbar.Value;
+ }
+
+ private void ArrangeWindows ()
+ {
+ if (!IsHandleCreated)
+ return;
+
+ int change = 0;
+ if (prev_bottom != -1)
+ change = Bottom - prev_bottom;
+
+ foreach (Widget c in Widgets) {
+ Form child = c as Form;
+
+ if (c == null || !child.Visible)
+ continue;
+
+ MdiWindowManager wm = child.WindowManager as MdiWindowManager;
+ if (wm.GetWindowState () == FormWindowState.Maximized)
+ child.Bounds = wm.MaximizedBounds;
+
+ if (wm.GetWindowState () == FormWindowState.Minimized) {
+ child.Top += change;
+ }
+
+ }
+
+ prev_bottom = Bottom;
+ }
+
+ internal void ArrangeIconicWindows (bool rearrange_all)
+ {
+ Rectangle rect = Rectangle.Empty;
+
+ lock_sizing = true;
+ foreach (Form form in Widgets) {
+ if (form.WindowState != FormWindowState.Minimized)
+ continue;
+
+ MdiWindowManager wm = (MdiWindowManager) form.WindowManager;
+
+ if (wm.IconicBounds != Rectangle.Empty && !rearrange_all) {
+ if (form.Bounds != wm.IconicBounds)
+ form.Bounds = wm.IconicBounds;
+ continue;
+ }
+
+ bool success = true;
+ int startx, starty, currentx, currenty;
+
+ rect.Size = wm.IconicSize;
+
+ startx = 0;
+ starty = ClientSize.Height - rect.Height;
+ currentx = startx;
+ currenty = starty;
+
+ do {
+ rect.X = currentx;
+ rect.Y = currenty;
+ success = true;
+ foreach (Form form2 in Widgets) {
+ if (form2 == form || form2.window_state != FormWindowState.Minimized)
+ continue;
+
+ if (form2.Bounds.IntersectsWith(rect)) {
+ success = false;
+ break;
+ }
+ }
+ if (!success) {
+ currentx += rect.Width;
+ if (currentx + rect.Width > Right) {
+ currentx = startx;
+ currenty -= rect.Height;
+ }
+ }
+ } while (!success);
+ wm.IconicBounds = rect;
+ form.Bounds = wm.IconicBounds;
+ }
+ lock_sizing = false;
+ }
+
+ internal void ChildFormClosed (Form form)
+ {
+ FormWindowState closed_form_windowstate = form.WindowState;
+
+ form.Visible = false;
+ Widgets.Remove (form);
+
+ if (Widgets.Count == 0) {
+ ((MdiWindowManager) form.window_manager).RaiseDeactivate ();
+ } else if (closed_form_windowstate == FormWindowState.Maximized) {
+ Form current = (Form) Widgets [0];
+ current.WindowState = FormWindowState.Maximized;
+ ActivateChild(current);
+ }
+
+ if (Widgets.Count == 0) {
+ XplatUI.RequestNCRecalc (Parent.Handle);
+ ParentForm.PerformLayout ();
+
+ // If we closed the last child, unmerge the menus.
+ // If it's not the last child, the menu will be unmerged
+ // when another child takes focus.
+ MenuStrip parent_menu = form.MdiParent.MainMenuStrip;
+
+ if (parent_menu != null)
+ if (parent_menu.IsCurrentlyMerged)
+ ToolStripManager.RevertMerge (parent_menu);
+ }
+ SizeScrollBars ();
+ SetParentText (false);
+ form.Dispose();
+ }
+
+ internal void ActivateNextChild ()
+ {
+ if (Widgets.Count < 1)
+ return;
+ if (Widgets.Count == 1 && Widgets[0] == ActiveMdiChild)
+ return;
+
+ Form front = (Form) Widgets [0];
+ Form form = (Form) Widgets [1];
+
+ ActivateChild (form);
+ front.SendToBack ();
+ }
+
+ internal void ActivatePreviousChild ()
+ {
+ if (Widgets.Count <= 1)
+ return;
+
+ Form back = (Form) Widgets [Widgets.Count - 1];
+
+ ActivateChild (back);
+ }
+
+ internal void ActivateChild (Form form)
+ {
+ if (Widgets.Count < 1)
+ return;
+
+ if (ParentForm.is_changing_visible_state > 0)
+ return;
+
+ Form current = (Form) Widgets [0];
+ bool raise_deactivate = ParentForm.ActiveWidget == current;
+
+ // We want to resize the new active form before it is
+ // made active to avoid flickering. Can't do it in the
+ // normal way (form.WindowState = Maximized) since it's not
+ // active yet and everything would just return to before.
+ // We also won't suspend layout, this way the layout will
+ // happen before the form is made active (and in many cases
+ // before it is visible, which avoids flickering as well).
+ MdiWindowManager wm = (MdiWindowManager)form.WindowManager;
+
+ if (current.WindowState == FormWindowState.Maximized && form.WindowState != FormWindowState.Maximized && form.Visible) {
+ FormWindowState old_state = form.window_state;
+ SetWindowState (form, old_state, FormWindowState.Maximized, true);
+ wm.was_minimized = form.window_state == FormWindowState.Minimized;
+ form.window_state = FormWindowState.Maximized;
+ SetParentText (false);
+ }
+
+ form.BringToFront ();
+ form.SendWidgetFocus (form);
+ SetWindowStates (wm);
+ if (current != form) {
+ form.has_focus = false;
+ if (current.IsHandleCreated)
+ XplatUI.InvalidateNC (current.Handle);
+ if (form.IsHandleCreated)
+ XplatUI.InvalidateNC (form.Handle);
+ if (raise_deactivate) {
+ MdiWindowManager current_wm = (MdiWindowManager) current.window_manager;
+ current_wm.RaiseDeactivate ();
+
+ }
+ }
+ active_child = (Form) Widgets [0];
+
+ if (active_child.Visible) {
+ bool raise_activated = ParentForm.ActiveWidget != active_child;
+ ParentForm.ActiveWidget = active_child;
+ if (raise_activated) {
+ MdiWindowManager active_wm = (MdiWindowManager) active_child.window_manager;
+ active_wm.RaiseActivated ();
+ }
+ }
+ }
+
+ internal override IntPtr AfterTopMostWidget ()
+ {
+ // order of scrollbars:
+ // top = vertical
+ // sizegrid
+ // bottom = horizontal
+ if (hbar != null && hbar.Visible)
+ return hbar.Handle;
+ // no need to check for sizegrip since it will only
+ // be visible if hbar is visible.
+ if (vbar != null && vbar.Visible)
+ return vbar.Handle;
+
+ return base.AfterTopMostWidget ();
+ }
+
+ internal bool SetWindowStates (MdiWindowManager wm)
+ {
+ /*
+ MDI WindowState behaviour:
+ - If the active window is maximized, all other maximized windows are normalized.
+ - If a normal window gets focus and the original active window was maximized,
+ the normal window gets maximized and the original window gets normalized.
+ - If a minimized window gets focus and the original window was maximized,
+ the minimzed window gets maximized and the original window gets normalized.
+ If the ex-minimized window gets deactivated, it will be normalized.
+ */
+ Form form = wm.form;
+
+ if (setting_windowstates) {
+ return false;
+ }
+
+ if (!form.Visible)
+ return false;
+
+ bool is_active = wm.IsActive;
+ bool maximize_this = false;
+
+ if (!is_active){
+ return false;
+ }
+
+ ArrayList minimize_these = new ArrayList ();
+ ArrayList normalize_these = new ArrayList ();
+
+ setting_windowstates = true;
+ foreach (Form frm in mdi_child_list) {
+ if (frm == form) {
+ continue;
+ } else if (!frm.Visible){
+ continue;
+ }
+ if (frm.WindowState == FormWindowState.Maximized && is_active) {
+ maximize_this = true;
+ if (((MdiWindowManager) frm.window_manager).was_minimized) {
+ minimize_these.Add (frm);
+ } else {
+ normalize_these.Add (frm);
+ }
+ }
+ }
+
+ if (maximize_this && form.WindowState != FormWindowState.Maximized) {
+ wm.was_minimized = form.window_state == FormWindowState.Minimized;
+ form.WindowState = FormWindowState.Maximized;
+ }
+
+ foreach (Form frm in minimize_these)
+ frm.WindowState = FormWindowState.Minimized;
+
+ foreach (Form frm in normalize_these)
+ frm.WindowState = FormWindowState.Normal;
+
+
+ SetParentText (false);
+
+ XplatUI.RequestNCRecalc (ParentForm.Handle);
+ XplatUI.RequestNCRecalc (Handle);
+
+ SizeScrollBars ();
+
+ setting_windowstates = false;
+
+ if (form.MdiParent.MainMenuStrip != null)
+ form.MdiParent.MainMenuStrip.RefreshMdiItems ();
+
+ // Implicit menu strip merging
+ // - When child is activated
+ // - Parent form must have a MainMenuStrip
+ // - Find the first menustrip on the child
+ // - Merge
+ MenuStrip parent_menu = form.MdiParent.MainMenuStrip;
+
+ if (parent_menu != null) {
+ if (parent_menu.IsCurrentlyMerged)
+ ToolStripManager.RevertMerge (parent_menu);
+
+ MenuStrip child_menu = LookForChildMenu (form);
+
+ if (form.WindowState != FormWindowState.Maximized)
+ RemoveControlMenuItems (wm);
+
+ if (form.WindowState == FormWindowState.Maximized) {
+ bool found = false;
+
+ foreach (ToolStripItem tsi in parent_menu.Items) {
+ if (tsi is MdiWidgetStrip.SystemMenuItem) {
+ (tsi as MdiWidgetStrip.SystemMenuItem).MdiForm = form;
+ found = true;
+ } else if (tsi is MdiWidgetStrip.WidgetBoxMenuItem) {
+ (tsi as MdiWidgetStrip.WidgetBoxMenuItem).MdiForm = form;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ parent_menu.SuspendLayout ();
+ parent_menu.Items.Insert (0, new MdiWidgetStrip.SystemMenuItem (form));
+ parent_menu.Items.Add (new MdiWidgetStrip.WidgetBoxMenuItem (form, MdiWidgetStrip.ControlBoxType.Close));
+ parent_menu.Items.Add (new MdiWidgetStrip.WidgetBoxMenuItem (form, MdiWidgetStrip.ControlBoxType.Max));
+ parent_menu.Items.Add (new MdiWidgetStrip.WidgetBoxMenuItem (form, MdiWidgetStrip.ControlBoxType.Min));
+ parent_menu.ResumeLayout ();
+ }
+ }
+
+ if (child_menu != null)
+ ToolStripManager.Merge (child_menu, parent_menu);
+ }
+
+ return maximize_this;
+ }
+
+ private MenuStrip LookForChildMenu (Widget parent)
+ {
+ foreach (Widget c in parent.Widgets) {
+ if (c is MenuStrip)
+ return (MenuStrip)c;
+
+ if (c is ToolStripContainer || c is ToolStripPanel) {
+ MenuStrip ms = LookForChildMenu (c);
+
+ if (ms != null)
+ return ms;
+ }
+ }
+
+ return null;
+ }
+
+ internal void RemoveControlMenuItems (MdiWindowManager wm)
+ {
+ Form form = wm.form;
+ MenuStrip parent_menu = form.MdiParent.MainMenuStrip;
+
+ // Only remove the items if the form requesting still owns the menu items
+ if (parent_menu != null) {
+ parent_menu.SuspendLayout ();
+
+ for (int i = parent_menu.Items.Count - 1; i >= 0; i--) {
+ if (parent_menu.Items[i] is MdiWidgetStrip.SystemMenuItem) {
+ if ((parent_menu.Items[i] as MdiWidgetStrip.SystemMenuItem).MdiForm == form)
+ parent_menu.Items.RemoveAt (i);
+ } else if (parent_menu.Items[i] is MdiWidgetStrip.WidgetBoxMenuItem) {
+ if ((parent_menu.Items[i] as MdiWidgetStrip.WidgetBoxMenuItem).MdiForm == form)
+ parent_menu.Items.RemoveAt (i);
+ }
+ }
+
+ parent_menu.ResumeLayout ();
+ }
+ }
+
+ internal void SetWindowState (Form form, FormWindowState old_window_state, FormWindowState new_window_state, bool is_activating_child)
+ {
+ bool mdiclient_layout;
+
+ MdiWindowManager wm = (MdiWindowManager) form.window_manager;
+
+ if (!is_activating_child && new_window_state == FormWindowState.Maximized && !wm.IsActive) {
+ ActivateChild (form);
+ return;
+ }
+
+ if (old_window_state == FormWindowState.Normal)
+ wm.NormalBounds = form.Bounds;
+
+ if (SetWindowStates (wm))
+ return;
+
+ if (old_window_state == new_window_state)
+ return;
+
+ mdiclient_layout = old_window_state == FormWindowState.Maximized || new_window_state == FormWindowState.Maximized;
+
+ switch (new_window_state) {
+ case FormWindowState.Minimized:
+ ArrangeIconicWindows (false);
+ break;
+ case FormWindowState.Maximized:
+ form.Bounds = wm.MaximizedBounds;
+ break;
+ case FormWindowState.Normal:
+ form.Bounds = wm.NormalBounds;
+ break;
+ }
+
+ wm.UpdateWindowDecorations (new_window_state);
+
+ form.ResetCursor ();
+
+ if (mdiclient_layout)
+ Parent.PerformLayout ();
+
+ XplatUI.RequestNCRecalc (Parent.Handle);
+ XplatUI.RequestNCRecalc (form.Handle);
+ if (!setting_windowstates)
+ SizeScrollBars ();
+ }
+ internal int ChildrenCreated {
+ get { return mdi_created; }
+ set { mdi_created = value; }
+ }
+
+ internal Form ActiveMdiChild {
+ get {
+ if (ParentForm != null && !ParentForm.Visible)
+ return null;
+
+ if (Widgets.Count < 1)
+ return null;
+
+ if (!ParentForm.IsHandleCreated)
+ return null;
+
+ if (!ParentForm.has_been_visible)
+ return null;
+
+ if (!ParentForm.Visible)
+ return active_child;
+
+ active_child = null;
+ for (int i = 0; i < Widgets.Count; i++) {
+ if (Widgets [i].Visible) {
+ active_child = (Form) Widgets [i];
+ break;
+ }
+ }
+ return active_child;
+ }
+ set {
+ ActivateChild (value);
+ }
+ }
+
+ internal void ActivateActiveMdiChild ()
+ {
+ if (ParentForm.is_changing_visible_state > 0)
+ return;
+
+ for (int i = 0; i < Widgets.Count; i++) {
+ if (Widgets [i].Visible) {
+ ActivateChild ((Form) Widgets [i]);
+ return;
+ }
+ }
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/MdiControlStrip.cs b/source/ShiftUI/Internal/MdiControlStrip.cs
new file mode 100644
index 0000000..a04e02a
--- /dev/null
+++ b/source/ShiftUI/Internal/MdiControlStrip.cs
@@ -0,0 +1,207 @@
+//
+// MdiWidgetstrip.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System;
+using System.Runtime.InteropServices;
+using System.ComponentModel;
+using System.Drawing;
+using ShiftUI.Layout;
+using System.Collections.Generic;
+using System.ComponentModel.Design.Serialization;
+
+namespace ShiftUI
+{
+ internal class MdiWidgetStrip
+ {
+ public class SystemMenuItem : ToolStripMenuItem
+ {
+ private Form form;
+
+ public SystemMenuItem (Form ownerForm)
+ {
+ form = ownerForm;
+
+ base.AutoSize = false;
+ base.Size = new Size (20, 20);
+ base.Image = ownerForm.Icon.ToBitmap ();
+ base.MergeIndex = int.MinValue;
+ base.DisplayStyle = ToolStripItemDisplayStyle.Image;
+
+ DropDownItems.Add ("&Restore", null, RestoreItemHandler);
+ ToolStripMenuItem tsiMove = (ToolStripMenuItem)DropDownItems.Add ("&Move");
+ tsiMove.Enabled = false;
+ ToolStripMenuItem tsiSize = (ToolStripMenuItem)DropDownItems.Add ("&Size");
+ tsiSize.Enabled = false;
+ DropDownItems.Add ("Mi&nimize", null, MinimizeItemHandler);
+ ToolStripMenuItem tsiMaximize = (ToolStripMenuItem)DropDownItems.Add ("Ma&ximize");
+ tsiMaximize.Enabled = false;
+ DropDownItems.Add ("-");
+ ToolStripMenuItem tsiClose = (ToolStripMenuItem)DropDownItems.Add ("&Close", null, CloseItemHandler);
+ tsiClose.ShortcutKeys = Keys.Widget | Keys.F4;
+ DropDownItems.Add ("-");
+ ToolStripMenuItem tsiNext = (ToolStripMenuItem)DropDownItems.Add ("Nex&t", null, NextItemHandler);
+ tsiNext.ShortcutKeys = Keys.Widget | Keys.F6;
+ }
+
+ protected override void OnPaint (PaintEventArgs e)
+ {
+ // Can't render without an owner
+ if (this.Owner == null)
+ return;
+
+ // If DropDown.ShowImageMargin is false, we don't display the image
+ Image draw_image = this.Image;
+
+ // Figure out where our text and image go
+ Rectangle text_layout_rect;
+ Rectangle image_layout_rect;
+
+ this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect);
+
+ if (image_layout_rect != Rectangle.Empty)
+ this.Owner.Renderer.DrawItemImage (new ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect));
+
+ return;
+ }
+
+ public Form MdiForm {
+ get { return form; }
+ set { form = value; }
+ }
+
+ private void RestoreItemHandler (object sender, EventArgs e)
+ {
+ form.WindowState = FormWindowState.Normal;
+ }
+
+ private void MinimizeItemHandler (object sender, EventArgs e)
+ {
+ form.WindowState = FormWindowState.Minimized;
+ }
+
+ private void CloseItemHandler (object sender, EventArgs e)
+ {
+ form.Close ();
+ }
+
+ private void NextItemHandler (object sender, EventArgs e)
+ {
+ form.MdiParent.MdiContainer.ActivateNextChild ();
+ }
+ }
+
+ public class WidgetBoxMenuItem : ToolStripMenuItem
+ {
+ private Form form;
+ private ControlBoxType type;
+
+ public WidgetBoxMenuItem (Form ownerForm, ControlBoxType type)
+ {
+ form = ownerForm;
+ this.type = type;
+
+ base.AutoSize = false;
+ base.Alignment = ToolStripItemAlignment.Right;
+ base.Size = new Size (20, 20);
+ base.MergeIndex = int.MaxValue;
+ base.DisplayStyle = ToolStripItemDisplayStyle.None;
+
+ switch (type) {
+ case ControlBoxType.Close:
+ this.Click += new EventHandler(CloseItemHandler);
+ break;
+ case ControlBoxType.Min:
+ this.Click += new EventHandler (MinimizeItemHandler);
+ break;
+ case ControlBoxType.Max:
+ this.Click += new EventHandler (RestoreItemHandler);
+ break;
+ }
+ }
+
+ protected override void OnPaint (PaintEventArgs e)
+ {
+ base.OnPaint (e);
+ Graphics g = e.Graphics;
+
+ switch (type) {
+ case ControlBoxType.Close:
+ g.FillRectangle (Brushes.Black, 8, 8, 4, 4);
+ g.FillRectangle (Brushes.Black, 6, 6, 2, 2);
+ g.FillRectangle (Brushes.Black, 6, 12, 2, 2);
+ g.FillRectangle (Brushes.Black, 12, 6, 2, 2);
+ g.FillRectangle (Brushes.Black, 12, 12, 2, 2);
+ g.DrawLine (Pens.Black, 8, 7, 8, 12);
+ g.DrawLine (Pens.Black, 7, 8, 12, 8);
+ g.DrawLine (Pens.Black, 11, 7, 11, 12);
+ g.DrawLine (Pens.Black, 7, 11, 12, 11);
+ break;
+ case ControlBoxType.Min:
+ g.DrawLine (Pens.Black, 6, 12, 11, 12);
+ g.DrawLine (Pens.Black, 6, 13, 11, 13);
+ break;
+ case ControlBoxType.Max:
+ g.DrawLines (Pens.Black, new Point[] {new Point (7, 8), new Point (7, 5), new Point (13, 5), new Point (13, 10), new Point (11, 10)});
+ g.DrawLine (Pens.Black, 7, 6, 12, 6);
+
+ g.DrawRectangle (Pens.Black, new Rectangle (5, 8, 6, 5));
+ g.DrawLine (Pens.Black, 5, 9, 11, 9);
+
+ break;
+ }
+ }
+
+ public Form MdiForm {
+ get { return form; }
+ set { form = value; }
+ }
+
+ private void RestoreItemHandler (object sender, EventArgs e)
+ {
+ form.WindowState = FormWindowState.Normal;
+ }
+
+ private void MinimizeItemHandler (object sender, EventArgs e)
+ {
+ form.WindowState = FormWindowState.Minimized;
+ }
+
+ private void CloseItemHandler (object sender, EventArgs e)
+ {
+ form.Close ();
+ }
+ }
+
+ public enum ControlBoxType
+ {
+ Close,
+ Min,
+ Max
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/MdiLayout.cs b/source/ShiftUI/Internal/MdiLayout.cs
new file mode 100644
index 0000000..8c610a4
--- /dev/null
+++ b/source/ShiftUI/Internal/MdiLayout.cs
@@ -0,0 +1,36 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+namespace ShiftUI {
+ public enum MdiLayout {
+ Cascade = 0,
+ TileHorizontal = 1,
+ TileVertical = 2,
+ ArrangeIcons = 3
+ }
+}
diff --git a/source/ShiftUI/Internal/MdiWindowManager.cs b/source/ShiftUI/Internal/MdiWindowManager.cs
new file mode 100644
index 0000000..0344f2c
--- /dev/null
+++ b/source/ShiftUI/Internal/MdiWindowManager.cs
@@ -0,0 +1,624 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Jackson Harper ([email protected])
+//
+//
+
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI {
+
+ internal class MdiWindowManager : InternalWindowManager {
+
+ private MainMenu merged_menu;
+ private MainMenu maximized_menu;
+ private MenuItem icon_menu;
+ internal bool was_minimized;
+
+ private PaintEventHandler draw_maximized_buttons;
+ internal EventHandler form_closed_handler;
+
+ private MdiClient mdi_container;
+ private Rectangle prev_virtual_position;
+
+ private Point icon_clicked;
+ private DateTime icon_clicked_time;
+ private bool icon_dont_show_popup;
+
+ private TitleButtons maximized_title_buttons;
+ private bool is_visible_pending;
+ private byte last_activation_event; // 0 = none, 1 = activated, 2 = deactivated.
+
+ public void RaiseActivated ()
+ {
+ if (last_activation_event == 1)
+ return;
+
+ last_activation_event = 1;
+ form.OnActivatedInternal ();
+ form.SelectActiveWidget ();
+ }
+
+ public void RaiseDeactivate ()
+ {
+ if (last_activation_event != 1)
+ return;
+ last_activation_event = 2;
+ form.OnDeactivateInternal ();
+ }
+
+ public override int MenuHeight {
+ get {
+ // Mdi children don't get menus on the form, they're shown on the main form.
+ return 0;
+ }
+ }
+
+ internal bool IsVisiblePending {
+ get {
+ return is_visible_pending;
+ }
+ set {
+ is_visible_pending = value;
+ }
+ }
+
+ private TitleButtons MaximizedTitleButtons {
+ get {
+ if (maximized_title_buttons == null) {
+ maximized_title_buttons = new TitleButtons (this.Form);
+ maximized_title_buttons.CloseButton.Visible = true;
+ maximized_title_buttons.RestoreButton.Visible = true;
+ maximized_title_buttons.MinimizeButton.Visible = true;
+ }
+ return maximized_title_buttons;
+ }
+ }
+
+ internal override Rectangle MaximizedBounds {
+ get {
+ Rectangle pb = mdi_container.ClientRectangle;
+ int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
+ int tw = TitleBarHeight;
+
+ Rectangle new_bounds = new Rectangle (pb.Left - bw,
+ pb.Top - tw - bw,
+ pb.Width + bw * 2,
+ pb.Height + tw + bw * 2);
+ return new_bounds;
+ }
+ }
+
+
+
+ public MdiWindowManager (Form form, MdiClient mdi_container) : base (form)
+ {
+ this.mdi_container = mdi_container;
+ if (form.WindowState == FormWindowState.Normal) {
+ NormalBounds = form.Bounds;
+ }
+ form_closed_handler = new EventHandler (FormClosed);
+ form.Closed += form_closed_handler;
+ form.TextChanged += new EventHandler (FormTextChangedHandler);
+ form.SizeChanged += new EventHandler (FormSizeChangedHandler);
+ form.LocationChanged += new EventHandler (FormLocationChangedHandler);
+ form.VisibleChanged += new EventHandler (FormVisibleChangedHandler);
+ draw_maximized_buttons = new PaintEventHandler (DrawMaximizedButtons);
+ CreateIconMenus ();
+ }
+
+ private void FormVisibleChangedHandler (object sender, EventArgs e)
+ {
+ if (mdi_container == null)
+ return;
+
+ if (form.Visible) {
+ mdi_container.ActivateChild (form);
+ } else if (mdi_container.Widgets.Count > 1) {
+ mdi_container.ActivateActiveMdiChild ();
+ }
+ }
+
+ private void FormTextChangedHandler (object sender, EventArgs e)
+ {
+ mdi_container.SetParentText (false);
+
+ if (form.MdiParent.MainMenuStrip != null)
+ form.MdiParent.MainMenuStrip.RefreshMdiItems ();
+ }
+
+ private void FormLocationChangedHandler (object sender, EventArgs e)
+ {
+ if (form.window_state == FormWindowState.Minimized)
+ IconicBounds = form.Bounds;
+ form.MdiParent.MdiContainer.SizeScrollBars ();
+ }
+
+ private void FormSizeChangedHandler (object sender, EventArgs e)
+ {
+ if (form.window_state == FormWindowState.Maximized && form.Bounds != MaximizedBounds)
+ form.Bounds = MaximizedBounds;
+
+ form.MdiParent.MdiContainer.SizeScrollBars ();
+ }
+
+ public MainMenu MergedMenu {
+ get {
+ if (merged_menu == null)
+ merged_menu = CreateMergedMenu ();
+ return merged_menu;
+ }
+ }
+
+ private MainMenu CreateMergedMenu ()
+ {
+ Form parent = (Form) mdi_container.Parent;
+ MainMenu clone;
+ if (parent.Menu != null)
+ clone = (MainMenu) parent.Menu.CloneMenu ();
+ else
+ clone = new MainMenu ();
+
+ if (form.WindowState == FormWindowState.Maximized) {
+
+ }
+ clone.MergeMenu (form.Menu);
+ clone.MenuChanged += new EventHandler (MenuChangedHandler);
+ clone.SetForm (parent);
+ return clone;
+ }
+
+ public MainMenu MaximizedMenu {
+ get {
+ if (maximized_menu == null)
+ maximized_menu = CreateMaximizedMenu ();
+ return maximized_menu;
+ }
+ }
+
+ private MainMenu CreateMaximizedMenu ()
+ {
+ Form parent = (Form) mdi_container.Parent;
+
+ if (form.MainMenuStrip != null || parent.MainMenuStrip != null)
+ return null;
+
+ MainMenu res = new MainMenu ();
+
+ if (parent.Menu != null) {
+ MainMenu clone = (MainMenu) parent.Menu.CloneMenu ();
+ res.MergeMenu (clone);
+ }
+
+ if (form.Menu != null) {
+ MainMenu clone = (MainMenu) form.Menu.CloneMenu ();
+ res.MergeMenu (clone);
+ }
+
+ if (res.MenuItems.Count == 0)
+ res.MenuItems.Add (new MenuItem ()); // Dummy item to get the menu height correct
+
+ res.MenuItems.Insert (0, icon_menu);
+
+ res.SetForm (parent);
+ return res;
+ }
+
+ private void CreateIconMenus ()
+ {
+ //TODO: remove this unneeded crap
+ }
+
+ private void ClickIconMenuItem(object sender, EventArgs e)
+ {
+ if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) {
+ form.Close ();
+ return;
+ }
+ icon_clicked_time = DateTime.Now;
+ Point pnt = Point.Empty;
+ pnt = form.MdiParent.PointToScreen (pnt);
+ pnt = form.PointToClient (pnt);
+ ShowPopup (pnt);
+ }
+
+ internal void ShowPopup (Point pnt)
+ {
+ // If we are using MainMenuStrip, display that menu instead
+ if (form.WindowState == FormWindowState.Maximized && form.MdiParent.MainMenuStrip != null)
+ if (form.MdiParent.MainMenuStrip.Items.Count > 0) {
+ ToolStripItem tsi = form.MdiParent.MainMenuStrip.Items[0];
+
+ if (tsi is MdiWidgetStrip.SystemMenuItem) {
+ (tsi as MdiWidgetStrip.SystemMenuItem).ShowDropDown ();
+ return;
+ }
+ }
+
+ }
+
+ private void RestoreItemHandler (object sender, EventArgs e)
+ {
+ form.WindowState = FormWindowState.Normal;
+ }
+
+ private void MoveItemHandler (object sender, EventArgs e)
+ {
+ int x = 0;
+ int y = 0;
+
+ PointToScreen (ref x, ref y);
+ Cursor.Position = new Point (x, y);
+ form.Cursor = Cursors.Cross;
+ state = State.Moving;
+ form.Capture = true;
+ }
+
+ private void SizeItemHandler (object sender, EventArgs e)
+ {
+ int x = 0;
+ int y = 0;
+
+ PointToScreen (ref x, ref y);
+ Cursor.Position = new Point (x, y);
+ form.Cursor = Cursors.Cross;
+ state = State.Sizing;
+ form.Capture = true;
+ }
+
+ private void MinimizeItemHandler (object sender, EventArgs e)
+ {
+ form.WindowState = FormWindowState.Minimized;
+ }
+
+ private void MaximizeItemHandler (object sender, EventArgs e)
+ {
+ if (form.WindowState != FormWindowState.Maximized)
+ form.WindowState = FormWindowState.Maximized;
+ }
+
+ private void CloseItemHandler (object sender, EventArgs e)
+ {
+ form.Close ();
+ }
+
+ private void NextItemHandler (object sender, EventArgs e)
+ {
+ mdi_container.ActivateNextChild ();
+ }
+
+ private void DrawIconMenuItem (object sender, DrawItemEventArgs de)
+ {
+ de.Graphics.DrawIcon (form.Icon, new Rectangle (de.Bounds.X + 2, de.Bounds.Y + 2,
+ de.Bounds.Height - 4, de.Bounds.Height - 4));
+ }
+
+ private void MeasureIconMenuItem (object sender, MeasureItemEventArgs me)
+ {
+ int size = SystemInformation.MenuHeight;
+ me.ItemHeight = size;
+ me.ItemWidth = size + 2; // some padding
+ }
+
+ private void MenuChangedHandler (object sender, EventArgs e)
+ {
+ CreateMergedMenu ();
+ }
+
+ public override void PointToClient (ref int x, ref int y)
+ {
+ XplatUI.ScreenToClient (mdi_container.Handle, ref x, ref y);
+ }
+
+ public override void PointToScreen (ref int x, ref int y)
+ {
+ XplatUI.ClientToScreen (mdi_container.Handle, ref x, ref y);
+ }
+
+ public override void UpdateWindowDecorations (FormWindowState window_state)
+ {
+ if (MaximizedMenu != null) {
+ switch (window_state) {
+ case FormWindowState.Minimized:
+ case FormWindowState.Normal:
+ MaximizedMenu.Paint -= draw_maximized_buttons;
+ MaximizedTitleButtons.Visible = false;
+ TitleButtons.Visible = true;
+ break;
+ case FormWindowState.Maximized:
+ MaximizedMenu.Paint += draw_maximized_buttons;
+ MaximizedTitleButtons.Visible = true;
+ TitleButtons.Visible = false;
+ break;
+ }
+ }
+
+ base.UpdateWindowDecorations (window_state);
+ }
+
+ public override void SetWindowState (FormWindowState old_state, FormWindowState window_state)
+ {
+ mdi_container.SetWindowState (form, old_state, window_state, false);
+ }
+
+ private void FormClosed (object sender, EventArgs e)
+ {
+ mdi_container.ChildFormClosed (form);
+
+ if (form.MdiParent.MainMenuStrip != null)
+ form.MdiParent.MainMenuStrip.RefreshMdiItems ();
+
+ mdi_container.RemoveControlMenuItems (this);
+ }
+
+ public override void DrawMaximizedButtons (object sender, PaintEventArgs pe)
+ {
+ Size bs = ThemeEngine.Current.ManagedWindowGetMenuButtonSize (this);
+ Point pnt = XplatUI.GetMenuOrigin (mdi_container.ParentForm.Handle);
+ int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
+ TitleButtons buttons = MaximizedTitleButtons;
+
+ buttons.Visible = true;
+ TitleButtons.Visible = false;
+
+ buttons.CloseButton.Rectangle = new Rectangle (mdi_container.ParentForm.Size.Width - 1 - bw - bs.Width - 2,
+ pnt.Y + 2, bs.Width, bs.Height);
+
+ buttons.RestoreButton.Rectangle = new Rectangle (buttons.CloseButton.Rectangle.Left - 2 - bs.Width,
+ pnt.Y + 2, bs.Width, bs.Height);
+
+ buttons.MinimizeButton.Rectangle = new Rectangle (buttons.RestoreButton.Rectangle.Left - bs.Width,
+ pnt.Y + 2, bs.Width, bs.Height);
+
+ DrawTitleButton (pe.Graphics, buttons.MinimizeButton, pe.ClipRectangle);
+ DrawTitleButton (pe.Graphics, buttons.RestoreButton, pe.ClipRectangle);
+ DrawTitleButton (pe.Graphics, buttons.CloseButton, pe.ClipRectangle);
+
+ buttons.MinimizeButton.Rectangle.Y -= pnt.Y;
+ buttons.RestoreButton.Rectangle.Y -= pnt.Y;
+ buttons.CloseButton.Rectangle.Y -= pnt.Y;
+ }
+
+ public bool HandleMenuMouseDown (MainMenu menu, int x, int y)
+ {
+ Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
+
+ HandleTitleBarDown (pt.X, pt.Y);
+ return TitleButtons.AnyPushedTitleButtons;
+ }
+
+ public void HandleMenuMouseUp (MainMenu menu, int x, int y)
+ {
+ Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
+
+ HandleTitleBarUp (pt.X, pt.Y);
+ }
+
+ public void HandleMenuMouseLeave (MainMenu menu, int x, int y)
+ {
+ Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
+ HandleTitleBarLeave (pt.X, pt.Y);
+
+ }
+
+ public void HandleMenuMouseMove (MainMenu menu, int x, int y)
+ {
+ Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
+
+ HandleTitleBarMouseMove (pt.X, pt.Y);
+
+ }
+
+ protected override void HandleTitleBarLeave (int x, int y)
+ {
+ base.HandleTitleBarLeave (x, y);
+
+ if (maximized_title_buttons != null) {
+ maximized_title_buttons.MouseLeave (x, y);
+ }
+
+ if (IsMaximized)
+ XplatUI.InvalidateNC (form.MdiParent.Handle);
+ }
+
+ protected override void HandleTitleBarUp (int x, int y)
+ {
+ if (IconRectangleContains (x, y)) {
+ if (!icon_dont_show_popup) {
+ if (IsMaximized)
+ ClickIconMenuItem (null, null);
+ else
+ ShowPopup (Point.Empty);
+ } else {
+ icon_dont_show_popup = false;
+ }
+ return;
+ }
+
+ bool was_maximized = IsMaximized;
+ base.HandleTitleBarUp (x, y);
+ if (maximized_title_buttons != null && was_maximized) {
+ maximized_title_buttons.MouseUp (x, y);
+ }
+
+ if (IsMaximized)
+ XplatUI.InvalidateNC (mdi_container.Parent.Handle);
+ }
+
+ protected override void HandleTitleBarDoubleClick (int x, int y)
+ {
+ if (IconRectangleContains (x, y)) {
+ form.Close ();
+ } else if (form.MaximizeBox == true) {
+ form.WindowState = FormWindowState.Maximized;
+ }
+ base.HandleTitleBarDoubleClick (x, y);
+ }
+
+ protected override void HandleTitleBarDown (int x, int y)
+ {
+ if (IconRectangleContains (x, y)) {
+ if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime && icon_clicked.X == x && icon_clicked.Y == y) {
+ form.Close ();
+ } else {
+ icon_clicked_time = DateTime.Now;
+ icon_clicked.X = x;
+ icon_clicked.Y = y;
+ }
+
+ return;
+ }
+
+ base.HandleTitleBarDown (x, y);
+
+ if (maximized_title_buttons != null) {
+ maximized_title_buttons.MouseDown (x, y);
+ }
+
+ if (IsMaximized) {
+ XplatUI.InvalidateNC (mdi_container.Parent.Handle);
+ }
+ }
+
+ protected override void HandleTitleBarMouseMove (int x, int y)
+ {
+ base.HandleTitleBarMouseMove (x, y);
+
+ if (maximized_title_buttons != null && maximized_title_buttons.MouseMove (x, y))
+ XplatUI.InvalidateNC (form.MdiParent.Handle);
+ }
+
+ protected override bool HandleLButtonDblClick (ref Message m)
+ {
+
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ // Correct since we are in NC land.
+ NCClientToNC (ref x, ref y);
+
+ if (IconRectangleContains (x, y)) {
+ form.Close ();
+ return true;
+ }
+
+ return base.HandleLButtonDblClick (ref m);
+ }
+
+ protected override bool HandleLButtonDown (ref Message m)
+ {
+
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ // Correct y since we are in NC land.
+ NCClientToNC(ref x, ref y);
+
+ if (IconRectangleContains (x, y)){
+ if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) {
+ form.Close ();
+ return true;
+ } else if (form.Capture) {
+ icon_dont_show_popup = true;
+ }
+ }
+ return base.HandleLButtonDown (ref m);
+ }
+
+ protected override bool ShouldRemoveWindowManager (FormBorderStyle style)
+ {
+ return false;
+ }
+
+ protected override void HandleWindowMove (Message m)
+ {
+ Point pos = Cursor.Position;
+ Point move = MouseMove (pos);
+
+ if (move.X == 0 && move.Y == 0)
+ return;
+
+ int x = virtual_position.X + move.X;
+ int y = virtual_position.Y + move.Y;
+
+ Rectangle client = mdi_container.ClientRectangle;
+ if (mdi_container.VerticalScrollbarVisible)
+ client.Width -= SystemInformation.VerticalScrollBarWidth;
+ if (mdi_container.HorizontalScrollbarVisible)
+ client.Height -= SystemInformation.HorizontalScrollBarHeight;
+
+ UpdateVP (x, y, form.Width, form.Height);
+
+ start = pos;
+ }
+
+ protected override bool HandleNCMouseMove (ref Message m)
+ {
+ XplatUI.RequestAdditionalWM_NCMessages (form.Handle, true, true);
+ return base.HandleNCMouseMove (ref m);
+ }
+
+ protected override void DrawVirtualPosition (Rectangle virtual_position)
+ {
+ ClearVirtualPosition ();
+
+ if (form.Parent != null)
+ XplatUI.DrawReversibleRectangle (form.Parent.Handle, virtual_position, 2);
+ prev_virtual_position = virtual_position;
+ }
+
+ protected override void ClearVirtualPosition ()
+ {
+ if (prev_virtual_position != Rectangle.Empty && form.Parent != null)
+ XplatUI.DrawReversibleRectangle (form.Parent.Handle,
+ prev_virtual_position, 2);
+ prev_virtual_position = Rectangle.Empty;
+ }
+
+ protected override void OnWindowFinishedMoving ()
+ {
+ form.Refresh ();
+ }
+
+ public override bool IsActive {
+ get {
+ if (mdi_container == null)
+ return false;
+ return mdi_container.ActiveMdiChild == form;
+ }
+ }
+
+ protected override void Activate ()
+ {
+ if (mdi_container.ActiveMdiChild != form) {
+ mdi_container.ActivateChild (form);
+ }
+ base.Activate ();
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/Message.cs b/source/ShiftUI/Internal/Message.cs
new file mode 100644
index 0000000..90881c3
--- /dev/null
+++ b/source/ShiftUI/Internal/Message.cs
@@ -0,0 +1,118 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+
+
+// COMPLETE
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Diagnostics;
+
+namespace ShiftUI {
+ public struct Message {
+ private int msg;
+ private IntPtr hwnd;
+ private IntPtr lParam;
+ private IntPtr wParam;
+ private IntPtr result;
+
+ #region Public Instance Properties
+ public IntPtr HWnd {
+ get { return hwnd; }
+ set { hwnd=value; }
+ }
+
+ public IntPtr LParam {
+ get { return lParam; }
+ set { lParam=value; }
+ }
+
+ public int Msg {
+ get { return msg; }
+ set { msg=value; }
+ }
+
+ public IntPtr Result {
+ get { return result; }
+ set { result=value; }
+ }
+
+ public IntPtr WParam {
+ get { return wParam; }
+ set { wParam=value; }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Static Methods
+ public static Message Create(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) {
+ Message new_message = new Message();
+
+ new_message.msg=msg;
+ new_message.hwnd=hWnd;
+ new_message.wParam=wparam;
+ new_message.lParam=lparam;
+ return new_message;
+ }
+
+ public static bool operator == (Message a, Message b)
+ {
+ return (a.hwnd == b.hwnd) && (a.lParam == b.lParam) && (a.msg == b.msg) && (a.result == b.result) && (a.wParam == b.wParam);
+ }
+
+ public static bool operator != (Message a, Message b)
+ {
+ return !(a == b);
+ }
+ #endregion // Public Static Methods
+
+ #region Public Instance Methods
+ public override bool Equals(object o) {
+ if (!(o is Message)) {
+ return false;
+ }
+
+ return ((this.msg == ((Message)o).msg) &&
+ (this.hwnd == ((Message)o).hwnd) &&
+ (this.lParam == ((Message)o).lParam) &&
+ (this.wParam == ((Message)o).wParam) &&
+ (this.result == ((Message)o).result));
+ }
+
+ public override int GetHashCode() {
+ return base.GetHashCode();
+ }
+
+ public object GetLParam(Type cls) {
+ object o = Marshal.PtrToStructure(this.lParam, cls);
+
+ return(o);
+ }
+
+ public override string ToString() {
+ return String.Format ("msg=0x{0:x} ({1}) hwnd=0x{2:x} wparam=0x{3:x} lparam=0x{4:x} result=0x{5:x}", msg, ((Msg) msg).ToString (), hwnd.ToInt32 (), wParam.ToInt32 (), lParam.ToInt32 (), result.ToInt32 ());
+ }
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/MethodInvoker.cs b/source/ShiftUI/Internal/MethodInvoker.cs
new file mode 100644
index 0000000..e0275f8
--- /dev/null
+++ b/source/ShiftUI/Internal/MethodInvoker.cs
@@ -0,0 +1,31 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+namespace ShiftUI {
+ public delegate void MethodInvoker();
+}
diff --git a/source/ShiftUI/Internal/MouseHandler.cs b/source/ShiftUI/Internal/MouseHandler.cs
new file mode 100644
index 0000000..9eb86be
--- /dev/null
+++ b/source/ShiftUI/Internal/MouseHandler.cs
@@ -0,0 +1,228 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.CarbonInternal {
+ internal class MouseHandler : EventHandlerBase, IEventHandler {
+ internal const uint kEventMouseDown = 1;
+ internal const uint kEventMouseUp = 2;
+ internal const uint kEventMouseMoved = 5;
+ internal const uint kEventMouseDragged = 6;
+ internal const uint kEventMouseEntered = 8;
+ internal const uint kEventMouseExited = 9;
+ internal const uint kEventMouseWheelMoved = 10;
+ internal const uint kEventMouseScroll = 11;
+
+ internal const uint kEventParamMouseLocation = 1835822947;
+ internal const uint kEventParamMouseButton = 1835168878;
+ internal const uint kEventParamMouseWheelAxis = 1836540280;
+ internal const uint kEventParamMouseWheelDelta = 1836541036;
+ internal const uint typeLongInteger = 1819242087;
+ internal const uint typeMouseWheelAxis = 1836540280;
+ internal const uint typeMouseButton = 1835168878;
+ internal const uint typeQDPoint = 1363439732;
+
+ internal const uint kEventMouseWheelAxisX = 0;
+ internal const uint kEventMouseWheelAxisY = 1;
+
+ internal const uint DoubleClickInterval = 7500000;
+ internal static ClickStruct ClickPending;
+
+ internal MouseHandler (XplatUICarbon driver) : base (driver) {}
+
+ public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
+ QDPoint qdpoint = new QDPoint ();
+ CGPoint point = new CGPoint ();
+ Rect window_bounds = new Rect ();
+ IntPtr view_handle = IntPtr.Zero;
+ IntPtr window_handle = IntPtr.Zero;
+ bool client = true;
+ ushort button = 0;
+ Hwnd hwnd;
+
+ GetEventParameter (eventref, kEventParamMouseLocation, typeQDPoint, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (QDPoint)), IntPtr.Zero, ref qdpoint);
+ GetEventParameter (eventref, kEventParamMouseButton, typeMouseButton, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (ushort)), IntPtr.Zero, ref button);
+
+ if (button == 1 && ((Driver.ModifierKeys & Keys.Widget) != 0))
+ button = 2;
+
+ point.x = qdpoint.x;
+ point.y = qdpoint.y;
+
+ if (FindWindow (qdpoint, ref window_handle) == 5)
+ return true;
+
+ GetWindowBounds (handle, 33, ref window_bounds);
+ HIViewFindByID (HIViewGetRoot (handle), new HIViewID (EventHandler.kEventClassWindow, 1), ref window_handle);
+
+ point.x -= window_bounds.left;
+ point.y -= window_bounds.top;
+
+ HIViewGetSubviewHit (window_handle, ref point, true, ref view_handle);
+ HIViewConvertPoint (ref point, window_handle, view_handle);
+
+ hwnd = Hwnd.ObjectFromHandle (view_handle);
+
+ if (hwnd != null)
+ client = (hwnd.ClientWindow == view_handle ? true : false);
+
+ if (XplatUICarbon.Grab.Hwnd != IntPtr.Zero) {
+ hwnd = Hwnd.ObjectFromHandle (XplatUICarbon.Grab.Hwnd);
+ client = true;
+ }
+ if (hwnd == null)
+ return true;
+
+ if (client) {
+ qdpoint.x = (short) point.x;
+ qdpoint.y = (short) point.y;
+
+ Driver.ScreenToClient (hwnd.Handle, ref qdpoint);
+ } else {
+ point.x = qdpoint.x;
+ point.y = qdpoint.y;
+ }
+
+ msg.hwnd = hwnd.Handle;
+ msg.lParam = (IntPtr) ((ushort) point.y << 16 | (ushort) point.x);
+
+ switch (kind) {
+ case kEventMouseDown:
+ UpdateMouseState (button, true);
+ msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 1;
+ msg.wParam = Driver.GetMousewParam (0);
+ if (ClickPending.Pending && (((DateTime.Now.Ticks - ClickPending.Time) < DoubleClickInterval) && (msg.hwnd == ClickPending.Hwnd) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
+ msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 3;
+ ClickPending.Pending = false;
+ } else {
+ ClickPending.Pending = true;
+ ClickPending.Hwnd = msg.hwnd;
+ ClickPending.Message = msg.message;
+ ClickPending.wParam = msg.wParam;
+ ClickPending.lParam = msg.lParam;
+ ClickPending.Time = DateTime.Now.Ticks;
+ }
+ break;
+ case kEventMouseUp:
+ UpdateMouseState (button, false);
+ msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 2;
+ msg.wParam = Driver.GetMousewParam (0);
+ break;
+ case kEventMouseDragged:
+ case kEventMouseMoved:
+ if (XplatUICarbon.Grab.Hwnd == IntPtr.Zero) {
+ IntPtr ht = IntPtr.Zero;
+ if (client) {
+ ht = (IntPtr) HitTest.HTCLIENT;
+ NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
+ } else {
+ ht = (IntPtr) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam).ToInt32 ();
+ NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, ht);
+ }
+ }
+ msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE);
+ msg.wParam = Driver.GetMousewParam (0);
+ break;
+ case kEventMouseWheelMoved:
+ case kEventMouseScroll:
+ UInt16 axis = 0;
+ Int32 delta = 0;
+
+ GetEventParameter (eventref, kEventParamMouseWheelAxis, typeMouseWheelAxis, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt16)), IntPtr.Zero, ref axis);
+ GetEventParameter (eventref, kEventParamMouseWheelDelta, typeLongInteger, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (Int32)), IntPtr.Zero, ref delta);
+
+ if (axis == kEventMouseWheelAxisY) {
+ msg.hwnd = XplatUICarbon.FocusWindow;
+ msg.message = Msg.WM_MOUSEWHEEL;
+ msg.wParam = Driver.GetMousewParam (delta*40);
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+ Driver.mouse_position.X = (int) point.x;
+ Driver.mouse_position.Y = (int) point.y;
+ return true;
+ }
+
+ internal bool TranslateMessage (ref MSG msg) {
+ if (msg.message == Msg.WM_MOUSEMOVE || msg.message == Msg.WM_NCMOUSEMOVE) {
+ Hwnd hwnd = Hwnd.ObjectFromHandle (msg.hwnd);
+ if (XplatUICarbon.MouseHwnd == null) {
+ Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero);
+ Cursor.SetCursor (hwnd.Cursor);
+ } else if (XplatUICarbon.MouseHwnd.Handle != hwnd.Handle) {
+ Driver.PostMessage (XplatUICarbon.MouseHwnd.Handle, Msg.WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero);
+ Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero);
+ Cursor.SetCursor (hwnd.Cursor);
+ }
+ XplatUICarbon.MouseHwnd = hwnd;
+ }
+
+ return false;
+ }
+
+ private void UpdateMouseState (int button, bool down) {
+ switch (button) {
+ case 1:
+ if (down) XplatUICarbon.MouseState |= MouseButtons.Left; else XplatUICarbon.MouseState &= ~MouseButtons.Left;
+ break;
+ case 2:
+ if (down) XplatUICarbon.MouseState |= MouseButtons.Right; else XplatUICarbon.MouseState &= ~MouseButtons.Right;
+ break;
+ case 3:
+ if (down) XplatUICarbon.MouseState |= MouseButtons.Middle; else XplatUICarbon.MouseState &= ~MouseButtons.Middle;
+ break;
+ }
+ }
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref QDPoint data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref Int32 data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref ushort data);
+
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern short FindWindow (QDPoint point, ref IntPtr handle);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern int GetWindowBounds (IntPtr handle, uint region, ref Rect bounds);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern int HIViewConvertPoint (ref CGPoint point, IntPtr source_view, IntPtr target_view);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern IntPtr HIViewGetRoot (IntPtr handle);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern int HIViewGetSubviewHit (IntPtr content_view, ref CGPoint point, bool tval, ref IntPtr hit_view);
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern int HIViewFindByID (IntPtr root_window, HIViewID id, ref IntPtr view_handle);
+
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ internal static extern int GetCurrentEventButtonState ();
+ }
+}
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
+ }
+}
diff --git a/source/ShiftUI/Internal/OpacityConverter.cs b/source/ShiftUI/Internal/OpacityConverter.cs
new file mode 100644
index 0000000..89fcc63
--- /dev/null
+++ b/source/ShiftUI/Internal/OpacityConverter.cs
@@ -0,0 +1,74 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Globalization;
+using System.Text;
+
+namespace ShiftUI {
+ public class OpacityConverter : TypeConverter {
+ #region Public Constructors
+ public OpacityConverter() {
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Methods
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
+ if (sourceType == typeof(string)) {
+ return true;
+ }
+ return false;
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
+ if (value is string) {
+ string s;
+
+ s = (string)value;
+ if (s.EndsWith("%")) {
+ s = ((string)value).Substring(0, ((string)value).Length - 1);
+ }
+ return Double.Parse(s, NumberStyles.Any, culture) / 100;
+ }
+ return base.ConvertFrom (context, culture, value);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
+ if (destinationType == typeof(string)) {
+ double v;
+
+ v = ((double)value) * 100;
+ return v.ToString() + "%";
+ }
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs b/source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs
new file mode 100644
index 0000000..f2d9453
--- /dev/null
+++ b/source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs
@@ -0,0 +1,112 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.Collections;
+
+namespace ShiftUI {
+
+ internal class OpenTreeNodeEnumerator : IEnumerator {
+
+ private TreeNode start;
+ private TreeNode current;
+ private bool started;
+
+ public OpenTreeNodeEnumerator (TreeNode start)
+ {
+ this.start = start;
+ }
+
+ public object Current {
+ get { return current; }
+ }
+
+ public TreeNode CurrentNode {
+ get { return current; }
+ }
+
+ public bool MoveNext ()
+ {
+ if (!started) {
+ started = true;
+ current = start;
+ return (current != null);
+ }
+
+ if (current.is_expanded && current.Nodes.Count > 0) {
+ current = current.Nodes [0];
+ return true;
+ }
+
+ TreeNode prev = current;
+ TreeNode next = current.NextNode;
+ while (next == null) {
+ // The next node is null so we need to move back up the tree until we hit the top
+ if (prev.parent == null)
+ return false;
+ prev = prev.parent;
+ if (prev.parent != null)
+ next = prev.NextNode;
+ }
+ current = next;
+ return true;
+ }
+
+ public bool MovePrevious ()
+ {
+ if (!started) {
+ started = true;
+ current = start;
+ return (current != null);
+ }
+
+ if (current.PrevNode != null) {
+ // Drill down as far as possible
+ TreeNode prev = current.PrevNode;
+ TreeNode walk = prev;
+ while (walk != null) {
+ prev = walk;
+ if (!walk.is_expanded)
+ break;
+ walk = walk.LastNode;
+ }
+ current = prev;
+ return true;
+ }
+
+ if (current.Parent == null)
+ return false;
+
+ current = current.Parent;
+ return true;
+ }
+
+ public void Reset ()
+ {
+ started = false;
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/OwnerDrawPropertyBag.cs b/source/ShiftUI/Internal/OwnerDrawPropertyBag.cs
new file mode 100644
index 0000000..c9f8e6f
--- /dev/null
+++ b/source/ShiftUI/Internal/OwnerDrawPropertyBag.cs
@@ -0,0 +1,101 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+using System;
+using System.Drawing;
+using System.Runtime.Serialization;
+
+namespace ShiftUI {
+
+ [Serializable]
+ public class OwnerDrawPropertyBag : MarshalByRefObject, ISerializable {
+
+ private Color fore_color;
+ private Color back_color;
+ private Font font;
+
+ internal OwnerDrawPropertyBag ()
+ {
+ fore_color = back_color = Color.Empty;
+ }
+
+ private OwnerDrawPropertyBag (Color fore_color, Color back_color, Font font)
+ {
+ this.fore_color = fore_color;
+ this.back_color = back_color;
+ this.font = font;
+ }
+
+ protected OwnerDrawPropertyBag(SerializationInfo info, StreamingContext context) {
+ SerializationInfoEnumerator en;
+ SerializationEntry e;
+
+ en = info.GetEnumerator();
+
+ while (en.MoveNext()) {
+ e = en.Current;
+ switch(e.Name) {
+ case "Font": font = (Font)e.Value; break;
+ case "ForeColor": fore_color = (Color)e.Value; break;
+ case "BackColor": back_color = (Color)e.Value; break;
+ }
+ }
+ }
+
+
+ public Color ForeColor {
+ get { return fore_color; }
+ set { fore_color = value; }
+ }
+
+ public Color BackColor {
+ get { return back_color; }
+ set { back_color = value; }
+ }
+
+ public Font Font {
+ get { return font; }
+ set { font = value; }
+ }
+
+ public virtual bool IsEmpty ()
+ {
+ return (font == null && fore_color.IsEmpty && back_color.IsEmpty);
+ }
+
+ void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context)
+ {
+ si.AddValue ("BackColor", BackColor);
+ si.AddValue ("ForeColor", ForeColor);
+ si.AddValue ("Font", Font);
+ }
+
+ public static OwnerDrawPropertyBag Copy (OwnerDrawPropertyBag value)
+ {
+ return new OwnerDrawPropertyBag (value.ForeColor, value.BackColor, value.Font);
+ }
+ }
+}
+
+
diff --git a/source/ShiftUI/Internal/Padding.cs b/source/ShiftUI/Internal/Padding.cs
new file mode 100644
index 0000000..63bdc64
--- /dev/null
+++ b/source/ShiftUI/Internal/Padding.cs
@@ -0,0 +1,170 @@
+// 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) 2005,2006 Novell, Inc. (http://www.novell.com)
+//
+// Author:
+// Pedro Martínez Juliá <[email protected]>
+// Daniel Nauck (dna(at)mono-project(dot)de)
+//
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+
+namespace ShiftUI {
+
+ [Serializable]
+ [TypeConverter(typeof(PaddingConverter))]
+ public struct Padding {
+
+ //NOTE: "_var" field name is required by serialization.
+ private int _bottom;
+ private int _left;
+ private int _right;
+ private int _top;
+ private bool _all;
+
+ public Padding (int all) {
+ _left = all;
+ _right = all;
+ _top = all;
+ _bottom = all;
+ _all = true;
+ }
+
+ public Padding (int left, int top, int right, int bottom) {
+ _left = left;
+ _right = right;
+ _top = top;
+ _bottom = bottom;
+ _all = (_left == _top) && (_left == _right) && (_left == _bottom);
+ }
+
+ public static readonly Padding Empty = new Padding(0);
+
+ [RefreshProperties(RefreshProperties.All)]
+ public int All {
+ get {
+ if(!_all)
+ return -1;
+ else
+ return _top;
+ }
+ set {
+ _all = true;
+ _left = _top = _right = _bottom = value;
+ }
+ }
+
+ [RefreshProperties(RefreshProperties.All)]
+ public int Bottom {
+ get { return _bottom; }
+ set {
+ _bottom = value;
+ _all = false;
+ }
+ }
+
+ [Browsable(false)]
+ public int Horizontal {
+ get { return _left + _right; }
+ }
+
+ [RefreshProperties(RefreshProperties.All)]
+ public int Left {
+ get { return _left; }
+ set {
+ _left = value;
+ _all = false;
+ }
+ }
+
+ [RefreshProperties(RefreshProperties.All)]
+ public int Right {
+ get { return _right; }
+ set {
+ _right = value;
+ _all = false;
+ }
+ }
+
+ [Browsable(false)]
+ public Size Size {
+ get { return new Size(Horizontal, Vertical); }
+ }
+
+ [RefreshProperties(RefreshProperties.All)]
+ public int Top {
+ get { return _top; }
+ set {
+ _top = value;
+ _all = false;
+ }
+ }
+
+ [Browsable(false)]
+ public int Vertical {
+ get { return _top + _bottom; }
+ }
+
+ public static Padding Add (Padding p1, Padding p2) {
+ return p1 + p2;
+ }
+
+ public override bool Equals (object other) {
+ if (other is Padding) {
+ Padding other_aux = (Padding) other;
+ return _left == other_aux.Left &&
+ _top == other_aux.Top &&
+ _right == other_aux.Right &&
+ _bottom == other_aux.Bottom;
+ }
+ return false;
+ }
+
+ public override int GetHashCode () {
+ return _top ^ _bottom ^ _left ^ _right;
+ }
+
+ public static Padding operator+ (Padding p1, Padding p2) {
+ return new Padding(p1.Left + p2.Left, p1.Top + p2.Top, p1.Right + p2.Right, p1.Bottom + p2.Bottom);
+ }
+
+ public static bool operator== (Padding p1, Padding p2) {
+ return p1.Equals(p2);
+ }
+
+ public static bool operator!= (Padding p1, Padding p2) {
+ return !(p1.Equals(p2));
+ }
+
+ public static Padding operator- (Padding p1, Padding p2) {
+ return new Padding(p1.Left - p2.Left, p1.Top - p2.Top, p1.Right - p2.Right, p1.Bottom - p2.Bottom);
+ }
+
+ public static Padding Subtract (Padding p1, Padding p2) {
+ return p1 - p2;
+ }
+
+ public override string ToString () {
+ return "{Left=" + Left + ",Top="+ Top + ",Right=" + Right + ",Bottom=" + Bottom + "}";
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/PaddingConverter.cs b/source/ShiftUI/Internal/PaddingConverter.cs
new file mode 100644
index 0000000..447f65d
--- /dev/null
+++ b/source/ShiftUI/Internal/PaddingConverter.cs
@@ -0,0 +1,125 @@
+// 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) 2007 Novell, Inc.
+//
+
+using System.ComponentModel;
+using System.Collections;
+using System.Reflection;
+using System.Globalization;
+using System.ComponentModel.Design.Serialization; // e.g. InstanceDescriptor
+using System;
+
+namespace ShiftUI
+{
+ public class PaddingConverter : TypeConverter
+ {
+ public PaddingConverter ()
+ {
+ }
+
+ #region Public Instance Methods
+ public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof (string))
+ return true;
+
+ return false;
+ }
+
+ public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof (string))
+ return true;
+ else if (destinationType == typeof(InstanceDescriptor))
+ return true;
+
+ return false;
+ }
+
+ public override object ConvertFrom (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
+ {
+ if ((value == null) || !(value is String))
+ return base.ConvertFrom (context, culture, value);
+
+ if (culture == null)
+ culture = CultureInfo.CurrentCulture;
+
+ string[] parts = ((string)value).Split (culture.TextInfo.ListSeparator.ToCharArray ());
+
+ return new Padding (int.Parse (parts[0].Trim ()), int.Parse (parts[1].Trim ()), int.Parse (parts[2].Trim ()), int.Parse (parts[3].Trim ()));
+ }
+
+ public override object ConvertTo (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+ {
+ if (value is Padding) {
+ Padding p = (Padding)value;
+ if (destinationType == typeof (string)) {
+ if (culture == null)
+ culture = CultureInfo.CurrentCulture;
+ return string.Format ("{0}{4} {1}{4} {2}{4} {3}", p.Left, p.Top, p.Right, p.Bottom, culture.TextInfo.ListSeparator);
+ } else if (destinationType == typeof (InstanceDescriptor)) {
+ Type[] types;
+ Object[] values;
+ if (p.All != -1) {
+ types = new Type[] { typeof(int) };
+ values = new Object[] { p.All };
+ } else {
+ types = new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) };
+ values = new Object[] { p.Left, p.Top, p.Right, p.Bottom };
+ }
+ ConstructorInfo ci = typeof(Padding).GetConstructor (types);
+ return new InstanceDescriptor (ci, values);
+ }
+ }
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ public override object CreateInstance (ITypeDescriptorContext context, IDictionary propertyValues)
+ {
+ if (propertyValues == null)
+ throw new ArgumentNullException ("propertyValues");
+ if (context == null)
+ throw new ArgumentNullException ("context");
+
+ Padding old = (Padding)context.PropertyDescriptor.GetValue (context.Instance);
+ if (old.All == (int)propertyValues["All"])
+ return new Padding ((int)propertyValues["Left"], (int)propertyValues["Top"], (int)propertyValues["Right"], (int)propertyValues["Bottom"]);
+ else
+ return new Padding ((int)propertyValues["All"]);
+ }
+
+ public override bool GetCreateInstanceSupported (ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object value, Attribute[] attributes)
+ {
+ return TypeDescriptor.GetProperties (typeof (Padding), attributes);
+ }
+
+ public override bool GetPropertiesSupported (ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/PaintEventArgs.cs b/source/ShiftUI/Internal/PaintEventArgs.cs
new file mode 100644
index 0000000..0f05b84
--- /dev/null
+++ b/source/ShiftUI/Internal/PaintEventArgs.cs
@@ -0,0 +1,98 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+
+// COMPLETE
+
+using System.Drawing;
+using System;
+
+namespace ShiftUI {
+ public class PaintEventArgs : EventArgs, IDisposable {
+ private Graphics graphics;
+ private Rectangle clip_rectangle;
+ internal bool Handled;
+ private bool disposed;
+
+ #region Public Constructors
+ public PaintEventArgs (Graphics graphics, Rectangle clipRect)
+ {
+ if (graphics == null)
+ throw new ArgumentNullException ("graphics");
+
+ this.graphics=graphics;
+ this.clip_rectangle=clipRect;
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ public Rectangle ClipRectangle {
+ get {
+ return this.clip_rectangle;
+ }
+ }
+
+ public Graphics Graphics {
+ get {
+ return this.graphics;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Instance Methods
+ public void Dispose() {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion // Public Instance Methods
+
+ // Returns the previous graphics
+ internal Graphics SetGraphics (Graphics g)
+ {
+ Graphics res = graphics;
+ graphics = g;
+
+ return res;
+ }
+
+ internal void SetClip (Rectangle clip)
+ {
+ clip_rectangle = clip;
+ }
+
+ #region Protected Instance Methods
+ ~PaintEventArgs() {
+ Dispose(false);
+ }
+
+ protected virtual void Dispose (bool disposing)
+ {
+ if (!disposed) {
+ disposed = true;
+ }
+ }
+ #endregion // Protected Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/PaintEventHandler.cs b/source/ShiftUI/Internal/PaintEventHandler.cs
new file mode 100644
index 0000000..9e074ee
--- /dev/null
+++ b/source/ShiftUI/Internal/PaintEventHandler.cs
@@ -0,0 +1,33 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public delegate void PaintEventHandler (object sender, PaintEventArgs e);
+}
diff --git a/source/ShiftUI/Internal/Pasteboard.cs b/source/ShiftUI/Internal/Pasteboard.cs
new file mode 100644
index 0000000..57a75b4
--- /dev/null
+++ b/source/ShiftUI/Internal/Pasteboard.cs
@@ -0,0 +1,106 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton ([email protected])
+//
+//
+
+
+using System;
+using System.Runtime.InteropServices;
+using ShiftUI;
+
+namespace ShiftUI.CarbonInternal {
+ internal class Pasteboard {
+ private static IntPtr primary_pbref;
+ private static IntPtr app_pbref;
+
+ private static IntPtr internal_format;
+
+ static Pasteboard () {
+ PasteboardCreate (XplatUICarbon.__CFStringMakeConstantString("com.apple.pasteboard.clipboard"), ref primary_pbref);
+ PasteboardCreate (IntPtr.Zero, ref app_pbref);
+ internal_format = XplatUICarbon.__CFStringMakeConstantString ("com.novell.mono.mwf.pasteboard");
+ }
+
+ internal static object Retrieve (IntPtr pbref, int key) {
+ UInt32 count = 0;
+
+ key = (int)internal_format;
+
+ PasteboardGetItemCount (pbref, ref count);
+ for (int i = 1; i <= count; i++) {
+ UInt32 itemid = 0;
+
+ PasteboardGetItemIdentifier (pbref, (UInt32)i, ref itemid);
+ //FIXME: We should get all the flavors and enumerate but we're cheating for now
+ if (itemid == 0xFACE) {
+ IntPtr pbdata = IntPtr.Zero;
+
+ PasteboardCopyItemFlavorData (pbref, (UInt32)0xFACE, (UInt32)key, ref pbdata);
+ if (pbdata != IntPtr.Zero) {
+ GCHandle handle = (GCHandle) Marshal.ReadIntPtr (CFDataGetBytePtr (pbdata));
+
+ return handle.Target;
+ }
+ }
+ }
+ return null;
+ }
+
+ internal static void Store (IntPtr pbref, object data, int key) {
+ IntPtr gcdata = (IntPtr) GCHandle.Alloc (data);
+ IntPtr pbdata = CFDataCreate (IntPtr.Zero, ref gcdata, Marshal.SizeOf (typeof (IntPtr)));
+
+ key = (int)internal_format;
+
+ PasteboardClear (pbref);
+ PasteboardPutItemFlavor (pbref, (UInt32)0xFACE, (UInt32)key, pbdata, 0);
+ }
+
+ internal static IntPtr Primary {
+ get { return primary_pbref; }
+ }
+
+ internal static IntPtr Application {
+ get { return app_pbref; }
+ }
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern IntPtr CFDataCreate (IntPtr allocator, ref IntPtr buf, Int32 length);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern IntPtr CFDataGetBytePtr (IntPtr data);
+
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int PasteboardClear (IntPtr pbref);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int PasteboardCreate (IntPtr str, ref IntPtr pbref);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int PasteboardCopyItemFlavorData (IntPtr pbref, UInt32 itemid, UInt32 key, ref IntPtr data);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int PasteboardGetItemCount (IntPtr pbref, ref UInt32 count);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int PasteboardGetItemIdentifier (IntPtr pbref, UInt32 itemindex, ref UInt32 itemid);
+ [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int PasteboardPutItemFlavor (IntPtr pbref, UInt32 itemid, UInt32 key, IntPtr data, UInt32 flags);
+ }
+}
diff --git a/source/ShiftUI/Internal/PopupEventArgs.cs b/source/ShiftUI/Internal/PopupEventArgs.cs
new file mode 100644
index 0000000..b11b837
--- /dev/null
+++ b/source/ShiftUI/Internal/PopupEventArgs.cs
@@ -0,0 +1,71 @@
+//
+// PopupEventArgs.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+using System.ComponentModel;
+using System.Drawing;
+
+namespace ShiftUI
+{
+ public class PopupEventArgs : CancelEventArgs
+ {
+ private Widget associated_control;
+ private IWin32Window associated_window;
+ private bool is_balloon;
+ private Size tool_tip_size;
+
+ #region Public Constructors
+ public PopupEventArgs (IWin32Window associatedWindow, Widget associatedControl, bool isBalloon, Size size) : base ()
+ {
+ this.associated_window = associatedWindow;
+ this.associated_control = associatedControl;
+ this.is_balloon = isBalloon;
+ this.tool_tip_size = size;
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ public Widget AssociatedControl {
+ get { return this.associated_control; }
+ }
+
+ public IWin32Window AssociatedWindow {
+ get { return this.associated_window; }
+ }
+
+ public bool IsBalloon {
+ get { return this.is_balloon; }
+ }
+
+ public Size ToolTipSize {
+ get { return this.tool_tip_size; }
+ set { this.tool_tip_size = value; }
+ }
+ #endregion // Public Instance Properties
+ }
+}
diff --git a/source/ShiftUI/Internal/PopupEventHandler.cs b/source/ShiftUI/Internal/PopupEventHandler.cs
new file mode 100644
index 0000000..ba87315
--- /dev/null
+++ b/source/ShiftUI/Internal/PopupEventHandler.cs
@@ -0,0 +1,32 @@
+//
+// PopupEventHandler.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+namespace ShiftUI
+{
+ public delegate void PopupEventHandler (object sender, PopupEventArgs e);
+}
diff --git a/source/ShiftUI/Internal/PreProcessControlState.cs b/source/ShiftUI/Internal/PreProcessControlState.cs
new file mode 100644
index 0000000..bd573a5
--- /dev/null
+++ b/source/ShiftUI/Internal/PreProcessControlState.cs
@@ -0,0 +1,38 @@
+//
+// PreProcessWidgetstate.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+namespace ShiftUI
+{
+ public enum PreProcessWidgetstate
+ {
+ MessageProcessed = 0,
+ MessageNeeded = 1,
+ MessageNotNeeded = 2
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/ProfessionalColorTable.cs b/source/ShiftUI/Internal/ProfessionalColorTable.cs
new file mode 100644
index 0000000..ff42d37
--- /dev/null
+++ b/source/ShiftUI/Internal/ProfessionalColorTable.cs
@@ -0,0 +1,654 @@
+//
+// ProfessionalColorTable.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System.Drawing;
+using ShiftUI.VisualStyles;
+
+namespace ShiftUI
+{
+ public class ProfessionalColorTable
+ {
+ #region Private Variables
+ private bool use_system_colors = false;
+
+ private Color button_checked_gradient_begin;
+ private Color button_checked_gradient_end;
+ private Color button_checked_gradient_middle;
+ private Color button_checked_highlight;
+ private Color button_checked_highlight_border;
+ private Color button_pressed_border;
+ private Color button_pressed_gradient_begin;
+ private Color button_pressed_gradient_end;
+ private Color button_pressed_gradient_middle;
+ private Color button_pressed_highlight;
+ private Color button_pressed_highlight_border;
+ private Color button_selected_border;
+ private Color button_selected_gradient_begin;
+ private Color button_selected_gradient_end;
+ private Color button_selected_gradient_middle;
+ private Color button_selected_highlight;
+ private Color button_selected_highlight_border;
+ private Color check_background;
+ private Color check_pressed_background;
+ private Color check_selected_background;
+ private Color grip_dark;
+ private Color grip_light;
+ private Color image_margin_gradient_begin;
+ private Color image_margin_gradient_end;
+ private Color image_margin_gradient_middle;
+ private Color image_margin_revealed_gradient_begin;
+ private Color image_margin_revealed_gradient_end;
+ private Color image_margin_revealed_gradient_middle;
+ private Color menu_border;
+ private Color menu_item_border;
+ private Color menu_item_pressed_gradient_begin;
+ private Color menu_item_pressed_gradient_end;
+ private Color menu_item_pressed_gradient_middle;
+ private Color menu_item_selected;
+ private Color menu_item_selected_gradient_begin;
+ private Color menu_item_selected_gradient_end;
+ private Color menu_strip_gradient_begin;
+ private Color menu_strip_gradient_end;
+ private Color overflow_button_gradient_begin;
+ private Color overflow_button_gradient_end;
+ private Color overflow_button_gradient_middle;
+ private Color rafting_container_gradient_begin;
+ private Color rafting_container_gradient_end;
+ private Color separator_dark;
+ private Color separator_light;
+ private Color status_strip_gradient_begin;
+ private Color status_strip_gradient_end;
+ private Color tool_strip_border;
+ private Color tool_strip_content_panel_gradient_begin;
+ private Color tool_strip_content_panel_gradient_end;
+ private Color tool_strip_drop_down_background;
+ private Color tool_strip_gradient_begin;
+ private Color tool_strip_gradient_end;
+ private Color tool_strip_gradient_middle;
+ private Color tool_strip_panel_gradient_begin;
+ private Color tool_strip_panel_gradient_end;
+ #endregion
+
+ #region Public Constructor
+ public ProfessionalColorTable ()
+ {
+ CalculateColors ();
+ }
+ #endregion
+
+ #region Public Properties
+ public virtual Color ButtonCheckedGradientBegin { get { return this.button_checked_gradient_begin; } }
+ public virtual Color ButtonCheckedGradientEnd { get { return this.button_checked_gradient_end; } }
+ public virtual Color ButtonCheckedGradientMiddle { get { return this.button_checked_gradient_middle; } }
+ public virtual Color ButtonCheckedHighlight { get { return this.button_checked_highlight; } }
+ public virtual Color ButtonCheckedHighlightBorder { get { return this.button_checked_highlight_border; } }
+ public virtual Color ButtonPressedBorder { get { return this.button_pressed_border; } }
+ public virtual Color ButtonPressedGradientBegin { get { return this.button_pressed_gradient_begin; } }
+ public virtual Color ButtonPressedGradientEnd { get { return this.button_pressed_gradient_end; } }
+ public virtual Color ButtonPressedGradientMiddle { get { return this.button_pressed_gradient_middle; } }
+ public virtual Color ButtonPressedHighlight { get { return this.button_pressed_highlight; } }
+ public virtual Color ButtonPressedHighlightBorder { get { return this.button_pressed_highlight_border; } }
+ public virtual Color ButtonSelectedBorder { get { return this.button_selected_border; } }
+ public virtual Color ButtonSelectedGradientBegin { get { return this.button_selected_gradient_begin; } }
+ public virtual Color ButtonSelectedGradientEnd { get { return this.button_selected_gradient_end; } }
+ public virtual Color ButtonSelectedGradientMiddle { get { return this.button_selected_gradient_middle; } }
+ public virtual Color ButtonSelectedHighlight { get { return this.button_selected_highlight; } }
+ public virtual Color ButtonSelectedHighlightBorder { get { return this.button_selected_highlight_border; } }
+ public virtual Color CheckBackground { get { return this.check_background; } }
+ public virtual Color CheckPressedBackground { get { return this.check_pressed_background; } }
+ public virtual Color CheckSelectedBackground { get { return this.check_selected_background; } }
+ public virtual Color GripDark { get { return this.grip_dark; } }
+ public virtual Color GripLight { get { return this.grip_light; } }
+ public virtual Color ImageMarginGradientBegin { get { return this.image_margin_gradient_begin; } }
+ public virtual Color ImageMarginGradientEnd { get { return this.image_margin_gradient_end; } }
+ public virtual Color ImageMarginGradientMiddle { get { return this.image_margin_gradient_middle; } }
+ public virtual Color ImageMarginRevealedGradientBegin { get { return this.image_margin_revealed_gradient_begin; } }
+ public virtual Color ImageMarginRevealedGradientEnd { get { return this.image_margin_revealed_gradient_end; } }
+ public virtual Color ImageMarginRevealedGradientMiddle { get { return this.image_margin_revealed_gradient_middle; } }
+ public virtual Color MenuBorder { get { return this.menu_border; } }
+ public virtual Color MenuItemBorder { get { return this.menu_item_border; } }
+ public virtual Color MenuItemPressedGradientBegin { get { return this.menu_item_pressed_gradient_begin; } }
+ public virtual Color MenuItemPressedGradientEnd { get { return this.menu_item_pressed_gradient_end; } }
+ public virtual Color MenuItemPressedGradientMiddle { get { return this.menu_item_pressed_gradient_middle; } }
+ public virtual Color MenuItemSelected { get { return this.menu_item_selected; } }
+ public virtual Color MenuItemSelectedGradientBegin { get { return this.menu_item_selected_gradient_begin; } }
+ public virtual Color MenuItemSelectedGradientEnd { get { return this.menu_item_selected_gradient_end; } }
+ public virtual Color MenuStripGradientBegin { get { return this.menu_strip_gradient_begin; } }
+ public virtual Color MenuStripGradientEnd { get { return this.menu_strip_gradient_end; } }
+ public virtual Color OverflowButtonGradientBegin { get { return this.overflow_button_gradient_begin; } }
+ public virtual Color OverflowButtonGradientEnd { get { return this.overflow_button_gradient_end; } }
+ public virtual Color OverflowButtonGradientMiddle { get { return this.overflow_button_gradient_middle; } }
+ public virtual Color RaftingContainerGradientBegin { get { return this.rafting_container_gradient_begin; } }
+ public virtual Color RaftingContainerGradientEnd { get { return this.rafting_container_gradient_end; } }
+ public virtual Color SeparatorDark { get { return this.separator_dark; } }
+ public virtual Color SeparatorLight { get { return this.separator_light; } }
+ public virtual Color StatusStripGradientBegin { get { return this.status_strip_gradient_begin; } }
+ public virtual Color StatusStripGradientEnd { get { return this.status_strip_gradient_end; } }
+ public virtual Color ToolStripBorder { get { return this.tool_strip_border; } }
+ public virtual Color ToolStripContentPanelGradientBegin { get { return this.tool_strip_content_panel_gradient_begin; } }
+ public virtual Color ToolStripContentPanelGradientEnd { get { return this.tool_strip_content_panel_gradient_end; } }
+ public virtual Color ToolStripDropDownBackground { get { return this.tool_strip_drop_down_background; } }
+ public virtual Color ToolStripGradientBegin { get { return this.tool_strip_gradient_begin; } }
+ public virtual Color ToolStripGradientEnd { get { return this.tool_strip_gradient_end; } }
+ public virtual Color ToolStripGradientMiddle { get { return this.tool_strip_gradient_middle; } }
+ public virtual Color ToolStripPanelGradientBegin { get { return this.tool_strip_panel_gradient_begin; } }
+ public virtual Color ToolStripPanelGradientEnd { get { return this.tool_strip_panel_gradient_end; } }
+ public bool UseSystemColors {
+ get { return use_system_colors; }
+ set {
+ if (value != use_system_colors) {
+ use_system_colors = value; CalculateColors ();
+ }
+ }
+ }
+ #endregion
+
+ #region Private Methods
+ private void CalculateColors ()
+ {
+ switch (GetCurrentStyle ()) {
+ case ColorSchemes.Classic:
+ button_checked_gradient_begin = Color.Empty;
+ button_checked_gradient_end = Color.Empty;
+ button_checked_gradient_middle = Color.Empty;
+ button_checked_highlight = Color.FromArgb (184, 191, 211);
+ button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_pressed_border = Color.FromKnownColor (KnownColor.Highlight);
+ button_pressed_gradient_begin = Color.FromArgb (133, 146, 181);
+ button_pressed_gradient_end = Color.FromArgb (133, 146, 181);
+ button_pressed_gradient_middle = Color.FromArgb (133, 146, 181);
+ button_pressed_highlight = Color.FromArgb (131, 144, 179);
+ button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_selected_border = Color.FromKnownColor (KnownColor.Highlight);
+ button_selected_gradient_begin = Color.FromArgb (182, 189, 210);
+ button_selected_gradient_end = Color.FromArgb (182, 189, 210);
+ button_selected_gradient_middle = Color.FromArgb (182, 189, 210);
+ button_selected_highlight = Color.FromArgb (184, 191, 211);
+ button_selected_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ check_background = Color.FromKnownColor (KnownColor.Highlight);
+ check_pressed_background = Color.FromArgb (133, 146, 181);
+ check_selected_background = Color.FromArgb (133, 146, 181);
+
+ grip_dark = Color.FromArgb (160, 160, 160);
+ grip_light = SystemColors.Window;
+
+ image_margin_gradient_begin = Color.FromArgb (245, 244, 242);
+ image_margin_gradient_end = SystemColors.Control;
+ image_margin_gradient_middle = Color.FromArgb (234, 232, 228);
+ image_margin_revealed_gradient_begin = Color.FromArgb (238, 236, 233);
+ image_margin_revealed_gradient_end = Color.FromArgb (216, 213, 206);
+ image_margin_revealed_gradient_middle = Color.FromArgb (225, 222, 217);
+
+ menu_border = Color.FromArgb (102, 102, 102);
+ menu_item_border = SystemColors.Highlight;
+
+ menu_item_pressed_gradient_begin = Color.FromArgb (245, 244, 242);
+ menu_item_pressed_gradient_end = Color.FromArgb (234, 232, 228);
+ menu_item_pressed_gradient_middle = Color.FromArgb (225, 222, 217);
+ menu_item_selected = SystemColors.Window;
+ menu_item_selected_gradient_begin = Color.FromArgb (182, 189, 210);
+ menu_item_selected_gradient_end = Color.FromArgb (182, 189, 210);
+
+ menu_strip_gradient_begin = SystemColors.ButtonFace;
+ menu_strip_gradient_end = Color.FromArgb (246, 245, 244);
+
+ overflow_button_gradient_begin = Color.FromArgb (225, 222, 217);
+ overflow_button_gradient_end = SystemColors.ButtonShadow;
+ overflow_button_gradient_middle = Color.FromArgb (216, 213, 206);
+
+ rafting_container_gradient_begin = SystemColors.ButtonFace;
+ rafting_container_gradient_end = Color.FromArgb (246, 245, 244);
+
+ separator_dark = Color.FromArgb (166, 166, 166);
+ separator_light = SystemColors.ButtonHighlight;
+
+ status_strip_gradient_begin = SystemColors.ButtonFace;
+ status_strip_gradient_end = Color.FromArgb (246, 245, 244);
+
+ tool_strip_border = Color.FromArgb (219, 216, 209);
+ tool_strip_content_panel_gradient_begin = SystemColors.ButtonFace;
+ tool_strip_content_panel_gradient_end = Color.FromArgb (246, 245, 244);
+ tool_strip_drop_down_background = SystemColors.Window;
+
+ tool_strip_gradient_begin = Color.FromArgb (245, 244, 242);
+ tool_strip_gradient_end = SystemColors.ButtonFace;
+ tool_strip_gradient_middle = Color.FromArgb (234, 232, 228);
+
+ tool_strip_panel_gradient_begin = SystemColors.ButtonFace;
+ tool_strip_panel_gradient_end = Color.FromArgb (246, 245, 244);
+ break;
+ case ColorSchemes.NormalColor:
+ button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (255, 223, 154);
+ button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (255, 166, 76);
+ button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (255, 195, 116);
+ button_checked_highlight = Color.FromArgb (195, 211, 237);
+ button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+ button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (0, 0, 128);
+ button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (254, 128, 62);
+ button_pressed_gradient_end = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (255, 223, 154);
+ button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (255, 177, 109);
+ button_pressed_highlight = use_system_colors ? Color.FromArgb (150, 179, 225) : Color.FromArgb (150, 179, 225);
+ button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+ button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (0, 0, 128);
+ button_selected_gradient_begin = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 255, 222);
+ button_selected_gradient_end = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 203, 136);
+ button_selected_gradient_middle = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 225, 172);
+ button_selected_highlight = use_system_colors ? Color.FromArgb (195, 211, 237) : Color.FromArgb (195, 211, 237);
+ button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (0, 0, 128);
+
+ check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (255, 192, 111);
+ check_pressed_background = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (254, 128, 62);
+ check_selected_background = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (254, 128, 62);
+
+ grip_dark = use_system_colors ? Color.FromArgb (193, 190, 179) : Color.FromArgb (39, 65, 118);
+ grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255);
+
+ image_margin_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (227, 239, 255);
+ image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (123, 164, 224);
+ image_margin_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (203, 225, 252);
+ image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (247, 246, 239) : Color.FromArgb (203, 221, 246);
+ image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (114, 155, 215);
+ image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (161, 197, 249);
+
+ menu_border = use_system_colors ? Color.FromArgb (138, 134, 122) : Color.FromArgb (0, 45, 150);
+ menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (0, 0, 128);
+
+ menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (227, 239, 255);
+ menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (123, 164, 224);
+ menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (161, 197, 249);
+ menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 238, 194);
+ menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 255, 222);
+ menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 203, 136);
+
+ menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245);
+ menu_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250);
+
+ overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (127, 177, 250);
+ overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (0, 53, 145);
+ overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (82, 127, 208);
+
+ rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245);
+ rafting_container_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250);
+
+ separator_dark = use_system_colors ? Color.FromArgb (197, 194, 184) : Color.FromArgb (106, 140, 203);
+ separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (241, 249, 255);
+
+ status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245);
+ status_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250);
+
+ tool_strip_border = use_system_colors ? Color.FromArgb (239, 237, 222) : Color.FromArgb (59, 97, 156);
+ tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245);
+ tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250);
+ tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (252, 252, 249) : Color.FromArgb (246, 246, 246);
+
+ tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (227, 239, 255);
+ tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (123, 164, 224);
+ tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (203, 225, 252);
+
+ tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245);
+ tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250);
+ break;
+ case ColorSchemes.HomeStead:
+ button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (255, 223, 154);
+ button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (255, 166, 76);
+ button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (255, 195, 116);
+ button_checked_highlight = Color.FromArgb (223, 227, 213);
+ button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (63, 93, 56);
+ button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (254, 128, 62);
+ button_pressed_gradient_end = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (255, 223, 154);
+ button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (255, 177, 109);
+ button_pressed_highlight = use_system_colors ? Color.FromArgb (200, 206, 182) : Color.FromArgb (200, 206, 182);
+ button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (63, 93, 56);
+ button_selected_gradient_begin = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 255, 222);
+ button_selected_gradient_end = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 203, 136);
+ button_selected_gradient_middle = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 225, 172);
+ button_selected_highlight = use_system_colors ? Color.FromArgb (223, 227, 213) : Color.FromArgb (223, 227, 213);
+ button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (63, 93, 56);
+
+ check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (255, 192, 111);
+ check_pressed_background = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (254, 128, 62);
+ check_selected_background = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (254, 128, 62);
+
+ grip_dark = use_system_colors ? Color.FromArgb (193, 190, 179) : Color.FromArgb (81, 94, 51);
+ grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255);
+
+ image_margin_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (255, 255, 237);
+ image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (181, 196, 143);
+ image_margin_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (206, 220, 167);
+ image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (247, 246, 239) : Color.FromArgb (230, 230, 209);
+ image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (160, 177, 116);
+ image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (186, 201, 143);
+
+ menu_border = use_system_colors ? Color.FromArgb (138, 134, 122) : Color.FromArgb (117, 141, 94);
+ menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (63, 93, 56);
+
+ menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (237, 240, 214);
+ menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (181, 196, 143);
+ menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (186, 201, 143);
+ menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 238, 194);
+ menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 255, 222);
+ menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 203, 136);
+
+ menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167);
+ menu_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228);
+
+ overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (186, 204, 150);
+ overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (96, 119, 107);
+ overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (141, 160, 107);
+
+ rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167);
+ rafting_container_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228);
+
+ separator_dark = use_system_colors ? Color.FromArgb (197, 194, 184) : Color.FromArgb (96, 128, 88);
+ separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (244, 247, 222);
+
+ status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167);
+ status_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228);
+
+ tool_strip_border = use_system_colors ? Color.FromArgb (239, 237, 222) : Color.FromArgb (96, 128, 88);
+ tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167);
+ tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228);
+ tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (252, 252, 249) : Color.FromArgb (244, 244, 238);
+
+ tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (255, 255, 237);
+ tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (181, 196, 143);
+ tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (206, 220, 167);
+
+ tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167);
+ tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228);
+ break;
+ case ColorSchemes.Metallic:
+ button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (255, 223, 154);
+ button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (255, 166, 76);
+ button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (255, 195, 116);
+ button_checked_highlight = Color.FromArgb (231, 232, 235);
+ button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (75, 75, 111);
+ button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (254, 128, 62);
+ button_pressed_gradient_end = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (255, 223, 154);
+ button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (255, 177, 109);
+ button_pressed_highlight = use_system_colors ? Color.FromArgb (215, 216, 222) : Color.FromArgb (215, 216, 222);
+ button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (75, 75, 111);
+ button_selected_gradient_begin = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 255, 222);
+ button_selected_gradient_end = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 203, 136);
+ button_selected_gradient_middle = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 225, 172);
+ button_selected_highlight = use_system_colors ? Color.FromArgb (231, 232, 235) : Color.FromArgb (231, 232, 235);
+ button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (75, 75, 111);
+
+ check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (255, 192, 111);
+ check_pressed_background = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (254, 128, 62);
+ check_selected_background = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (254, 128, 62);
+
+ grip_dark = use_system_colors ? Color.FromArgb (182, 182, 185) : Color.FromArgb (84, 84, 117);
+ grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255);
+
+ image_margin_gradient_begin = use_system_colors ? Color.FromArgb (248, 248, 249) : Color.FromArgb (249, 249, 255);
+ image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (147, 145, 176);
+ image_margin_gradient_middle = use_system_colors ? Color.FromArgb (240, 239, 241) : Color.FromArgb (225, 226, 236);
+ image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (243, 242, 244) : Color.FromArgb (215, 215, 226);
+ image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (227, 226, 230) : Color.FromArgb (118, 116, 151);
+ image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (233, 233, 235) : Color.FromArgb (184, 185, 202);
+
+ menu_border = use_system_colors ? Color.FromArgb (126, 126, 129) : Color.FromArgb (124, 124, 148);
+ menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (75, 75, 111);
+
+ menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (248, 248, 249) : Color.FromArgb (232, 233, 242);
+ menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (240, 239, 241) : Color.FromArgb (172, 170, 194);
+ menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (233, 233, 235) : Color.FromArgb (184, 185, 202);
+ menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 238, 194);
+ menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 255, 222);
+ menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 203, 136);
+
+ menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229);
+ menu_strip_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247);
+
+ overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (233, 233, 235) : Color.FromArgb (186, 185, 206);
+ overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (118, 116, 146);
+ overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (227, 226, 230) : Color.FromArgb (156, 155, 180);
+
+ rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229);
+ rafting_container_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247);
+
+ separator_dark = use_system_colors ? Color.FromArgb (186, 186, 189) : Color.FromArgb (110, 109, 143);
+ separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (255, 255, 255);
+
+ status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229);
+ status_strip_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247);
+
+ tool_strip_border = use_system_colors ? Color.FromArgb (229, 228, 232) : Color.FromArgb (124, 124, 148);
+ tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229);
+ tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247);
+ tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (253, 250, 255);
+
+ tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (248, 248, 249) : Color.FromArgb (249, 249, 255);
+ tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (147, 145, 176);
+ tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (240, 239, 241) : Color.FromArgb (225, 226, 236);
+
+ tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229);
+ tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247);
+ break;
+ case ColorSchemes.MediaCenter:
+ button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (226, 229, 238);
+ button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (226, 229, 238);
+ button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (226, 229, 238);
+ button_checked_highlight = Color.FromArgb (196, 208, 229);
+ button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168);
+ button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (153, 175, 212);
+ button_pressed_gradient_end = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (153, 175, 212);
+ button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (153, 175, 212);
+ button_pressed_highlight = use_system_colors ? Color.FromArgb (152, 173, 210) : Color.FromArgb (152, 173, 210);
+ button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168);
+ button_selected_gradient_begin = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229);
+ button_selected_gradient_end = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229);
+ button_selected_gradient_middle = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229);
+ button_selected_highlight = use_system_colors ? Color.FromArgb (196, 208, 229) : Color.FromArgb (196, 208, 229);
+ button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168);
+
+ check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (226, 229, 238);
+ check_pressed_background = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (51, 94, 168);
+ check_selected_background = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (51, 94, 168);
+
+ grip_dark = use_system_colors ? Color.FromArgb (189, 188, 191) : Color.FromArgb (189, 188, 191);
+ grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255);
+
+ image_margin_gradient_begin = use_system_colors ? Color.FromArgb (250, 250, 251) : Color.FromArgb (252, 252, 252);
+ image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (235, 233, 237);
+ image_margin_gradient_middle = use_system_colors ? Color.FromArgb (245, 244, 246) : Color.FromArgb (245, 244, 246);
+ image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (247, 246, 248) : Color.FromArgb (247, 246, 248);
+ image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (237, 235, 239) : Color.FromArgb (228, 226, 230);
+ image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (241, 240, 242) : Color.FromArgb (241, 240, 242);
+
+ menu_border = use_system_colors ? Color.FromArgb (134, 133, 136) : Color.FromArgb (134, 133, 136);
+ menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (51, 94, 168);
+
+ menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (250, 250, 251) : Color.FromArgb (252, 252, 252);
+ menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (245, 244, 246) : Color.FromArgb (245, 244, 246);
+ menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (241, 240, 242) : Color.FromArgb (241, 240, 242);
+ menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (194, 207, 229);
+ menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229);
+ menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229);
+
+ menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237);
+ menu_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251);
+
+ overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (241, 240, 242) : Color.FromArgb (242, 242, 242);
+ overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (167, 166, 170);
+ overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (237, 235, 239) : Color.FromArgb (224, 224, 225);
+
+ rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237);
+ rafting_container_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251);
+
+ separator_dark = use_system_colors ? Color.FromArgb (193, 193, 196) : Color.FromArgb (193, 193, 196);
+ separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (255, 255, 255);
+
+ status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237);
+ status_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251);
+
+ tool_strip_border = use_system_colors ? Color.FromArgb (238, 237, 240) : Color.FromArgb (238, 237, 240);
+ tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237);
+ tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251);
+ tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (252, 252, 252) : Color.FromArgb (252, 252, 252);
+
+ tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (250, 250, 251) : Color.FromArgb (252, 252, 252);
+ tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237);
+ tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (245, 244, 246) : Color.FromArgb (245, 244, 246);
+
+ tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237);
+ tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251);
+ break;
+ case ColorSchemes.Aero:
+ button_checked_gradient_begin = Color.Empty;
+ button_checked_gradient_end = Color.Empty;
+ button_checked_gradient_middle = Color.Empty;
+ button_checked_highlight = Color.FromArgb (196, 225, 255);
+ button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_pressed_border = Color.FromKnownColor (KnownColor.Highlight);
+ button_pressed_gradient_begin = Color.FromArgb (153, 204, 255);
+ button_pressed_gradient_end = Color.FromArgb (153, 204, 255);
+ button_pressed_gradient_middle = Color.FromArgb (153, 204, 255);
+ button_pressed_highlight = Color.FromArgb (152, 203, 255);
+ button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168);
+ button_selected_gradient_begin = Color.FromArgb (194, 224, 255);
+ button_selected_gradient_end = Color.FromArgb (194, 224, 255);
+ button_selected_gradient_middle = Color.FromArgb (194, 224, 255);
+ button_selected_highlight = Color.FromArgb (196, 225, 255);
+ button_selected_highlight_border = Color.FromKnownColor (KnownColor.Highlight);
+
+ check_background = Color.FromKnownColor (KnownColor.Highlight);
+ check_pressed_background = Color.FromArgb (153, 204, 255);
+ check_selected_background = Color.FromArgb (153, 204, 255);
+
+ grip_dark = Color.FromArgb (184, 184, 184);
+ grip_light = SystemColors.Window;
+
+ image_margin_gradient_begin = Color.FromArgb (252, 252, 252);
+ image_margin_gradient_end = SystemColors.Control;
+ image_margin_gradient_middle = Color.FromArgb (250, 250, 250);
+ image_margin_revealed_gradient_begin = Color.FromArgb (251, 251, 251);
+ image_margin_revealed_gradient_end = Color.FromArgb (245, 245, 245);
+ image_margin_revealed_gradient_middle = Color.FromArgb (247, 247, 247);
+
+ menu_border = Color.FromArgb (128, 128, 128);
+ menu_item_border = SystemColors.Highlight;
+
+ menu_item_pressed_gradient_begin = Color.FromArgb (252, 252, 252);
+ menu_item_pressed_gradient_end = Color.FromArgb (250, 250, 250);
+ menu_item_pressed_gradient_middle = Color.FromArgb (247, 247, 247);
+ menu_item_selected = SystemColors.Window;
+ menu_item_selected_gradient_begin = Color.FromArgb (194, 224, 255);
+ menu_item_selected_gradient_end = Color.FromArgb (194, 224, 255);
+
+ menu_strip_gradient_begin = SystemColors.ButtonFace;
+ menu_strip_gradient_end = Color.FromArgb (253, 253, 253);
+
+ overflow_button_gradient_begin = Color.FromArgb (247, 247, 247);
+ overflow_button_gradient_end = SystemColors.ButtonShadow;
+ overflow_button_gradient_middle = Color.FromArgb (245, 245, 245);
+
+ rafting_container_gradient_begin = SystemColors.ButtonFace;
+ rafting_container_gradient_end = Color.FromArgb (253, 253, 253);
+
+ separator_dark = Color.FromArgb (189, 189, 189);
+ separator_light = SystemColors.ButtonHighlight;
+
+ status_strip_gradient_begin = SystemColors.ButtonFace;
+ status_strip_gradient_end = Color.FromArgb (253, 253, 253);
+
+ tool_strip_border = Color.FromArgb (246, 246, 246);
+ tool_strip_content_panel_gradient_begin = SystemColors.ButtonFace;
+ tool_strip_content_panel_gradient_end = Color.FromArgb (253, 253, 253);
+ tool_strip_drop_down_background = Color.FromArgb (253, 253, 253);
+
+ tool_strip_gradient_begin = Color.FromArgb (252, 252, 252);
+ tool_strip_gradient_end = SystemColors.ButtonFace;
+ tool_strip_gradient_middle = Color.FromArgb (250, 250, 250);
+
+ tool_strip_panel_gradient_begin = SystemColors.ButtonFace;
+ tool_strip_panel_gradient_end = Color.FromArgb (253, 253, 253);
+ break;
+ }
+ }
+
+ private ColorSchemes GetCurrentStyle ()
+ {
+ if (!VisualStyleInformation.IsEnabledByUser || string.IsNullOrEmpty (VisualStylesEngine.Instance.VisualStyleInformationFileName))
+
+
+ return ColorSchemes.Classic;
+ else {
+ switch (System.IO.Path.GetFileNameWithoutExtension (VisualStylesEngine.Instance.VisualStyleInformationFileName).ToLowerInvariant ()) {
+ case "aero":
+ return ColorSchemes.Aero;
+ case "royale":
+ return ColorSchemes.MediaCenter;
+ default:
+ switch (VisualStyleInformation.ColorScheme) {
+ case "NormalColor":
+ return ColorSchemes.NormalColor;
+ case "HomeStead":
+ return ColorSchemes.HomeStead;
+ case "Metallic":
+ return ColorSchemes.Metallic;
+ default:
+ return ColorSchemes.Classic;
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region Private Enums
+ private enum ColorSchemes
+ {
+ Classic, // Windows Classic (No theme)
+ NormalColor, // Luna Blue
+ HomeStead, // Luna Olive
+ Metallic, // Luna Silver
+ MediaCenter, // Media Center (Energy Blue)
+ Aero // Windows Vista
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/PropertyManager.cs b/source/ShiftUI/Internal/PropertyManager.cs
new file mode 100644
index 0000000..f31608f
--- /dev/null
+++ b/source/ShiftUI/Internal/PropertyManager.cs
@@ -0,0 +1,166 @@
+// 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) 2005 Novell, Inc.
+//
+// Authors:
+// Jackson Harper [email protected]
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+
+namespace ShiftUI {
+
+ public class PropertyManager : BindingManagerBase {
+
+ internal string property_name;
+ private PropertyDescriptor prop_desc;
+ private object data_source;
+ private EventDescriptor changed_event;
+ private EventHandler property_value_changed_handler;
+
+ public PropertyManager() {
+ }
+
+ internal PropertyManager (object data_source)
+ {
+ SetDataSource (data_source);
+ }
+
+ internal PropertyManager (object data_source, string property_name)
+ {
+ this.property_name = property_name;
+
+ SetDataSource (data_source);
+ }
+
+ internal void SetDataSource (object new_data_source)
+ {
+ if (changed_event != null)
+ changed_event.RemoveEventHandler (data_source, property_value_changed_handler);
+
+ data_source = new_data_source;
+
+ if (property_name != null) {
+ prop_desc = TypeDescriptor.GetProperties (data_source).Find (property_name, true);
+
+ if (prop_desc == null)
+ return;
+
+ changed_event = TypeDescriptor.GetEvents (data_source).Find (property_name + "Changed", false);
+ if (changed_event != null) {
+ property_value_changed_handler = new EventHandler (PropertyValueChanged);
+ changed_event.AddEventHandler (data_source, property_value_changed_handler);
+ }
+ }
+ }
+
+ void PropertyValueChanged (object sender, EventArgs args)
+ {
+ OnCurrentChanged (args);
+ }
+
+ public override object Current {
+ get { return prop_desc == null ? data_source : prop_desc.GetValue (data_source); }
+ }
+
+ public override int Position {
+ get { return 0; }
+ set { /* Doesn't do anything on MS" */ }
+ }
+
+ public override int Count {
+ get { return 1; }
+ }
+
+ public override void AddNew ()
+ {
+ throw new NotSupportedException ("AddNew is not supported for property to property binding");
+ }
+
+ public override void CancelCurrentEdit ()
+ {
+ IEditableObject editable = data_source as IEditableObject;
+ if (editable == null)
+ return;
+ editable.CancelEdit ();
+
+ PushData ();
+ }
+
+ public override void EndCurrentEdit ()
+ {
+ PullData ();
+
+ IEditableObject editable = data_source as IEditableObject;
+ if (editable == null)
+ return;
+ editable.EndEdit ();
+ }
+
+ // Hide this method from the 2.0 public API
+ internal override PropertyDescriptorCollection GetItemPropertiesInternal ()
+ {
+ return TypeDescriptor.GetProperties (data_source);
+ }
+
+ public override void RemoveAt (int index)
+ {
+ throw new NotSupportedException ("RemoveAt is not supported for property to property binding");
+ }
+
+ public override void ResumeBinding ()
+ {
+ }
+
+ public override void SuspendBinding ()
+ {
+ }
+
+ internal override bool IsSuspended {
+ get { return data_source == null; }
+ }
+
+ protected internal override string GetListName (ArrayList listAccessors)
+ {
+ return String.Empty;
+ }
+
+ [MonoTODO ("Stub, does nothing")]
+ protected override void UpdateIsBinding ()
+ {
+ }
+
+ protected internal override void OnCurrentChanged (EventArgs ea)
+ {
+ PushData ();
+
+ if (onCurrentChangedHandler != null) {
+ onCurrentChangedHandler (this, ea);
+ }
+ }
+
+ protected override void OnCurrentItemChanged (EventArgs ea)
+ {
+ throw new NotImplementedException ();
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/PropertySort.cs b/source/ShiftUI/Internal/PropertySort.cs
new file mode 100644
index 0000000..30a9fa6
--- /dev/null
+++ b/source/ShiftUI/Internal/PropertySort.cs
@@ -0,0 +1,40 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+using System.Runtime.InteropServices;
+
+namespace ShiftUI
+{
+ [ComVisible(true)]
+ public enum PropertySort
+ {
+ NoSort = 0,
+ Alphabetical = 1,
+ Categorized = 2,
+ CategorizedAlphabetical = 3
+ }
+}
diff --git a/source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs b/source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs
new file mode 100644
index 0000000..3fee1c3
--- /dev/null
+++ b/source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs
@@ -0,0 +1,66 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+using System;
+using System.Runtime.InteropServices;
+using ShiftUI.Design;
+
+namespace ShiftUI
+{
+ [ComVisible(true)]
+ public class PropertyTabChangedEventArgs : EventArgs
+ {
+ #region Local Variables
+ private PropertyTab old_tab;
+ private PropertyTab new_tab;
+ #endregion // Local Variables
+
+ #region Constructor
+ public PropertyTabChangedEventArgs ( PropertyTab oldTab , PropertyTab newTab )
+ {
+ old_tab = oldTab;
+ new_tab = newTab;
+ }
+ #endregion // Constructor
+
+ #region Public Instance Properties
+ public PropertyTab NewTab
+ {
+ get {
+ return new_tab;
+ }
+ }
+
+ public PropertyTab OldTab
+ {
+ get {
+ return old_tab;
+ }
+ }
+ #endregion // Public Instance Properties
+ }
+}
diff --git a/source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs b/source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs
new file mode 100644
index 0000000..498776f
--- /dev/null
+++ b/source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs
@@ -0,0 +1,33 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public delegate void PropertyTabChangedEventHandler(object s, PropertyTabChangedEventArgs e);
+}
+
+
diff --git a/source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs b/source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs
new file mode 100644
index 0000000..ac308af
--- /dev/null
+++ b/source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs
@@ -0,0 +1,66 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+using System;
+using System.Runtime.InteropServices;
+using ShiftUI.Design;
+
+namespace ShiftUI
+{
+ [ComVisible(true)]
+ public class PropertyValueChangedEventArgs : EventArgs
+ {
+ #region Local Variables
+ private GridItem changed_item;
+ private object old_value;
+ #endregion // Local Variables
+
+ #region Constructors
+ public PropertyValueChangedEventArgs ( GridItem changedItem , object oldValue )
+ {
+ changed_item = changedItem;
+ old_value = oldValue;
+ }
+ #endregion
+
+ #region Public Instance Properties
+ public GridItem ChangedItem
+ {
+ get {
+ return changed_item;
+ }
+ }
+
+ public object OldValue
+ {
+ get {
+ return old_value;
+ }
+ }
+ #endregion // Public Instance Properties
+ }
+}
diff --git a/source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs b/source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs
new file mode 100644
index 0000000..3e76a86
--- /dev/null
+++ b/source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs
@@ -0,0 +1,31 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public delegate void PropertyValueChangedEventHandler(object s, PropertyValueChangedEventArgs e);
+}
diff --git a/source/ShiftUI/Internal/RadioButtonRenderer.cs b/source/ShiftUI/Internal/RadioButtonRenderer.cs
new file mode 100644
index 0000000..c08eb4f
--- /dev/null
+++ b/source/ShiftUI/Internal/RadioButtonRenderer.cs
@@ -0,0 +1,182 @@
+//
+// RadioButtonRenderer.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System.Drawing;
+using ShiftUI.VisualStyles;
+using System;
+
+namespace ShiftUI
+{
+ public sealed class RadioButtonRenderer
+ {
+ private static bool always_use_visual_styles = false;
+
+ #region Private Constructor
+ private RadioButtonRenderer () { }
+ #endregion
+
+ #region Public Static Methods
+ public static void DrawRadioButton (Graphics g, Point glyphLocation, RadioButtonState state)
+ {
+ DrawRadioButton (g, glyphLocation, Rectangle.Empty, String.Empty, null, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, false, state);
+ }
+
+ public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, bool focused, RadioButtonState state)
+ {
+ DrawRadioButton (g, glyphLocation, textBounds, radioButtonText, font, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, focused, state);
+ }
+
+ public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, TextFormatFlags flags, bool focused, RadioButtonState state)
+ {
+ DrawRadioButton (g, glyphLocation, textBounds, radioButtonText, font, flags, null, Rectangle.Empty, focused, state);
+ }
+
+ public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, Image image, Rectangle imageBounds, bool focused, RadioButtonState state)
+ {
+ DrawRadioButton (g, glyphLocation, textBounds, radioButtonText, font, TextFormatFlags.HorizontalCenter, image, imageBounds, focused, state);
+ }
+
+ public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, RadioButtonState state)
+ {
+ Rectangle bounds = new Rectangle (glyphLocation, GetGlyphSize (g, state));
+
+ if (Application.RenderWithVisualStyles || always_use_visual_styles == true) {
+ VisualStyleRenderer vsr = GetRadioButtonRenderer (state);
+
+ vsr.DrawBackground (g, bounds);
+
+ if (image != null)
+ vsr.DrawImage (g, imageBounds, image);
+
+ if (focused)
+ WidgetPaint.DrawFocusRectangle (g, textBounds);
+
+ if (radioButtonText != String.Empty)
+ if (state == RadioButtonState.CheckedDisabled || state == RadioButtonState.UncheckedDisabled)
+ TextRenderer.DrawText (g, radioButtonText, font, textBounds, SystemColors.GrayText, flags);
+ else
+ TextRenderer.DrawText (g, radioButtonText, font, textBounds, SystemColors.ControlText, flags);
+ }
+ else {
+ switch (state) {
+ case RadioButtonState.CheckedDisabled:
+ WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Inactive | ButtonState.Checked);
+ break;
+ case RadioButtonState.CheckedHot:
+ case RadioButtonState.CheckedNormal:
+ WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Checked);
+ break;
+ case RadioButtonState.CheckedPressed:
+ WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Pushed | ButtonState.Checked);
+ break;
+ case RadioButtonState.UncheckedDisabled:
+ case RadioButtonState.UncheckedPressed:
+ WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Inactive);
+ break;
+ case RadioButtonState.UncheckedHot:
+ case RadioButtonState.UncheckedNormal:
+ WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Normal);
+ break;
+ }
+
+ if (image != null)
+ g.DrawImage (image, imageBounds);
+
+ if (focused)
+ WidgetPaint.DrawFocusRectangle (g, textBounds);
+
+ if (radioButtonText != String.Empty)
+ TextRenderer.DrawText (g, radioButtonText, font, textBounds, SystemColors.ControlText, flags);
+ }
+
+ }
+
+ public static bool IsBackgroundPartiallyTransparent (RadioButtonState state)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return false;
+
+ VisualStyleRenderer vsr = GetRadioButtonRenderer (state);
+
+ return vsr.IsBackgroundPartiallyTransparent ();
+ }
+
+ public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return;
+
+ VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedNormal);
+
+ vsr.DrawParentBackground (g, bounds, childControl);
+ }
+
+ public static Size GetGlyphSize (Graphics g, RadioButtonState state)
+ {
+ if (!VisualStyleRenderer.IsSupported)
+ return new Size (13, 13);
+
+ VisualStyleRenderer vsr = GetRadioButtonRenderer(state);
+
+ return vsr.GetPartSize (g, ThemeSizeType.Draw);
+ }
+ #endregion
+
+ #region Private Static Methods
+ private static VisualStyleRenderer GetRadioButtonRenderer (RadioButtonState state)
+ {
+ switch (state) {
+ case RadioButtonState.CheckedDisabled:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedDisabled);
+ case RadioButtonState.CheckedHot:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedHot);
+ case RadioButtonState.CheckedNormal:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedNormal);
+ case RadioButtonState.CheckedPressed:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedPressed);
+ case RadioButtonState.UncheckedDisabled:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedDisabled);
+ case RadioButtonState.UncheckedHot:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedHot);
+ case RadioButtonState.UncheckedNormal:
+ default:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedNormal);
+ case RadioButtonState.UncheckedPressed:
+ return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedPressed);
+ }
+ }
+ #endregion
+
+ #region Public Static Properties
+ public static bool RenderMatchingApplicationState {
+ get { return !always_use_visual_styles; }
+ set { always_use_visual_styles = !value; }
+ }
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/RelatedCurrencyManager.cs b/source/ShiftUI/Internal/RelatedCurrencyManager.cs
new file mode 100644
index 0000000..2957db0
--- /dev/null
+++ b/source/ShiftUI/Internal/RelatedCurrencyManager.cs
@@ -0,0 +1,54 @@
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Chris Toshok ([email protected])
+//
+
+using System;
+using System.Data;
+using System.Reflection;
+using System.Collections;
+using System.ComponentModel;
+
+namespace ShiftUI {
+ [DefaultMember("Item")]
+ internal class RelatedCurrencyManager : CurrencyManager {
+
+ BindingManagerBase parent;
+ PropertyDescriptor prop_desc;
+
+ public RelatedCurrencyManager (BindingManagerBase parent, PropertyDescriptor prop_desc)
+ : base (prop_desc.GetValue (parent.Current))
+ {
+ this.parent = parent;
+ this.prop_desc = prop_desc;
+
+ parent.PositionChanged += new EventHandler (parent_PositionChanged);
+ }
+
+ private void parent_PositionChanged (object sender, EventArgs args)
+ {
+ SetDataSource (prop_desc.GetValue (parent.Current));
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/RelatedImageListAttribute.cs b/source/ShiftUI/Internal/RelatedImageListAttribute.cs
new file mode 100644
index 0000000..4c3af82
--- /dev/null
+++ b/source/ShiftUI/Internal/RelatedImageListAttribute.cs
@@ -0,0 +1,48 @@
+//
+// RelatedImageListAttribute.cs
+//
+// 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) 2007 Novell, Inc.
+//
+// Author:
+// Jonathan Pobst ([email protected])
+
+
+using System;
+using ShiftUI;
+
+namespace ShiftUI
+{
+ [AttributeUsageAttribute (AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public sealed class RelatedImageListAttribute : Attribute
+ {
+ private string related_image_list;
+
+ public RelatedImageListAttribute (string relatedImageList)
+ {
+ this.related_image_list = relatedImageList;
+ }
+
+ public string RelatedImageList {
+ get { return this.related_image_list; }
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/RelatedPropertyManager.cs b/source/ShiftUI/Internal/RelatedPropertyManager.cs
new file mode 100644
index 0000000..0ba4834
--- /dev/null
+++ b/source/ShiftUI/Internal/RelatedPropertyManager.cs
@@ -0,0 +1,67 @@
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Chris Toshok <[email protected]>
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+
+namespace ShiftUI {
+
+ internal class RelatedPropertyManager : PropertyManager {
+
+ BindingManagerBase parent;
+
+ public RelatedPropertyManager (BindingManagerBase parent, string property_name)
+ {
+ this.parent = parent;
+ this.property_name = property_name;
+
+ if (parent.Position != -1)
+ SetDataSource (parent.Current);
+ parent.PositionChanged += new EventHandler (parent_PositionChanged);
+ }
+
+ void parent_PositionChanged (object sender, EventArgs args)
+ {
+ if (parent.Position == -1) {
+ SetDataSource (null);
+ }
+ else {
+ SetDataSource (parent.Current);
+ }
+
+ OnCurrentChanged (EventArgs.Empty);
+ }
+
+ public override PropertyDescriptorCollection GetItemProperties ()
+ {
+ PropertyDescriptor property = parent.GetItemProperties ().Find (property_name, true);
+
+ // We can't just pass property.PropertyType, since the actual object could implement
+ // more elements and not only those described in the property type
+ return TypeDescriptor.GetProperties (property.GetValue (parent.Current));
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/RichTextBoxFinds.cs b/source/ShiftUI/Internal/RichTextBoxFinds.cs
new file mode 100644
index 0000000..28cd616
--- /dev/null
+++ b/source/ShiftUI/Internal/RichTextBoxFinds.cs
@@ -0,0 +1,39 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok <[email protected]>
+//
+//
+
+// COMPLETE
+using System;
+
+namespace ShiftUI {
+ [Flags]
+ public enum RichTextBoxFinds {
+ None = 0x00000000,
+ WholeWord = 0x00000002,
+ MatchCase = 0x00000004,
+ NoHighlight = 0x00000008,
+ Reverse = 0x00000010,
+ }
+}
diff --git a/source/ShiftUI/Internal/RichTextBoxScrollBars.cs b/source/ShiftUI/Internal/RichTextBoxScrollBars.cs
new file mode 100644
index 0000000..b155f53
--- /dev/null
+++ b/source/ShiftUI/Internal/RichTextBoxScrollBars.cs
@@ -0,0 +1,39 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok <[email protected]>
+//
+//
+
+// COMPLETE
+
+namespace ShiftUI {
+ public enum RichTextBoxScrollBars {
+ None = 0,
+ Horizontal = 1,
+ Vertical = 2,
+ Both = 3,
+ ForcedHorizontal= 17,
+ ForcedVertical = 18,
+ ForcedBoth = 19
+ }
+}
diff --git a/source/ShiftUI/Internal/SUI_NOTES.txt b/source/ShiftUI/Internal/SUI_NOTES.txt
new file mode 100644
index 0000000..96350b0
--- /dev/null
+++ b/source/ShiftUI/Internal/SUI_NOTES.txt
@@ -0,0 +1,3 @@
+The code found in this folder is from the Mono project.
+
+The Mono project can be found on Github at http://github.com/mono/mono.
diff --git a/source/ShiftUI/Internal/Screen.cs b/source/ShiftUI/Internal/Screen.cs
new file mode 100644
index 0000000..7da251f
--- /dev/null
+++ b/source/ShiftUI/Internal/Screen.cs
@@ -0,0 +1,221 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+using System;
+using System.Drawing;
+
+namespace ShiftUI {
+ public class Screen {
+ #region Local Variables
+ private static Screen[] all_screens;
+ private bool primary;
+ private Rectangle bounds;
+ private Rectangle workarea;
+ private string name;
+ private int bits_per_pixel;
+ #endregion // Local Variables
+
+ #region Constructors
+ static Screen ()
+ {
+ try {
+ all_screens = XplatUI.AllScreens;
+ }
+ catch (Exception e) {
+ Console.WriteLine ("{0} trying to get all screens: {1}", e.GetType (), e.Message);
+ }
+
+ if (all_screens == null || all_screens.Length == 0) {
+ // just use a default one
+ all_screens = new[] { new Screen(true, "Mono MWF Primary Display",
+ XplatUI.VirtualScreen, XplatUI.WorkingArea) };
+ }
+ }
+
+ internal Screen() {
+ this.primary = true;
+ this.bounds = XplatUI.WorkingArea;
+ }
+
+ internal Screen(bool primary, string name, Rectangle bounds, Rectangle workarea) {
+ this.primary = primary;
+ this.name = name;
+ this.bounds = bounds;
+ this.workarea = workarea;
+ this.bits_per_pixel = 32;
+ }
+ #endregion // Constructors
+
+ #region Public Static Properties
+ public static Screen[] AllScreens {
+ get {
+ return all_screens;
+ }
+ }
+
+ public static Screen PrimaryScreen {
+ get {
+ return all_screens[0];
+ }
+ }
+ #endregion // Public Static Properties
+
+ #region Public Instance Properties
+ [MonoTODO ("Stub, always returns 32")]
+ public int BitsPerPixel {
+ get { return bits_per_pixel; }
+ }
+
+ public Rectangle Bounds {
+ get {
+ return this.bounds;
+ }
+ }
+
+ public string DeviceName {
+ get {
+ return this.name;
+ }
+ }
+
+ public bool Primary {
+ get {
+ return this.primary;
+ }
+ }
+
+ public Rectangle WorkingArea {
+ get {
+ return this.workarea;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Static Methods
+ public static Screen FromControl(Widget control) {
+ var point = control.Parent != null ? control.Parent.PointToScreen(control.Location) : control.Location;
+ return Screen.FromPoint(point);
+ }
+
+ public static Screen FromHandle(IntPtr hwnd) {
+ Widget control;
+
+ control = Widget.FromHandle(hwnd);
+ if (control != null) {
+ var point = control.Parent != null ? control.Parent.PointToScreen(control.Location) : control.Location;
+ return Screen.FromPoint(point);
+ }
+ return Screen.PrimaryScreen;
+ }
+
+ public static Screen FromPoint(Point point) {
+ for (int i = 0; i < all_screens.Length; i++) {
+ if (all_screens[i].Bounds.Contains(point)) {
+ return all_screens[i];
+ }
+ }
+ return Screen.PrimaryScreen;
+ }
+
+ public static Screen FromRectangle(Rectangle rect) {
+ Screen bestScrn = null;
+ int closest = Int32.MaxValue;
+ foreach (Screen scrn in Screen.AllScreens) {
+ Rectangle rcBounds = scrn.Bounds;
+ int distance = 0;
+ if (rect.Left > rcBounds.Right)
+ distance += rect.Left - rcBounds.Right;
+ else if (rcBounds.Left > rect.Left)
+ distance += rcBounds.Left - rect.Left;
+ if (rcBounds.Left > rect.Right)
+ distance += rcBounds.Left - rect.Right;
+ else if (rect.Right > rcBounds.Right)
+ distance += rect.Right - rcBounds.Right;
+ if (rect.Top > rcBounds.Bottom)
+ distance += rect.Top - rcBounds.Bottom;
+ else if (rcBounds.Top > rect.Top)
+ distance += rcBounds.Top - rect.Top;
+ if (rcBounds.Top > rect.Bottom)
+ distance += rcBounds.Top - rect.Bottom;
+ else if (rect.Bottom > rcBounds.Bottom)
+ distance += rect.Bottom - rcBounds.Bottom;
+ if (distance < closest) {
+ bestScrn = scrn;
+ closest = distance;
+ }
+ }
+ return bestScrn;
+ }
+
+ public static Rectangle GetBounds(Widget ctl) {
+ return Screen.FromControl(ctl).Bounds;
+ }
+
+ public static Rectangle GetBounds(Point pt) {
+ return Screen.FromPoint(pt).Bounds;
+ }
+
+ public static Rectangle GetBounds(Rectangle rect) {
+ return Screen.FromRectangle(rect).Bounds;
+ }
+
+ public static Rectangle GetWorkingArea(Widget ctl) {
+ return Screen.FromControl(ctl).WorkingArea;
+ }
+
+ public static Rectangle GetWorkingArea(Point pt) {
+ return Screen.FromPoint(pt).WorkingArea;
+ }
+
+ public static Rectangle GetWorkingArea(Rectangle rect) {
+ return Screen.FromRectangle(rect).WorkingArea;
+ }
+ #endregion // Public Static Methods
+
+ #region Public Instance Methods
+ public override bool Equals(object obj) {
+ if (obj is Screen) {
+ Screen s = (Screen)obj;
+
+ if (name.Equals(s.name) && (primary == s.primary) && (bounds.Equals(s.Bounds)) && (workarea.Equals(s.workarea))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public override int GetHashCode() {
+ return base.GetHashCode ();
+ }
+
+ public override string ToString() {
+ return "Screen[Bounds={" + this.Bounds + "} WorkingArea={" + this.WorkingArea + "} Primary={" + this.Primary + "} DeviceName=" + this.DeviceName;
+ }
+
+
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/ScrollProperties.cs b/source/ShiftUI/Internal/ScrollProperties.cs
new file mode 100644
index 0000000..a5f59ee
--- /dev/null
+++ b/source/ShiftUI/Internal/ScrollProperties.cs
@@ -0,0 +1,97 @@
+// 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.
+//
+// Authors:
+// Olivier Dufour [email protected]
+// Jonathan Pobst [email protected]
+//
+
+using System.ComponentModel;
+
+namespace ShiftUI
+{
+ public abstract class ScrollProperties
+ {
+ #region Private Fields
+ private ScrollableWidget parentControl;
+ internal ScrollBar scroll_bar;
+ #endregion
+
+ #region constructor
+ protected ScrollProperties (ScrollableWidget container)
+ {
+ parentControl = container;
+ }
+ #endregion
+
+ #region Public Properties
+ [DefaultValue (true)]
+ public bool Enabled {
+ get { return scroll_bar.Enabled; }
+ set { scroll_bar.Enabled = value; }
+ }
+
+ [DefaultValue (10)]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ public int LargeChange {
+ get { return scroll_bar.LargeChange; }
+ set { scroll_bar.LargeChange = value; }
+ }
+
+ [DefaultValue (100)]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ public int Maximum {
+ get { return scroll_bar.Maximum; }
+ set { scroll_bar.Maximum = value; }
+ }
+
+ [DefaultValue (0)]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ public int Minimum {
+ get { return scroll_bar.Minimum; }
+ set { scroll_bar.Minimum = value; }
+ }
+
+ [DefaultValue (1)]
+ public int SmallChange {
+ get { return scroll_bar.SmallChange; }
+ set { scroll_bar.SmallChange = value; }
+ }
+
+ [DefaultValue (0)]
+ [BindableAttribute (true)]
+ public int Value {
+ get { return scroll_bar.Value; }
+ set { scroll_bar.Value = value; }
+ }
+
+ [DefaultValue (false)]
+ public bool Visible {
+ get { return scroll_bar.Visible; }
+ set { scroll_bar.Visible = value; }
+ }
+ #endregion
+
+ #region Protected Properties
+ protected ScrollableWidget ParentControl {
+ get { return parentControl; }
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs b/source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs
new file mode 100644
index 0000000..8a6149c
--- /dev/null
+++ b/source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs
@@ -0,0 +1,65 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+using System;
+using ShiftUI.Design;
+
+namespace ShiftUI
+{
+ public class SelectedGridItemChangedEventArgs : EventArgs
+ {
+ #region Local Variables
+ private GridItem new_selection;
+ private GridItem old_selection;
+ #endregion
+
+ #region Constructors
+ public SelectedGridItemChangedEventArgs ( GridItem oldSel , GridItem newSel )
+ {
+ old_selection = oldSel;
+ new_selection = newSel;
+ }
+ #endregion // Constructors
+
+ #region Public Instance Properties
+ public GridItem NewSelection
+ {
+ get {
+ return new_selection;
+ }
+ }
+
+ public GridItem OldSelection
+ {
+ get {
+ return old_selection;
+ }
+ }
+ #endregion // Public Instance Properties
+ }
+}
+
diff --git a/source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs b/source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs
new file mode 100644
index 0000000..da69bf3
--- /dev/null
+++ b/source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs
@@ -0,0 +1,31 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jonathan Chambers ([email protected])
+//
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public delegate void SelectedGridItemChangedEventHandler(object sender, SelectedGridItemChangedEventArgs e);
+}
diff --git a/source/ShiftUI/Internal/SelectionRangeConverter.cs b/source/ShiftUI/Internal/SelectionRangeConverter.cs
new file mode 100644
index 0000000..07f18ef
--- /dev/null
+++ b/source/ShiftUI/Internal/SelectionRangeConverter.cs
@@ -0,0 +1,110 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// COMPLETE
+
+using System.ComponentModel;
+using System.Globalization;
+using System;
+
+namespace ShiftUI {
+ public class SelectionRangeConverter : TypeConverter {
+ #region Public Constructors
+ public SelectionRangeConverter() {
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Methods
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
+ if (sourceType == typeof(string)) {
+ return true;
+ }
+ return false;
+ }
+
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
+ if (destinationType == typeof(string)) {
+ return true;
+ }
+ return false;
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
+ string[] parts;
+ DateTime start;
+ DateTime end;
+
+ if ((value == null) || !(value is String)) {
+ return base.ConvertFrom (context, culture, value);
+ }
+
+ if (culture == null) {
+ culture = CultureInfo.CurrentCulture;
+ }
+
+ parts = ((string)value).Split(culture.TextInfo.ListSeparator.ToCharArray());
+
+ start = (DateTime)TypeDescriptor.GetConverter(typeof(DateTime)).ConvertFromString(context, culture, parts[0]);
+ end = (DateTime)TypeDescriptor.GetConverter(typeof(DateTime)).ConvertFromString(context, culture, parts[1]);
+
+ return new SelectionRange(start, end);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
+ SelectionRange s;
+
+ if ((value == null) || !(value is SelectionRange) || (destinationType != typeof(string))) {
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ if (culture == null) {
+ culture = CultureInfo.CurrentCulture;
+ }
+
+ s = (SelectionRange)value;
+
+
+ return s.Start.ToShortDateString() + culture.TextInfo.ListSeparator + s.End.ToShortDateString();
+ }
+
+ public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues) {
+ return new SelectionRange((DateTime)propertyValues["Start"], (DateTime)propertyValues["End"]);
+ }
+
+ public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
+ return true;
+ }
+
+ public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
+ return TypeDescriptor.GetProperties(typeof(SelectionRange), attributes);
+ }
+
+ public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
+ return true;
+ }
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/Splitter.cs b/source/ShiftUI/Internal/Splitter.cs
new file mode 100644
index 0000000..761f6ee
--- /dev/null
+++ b/source/ShiftUI/Internal/Splitter.cs
@@ -0,0 +1,707 @@
+// 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) 2005-2008 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Dennis Bartok ([email protected])
+// Ivan N. Zlatev (contact i-nz.net)
+//
+//
+
+// COMPLETE
+
+#undef Debug
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI {
+ [ComVisible (true)]
+ [ClassInterface (ClassInterfaceType.AutoDispatch)]
+ [DefaultEvent("SplitterMoved")]
+ [Designer("ShiftUI.Design.SplitterDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
+ [DefaultProperty("Dock")]
+ public class Splitter : Widget
+ {
+ #region Local Variables
+ static private Cursor splitter_ns;
+ static private Cursor splitter_we;
+ // XXX this "new" shouldn't be here. Widget shouldn't define border_style as internal.
+ new private BorderStyle border_style;
+ private int min_extra;
+ private int min_size;
+ private int max_size;
+ private int splitter_size; // Size (width or height) of our splitter control
+ private bool horizontal; // true if we've got a horizontal splitter
+ private Widget affected; // The control that the splitter resizes
+ private int split_requested; // If the user requests a position before we have ever laid out the doc
+ private int splitter_prev_move;
+ private Rectangle splitter_rectangle_moving;
+ private int moving_offset;
+ #endregion // Local Variables
+
+ #region Constructors
+ static Splitter() {
+ splitter_ns = Cursors.HSplit;
+ splitter_we = Cursors.VSplit;
+ }
+
+ public Splitter() {
+
+ min_extra = 25;
+ min_size = 25;
+ split_requested = -1;
+ splitter_size = 3;
+ horizontal = false;
+
+ SetStyle(Widgetstyles.Selectable, false);
+ Anchor = AnchorStyles.None;
+ Dock = DockStyle.Left;
+
+ Layout += new LayoutEventHandler(LayoutSplitter);
+ this.ParentChanged += new EventHandler(ReparentSplitter);
+ Cursor = splitter_we;
+ }
+ #endregion // Constructors
+
+ #region Public Instance Properties
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool AllowDrop {
+ get {
+ return base.AllowDrop;
+ }
+
+ set {
+ base.AllowDrop = value;
+ }
+ }
+
+ [Browsable(false)]
+ [DefaultValue(AnchorStyles.None)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override AnchorStyles Anchor {
+ get {
+ return AnchorStyles.None;
+ }
+
+ set {
+ ; // MS doesn't set it
+ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Image BackgroundImage {
+ get {
+ return base.BackgroundImage;
+ }
+
+ set {
+ base.BackgroundImage = value;
+ }
+ }
+
+ [Browsable (false)]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public override ImageLayout BackgroundImageLayout {
+ get { return base.BackgroundImageLayout; }
+ set { base.BackgroundImageLayout = value; }
+ }
+
+ [DispId(-504)]
+ [DefaultValue (BorderStyle.None)]
+ [MWFDescription("Sets the border style for the splitter")]
+ [MWFCategory("Appearance")]
+ public BorderStyle BorderStyle {
+ get {
+ return border_style;
+ }
+
+ set {
+ border_style = value;
+
+ switch(value) {
+ case BorderStyle.FixedSingle:
+ splitter_size = 4; // We don't get motion events for 1px wide windows on X11. sigh.
+ break;
+
+ case BorderStyle.Fixed3D:
+ value = BorderStyle.None;
+ splitter_size = 3;
+ break;
+
+ case BorderStyle.None:
+ splitter_size = 3;
+ break;
+
+ default:
+ throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for BorderStyle", value));
+ }
+
+ base.InternalBorderStyle = value;
+ }
+ }
+
+ [DefaultValue(DockStyle.Left)]
+ [Localizable(true)]
+ public override DockStyle Dock {
+ get {
+ return base.Dock;
+ }
+
+ set {
+ if (!Enum.IsDefined (typeof (DockStyle), value) || (value == DockStyle.None) || (value == DockStyle.Fill)) {
+ throw new ArgumentException("Splitter must be docked left, top, bottom or right");
+ }
+
+ if ((value == DockStyle.Top) || (value == DockStyle.Bottom)) {
+ horizontal = true;
+ Cursor = splitter_ns;
+ } else {
+ horizontal = false;
+ Cursor = splitter_we;
+ }
+ base.Dock = value;
+ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Font Font {
+ get {
+ return base.Font;
+ }
+
+ set {
+ base.Font = value;
+ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Color ForeColor {
+ get {
+ return base.ForeColor;
+ }
+
+ set {
+ base.ForeColor = value;
+ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new ImeMode ImeMode {
+ get {
+ return base.ImeMode;
+ }
+
+ set {
+ base.ImeMode = value;
+ }
+ }
+
+ [DefaultValue(25)]
+ [Localizable(true)]
+ [MWFDescription("Sets minimum size of undocked window")]
+ [MWFCategory("Behaviour")]
+ public int MinExtra {
+ get {
+ return min_extra;
+ }
+
+ set {
+ min_extra = value;
+ }
+ }
+
+ [DefaultValue(25)]
+ [Localizable(true)]
+ [MWFDescription("Sets minimum size of the resized control")]
+ [MWFCategory("Behaviour")]
+ public int MinSize {
+ get {
+ return min_size;
+ }
+
+ set {
+ min_size = value;
+ }
+ }
+
+ internal int MaxSize {
+ get {
+ if (this.Parent == null)
+ return 0;
+
+ if (affected == null)
+ affected = AffectedControl;
+
+ int widths = 0;
+ int heights = 0;
+ int vert_offset = 0;
+ int horiz_offset = 0;
+ foreach (Widget c in this.Parent.Widgets) {
+ if (c != affected) {
+ switch (c.Dock) {
+ case DockStyle.Left:
+ case DockStyle.Right:
+ widths += c.Width;
+
+ if (c.Location.X < this.Location.X)
+ vert_offset += c.Width;
+ break;
+ case DockStyle.Top:
+ case DockStyle.Bottom:
+ heights += c.Height;
+
+ if (c.Location.Y < this.Location.Y)
+ horiz_offset += c.Height;
+ break;
+ }
+ }
+ }
+
+ if (horizontal) {
+ moving_offset = horiz_offset;
+
+ return Parent.ClientSize.Height - heights - MinExtra;
+ } else {
+ moving_offset = vert_offset;
+
+ return Parent.ClientSize.Width - widths - MinExtra;
+ }
+ }
+ }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ [MWFDescription("Current splitter position")]
+ [MWFCategory("Layout")]
+ public int SplitPosition {
+ get {
+ affected = AffectedControl;
+ if (affected == null) {
+ return -1;
+ }
+
+ if (Capture) {
+ return CalculateSplitPosition();
+ }
+
+ if (horizontal) {
+ return affected.Height;
+ } else {
+ return affected.Width;
+ }
+ }
+
+ set {
+ if (value > MaxSize)
+ value = MaxSize;
+ if (value < MinSize)
+ value = MinSize;
+
+ affected = AffectedControl;
+ if (affected == null)
+ split_requested = value;
+ else {
+ if (horizontal)
+ affected.Height = value;
+ else
+ affected.Width = value;
+ OnSplitterMoved (new SplitterEventArgs (Left, Top, value, value));
+ }
+ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new bool TabStop {
+ get { return base.TabStop; }
+ set { base.TabStop = value; }
+ }
+
+ [Bindable(false)]
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string Text {
+ get {
+ return base.Text;
+ }
+
+ set {
+ base.Text = value;
+ }
+ }
+
+ #endregion // Public Instance Properties
+
+ #region Protected Instance Properties
+ protected override CreateParams CreateParams {
+ get {
+ return base.CreateParams;
+ }
+ }
+
+ protected override Cursor DefaultCursor {
+ get { return base.DefaultCursor; }
+ }
+
+ protected override ImeMode DefaultImeMode {
+ get {
+ return ImeMode.Disable;
+ }
+ }
+
+ protected override Size DefaultSize {
+ get {
+ return new Size (3, 3);
+ }
+ }
+ #endregion // Protected Instance Properties
+
+ #region Public Instance Methods
+ public override string ToString() {
+ return base.ToString () + String.Format(", MinExtra: {0}, MinSize: {1}", min_extra, min_size);
+ }
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+ protected override void OnKeyDown(KeyEventArgs e) {
+ base.OnKeyDown (e);
+ if (Capture && (e.KeyCode == Keys.Escape)) {
+ Capture = false;
+ SplitterEndMove (Point.Empty, true);
+ }
+ }
+
+ protected override void OnMouseDown(MouseEventArgs e) {
+ base.OnMouseDown (e);
+
+ // Only allow if we are set up properly
+ if (affected == null)
+ affected = AffectedControl;
+ max_size = MaxSize;
+
+ if (affected == null || e.Button != MouseButtons.Left)
+ return;
+
+ Capture = true;
+ SplitterBeginMove (Parent.PointToClient (PointToScreen (new Point (e.X, e.Y))));
+ }
+
+ protected override void OnMouseMove (MouseEventArgs e)
+ {
+ base.OnMouseMove (e);
+
+ if (!Capture || e.Button != MouseButtons.Left || affected == null)
+ return;
+
+ // We need our mouse coordinates relative to our parent
+ SplitterMove (Parent.PointToClient (PointToScreen (e.Location)));
+ }
+
+ protected override void OnMouseUp (MouseEventArgs e)
+ {
+ base.OnMouseUp (e);
+ if (!Capture || e.Button != MouseButtons.Left || affected == null)
+ return;
+
+ SplitterEndMove (Parent.PointToClient (PointToScreen (e.Location)), false);
+ Capture = false;
+ }
+
+ private void SplitterBeginMove (Point location)
+ {
+ splitter_rectangle_moving = new Rectangle (Bounds.X, Bounds.Y,
+ Width, Height);
+ splitter_prev_move = horizontal ? location.Y : location.X;
+ }
+
+ private void SplitterMove (Point location)
+ {
+ int currentMove = horizontal ? location.Y : location.X;
+ int delta = currentMove - splitter_prev_move;
+ Rectangle prev_location = splitter_rectangle_moving;
+ bool moved = false;
+ int min = this.MinSize + moving_offset;
+ int max = max_size + moving_offset;
+
+ if (horizontal) {
+ if (splitter_rectangle_moving.Y + delta > min && splitter_rectangle_moving.Y + delta < max) {
+ splitter_rectangle_moving.Y += delta;
+ moved = true;
+ } else {
+ // Ensure that the splitter is set to minimum or maximum position,
+ // even if the mouse "skips".
+ //
+ if (splitter_rectangle_moving.Y + delta <= min && splitter_rectangle_moving.Y != min) {
+ splitter_rectangle_moving.Y = min;
+ moved = true;
+ } else if (splitter_rectangle_moving.Y + delta >= max && splitter_rectangle_moving.Y != max) {
+ splitter_rectangle_moving.Y = max;
+ moved = true;
+ }
+ }
+ } else {
+ if (splitter_rectangle_moving.X + delta > min && splitter_rectangle_moving.X + delta < max) {
+ splitter_rectangle_moving.X += delta;
+ moved = true;
+ } else {
+ // Ensure that the splitter is set to minimum or maximum position,
+ // even if the mouse "skips".
+ //
+ if (splitter_rectangle_moving.X + delta <= min && splitter_rectangle_moving.X != min) {
+ splitter_rectangle_moving.X = min;
+ moved = true;
+ } else if (splitter_rectangle_moving.X + delta >= max && splitter_rectangle_moving.X != max) {
+ splitter_rectangle_moving.X = max;
+ moved = true;
+ }
+ }
+ }
+
+ if (moved) {
+ splitter_prev_move = currentMove;
+ OnSplitterMoving (new SplitterEventArgs (location.X, location.Y,
+ splitter_rectangle_moving.X,
+ splitter_rectangle_moving.Y));
+ XplatUI.DrawReversibleRectangle (this.Parent.Handle, prev_location, 1);
+ XplatUI.DrawReversibleRectangle (this.Parent.Handle, splitter_rectangle_moving, 1);
+ }
+ }
+
+ private void SplitterEndMove (Point location, bool cancel)
+ {
+ if (!cancel) {
+ // Resize the affected window
+ if (horizontal)
+ affected.Height = CalculateSplitPosition();
+ else
+ affected.Width = CalculateSplitPosition();
+ }
+
+ this.Parent.Refresh (); // to clean up the drag handle artifacts from all Widgets
+ SplitterEventArgs args = new SplitterEventArgs (location.X, location.Y,
+ splitter_rectangle_moving.X,
+ splitter_rectangle_moving.Y);
+ OnSplitterMoved (args);
+ }
+
+ protected virtual void OnSplitterMoved(SplitterEventArgs sevent) {
+ SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovedEvent]);
+ if (eh != null)
+ eh (this, sevent);
+ }
+
+ protected virtual void OnSplitterMoving(SplitterEventArgs sevent) {
+ SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovingEvent]);
+ if (eh != null)
+ eh (this, sevent);
+ }
+
+ protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
+ // enforce our width / height
+ if (horizontal) {
+ splitter_size = height;
+ if (splitter_size < 1) {
+ splitter_size = 3;
+ }
+ base.SetBoundsCore (x, y, width, splitter_size, specified);
+ } else {
+ splitter_size = width;
+ if (splitter_size < 1) {
+ splitter_size = 3;
+ }
+ base.SetBoundsCore (x, y, splitter_size, height, specified);
+ }
+ }
+ #endregion // Protected Instance Methods
+
+ #region Private Properties and Methods
+ private Widget AffectedControl {
+ get {
+ if (Parent == null)
+ return null;
+
+ // Doc says the first control preceeding us in the zorder
+ for (int i = Parent.Widgets.GetChildIndex(this) + 1; i < Parent.Widgets.Count; i++) {
+ switch (Dock) {
+ case DockStyle.Top:
+ if (Top == Parent.Widgets[i].Bottom)
+ return Parent.Widgets[i];
+ break;
+ case DockStyle.Bottom:
+ if (Bottom == Parent.Widgets[i].Top)
+ return Parent.Widgets[i];
+ break;
+ case DockStyle.Left:
+ if (Left == Parent.Widgets[i].Right)
+ return Parent.Widgets[i];
+ break;
+ case DockStyle.Right:
+ if (Right == Parent.Widgets[i].Left)
+ return Parent.Widgets[i];
+ break;
+ }
+ }
+ return null;
+ }
+ }
+
+ private int CalculateSplitPosition() {
+ if (horizontal) {
+ if (Dock == DockStyle.Top)
+ return splitter_rectangle_moving.Y - affected.Top;
+ else
+ return affected.Bottom - splitter_rectangle_moving.Y - splitter_size;
+ } else {
+ if (Dock == DockStyle.Left)
+ return splitter_rectangle_moving.X - affected.Left;
+ else
+ return affected.Right - splitter_rectangle_moving.X - splitter_size;
+ }
+ }
+
+ internal override void OnPaintInternal (PaintEventArgs e) {
+ e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(this.BackColor), e.ClipRectangle);
+ }
+
+ private void LayoutSplitter(object sender, LayoutEventArgs e) {
+ affected = AffectedControl;
+ if (split_requested != -1) {
+ SplitPosition = split_requested;
+ split_requested = -1;
+ }
+ }
+
+ private void ReparentSplitter(object sender, EventArgs e) {
+ affected = null;
+ }
+
+ #endregion // Private Properties and Methods
+
+ #region Events
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler BackgroundImageChanged {
+ add { base.BackgroundImageChanged += value; }
+ remove { base.BackgroundImageChanged -= value; }
+ }
+
+ [Browsable (false)]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler BackgroundImageLayoutChanged
+ {
+ add { base.BackgroundImageLayoutChanged += value; }
+ remove { base.BackgroundImageLayoutChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler Enter {
+ add { base.Enter += value; }
+ remove { base.Enter -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler FontChanged {
+ add { base.FontChanged += value; }
+ remove { base.FontChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler ForeColorChanged {
+ add { base.ForeColorChanged += value; }
+ remove { base.ForeColorChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler ImeModeChanged {
+ add { base.ImeModeChanged += value; }
+ remove { base.ImeModeChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event KeyEventHandler KeyDown {
+ add { base.KeyDown += value; }
+ remove { base.KeyDown -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event KeyPressEventHandler KeyPress {
+ add { base.KeyPress += value; }
+ remove { base.KeyPress -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event KeyEventHandler KeyUp {
+ add { base.KeyUp += value; }
+ remove { base.KeyUp -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler Leave {
+ add { base.Leave += value; }
+ remove { base.Leave -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler TabStopChanged {
+ add { base.TabStopChanged += value; }
+ remove { base.TabStopChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler TextChanged {
+ add { base.TextChanged += value; }
+ remove { base.TextChanged -= value; }
+ }
+
+ static object SplitterMovedEvent = new object ();
+ static object SplitterMovingEvent = new object ();
+
+ public event SplitterEventHandler SplitterMoved {
+ add { Events.AddHandler (SplitterMovedEvent, value); }
+ remove { Events.RemoveHandler (SplitterMovedEvent, value); }
+ }
+
+ public event SplitterEventHandler SplitterMoving {
+ add { Events.AddHandler (SplitterMovingEvent, value); }
+ remove { Events.RemoveHandler (SplitterMovingEvent, value); }
+ }
+ #endregion // Events
+ }
+}
diff --git a/source/ShiftUI/Internal/Structs.cs b/source/ShiftUI/Internal/Structs.cs
new file mode 100644
index 0000000..087964d
--- /dev/null
+++ b/source/ShiftUI/Internal/Structs.cs
@@ -0,0 +1,157 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+
+using System;
+
+namespace ShiftUI.CarbonInternal {
+ internal struct CGSize {
+ public float width;
+ public float height;
+
+ public CGSize (int w, int h) {
+ this.width = (float)w;
+ this.height = (float)h;
+ }
+ }
+
+ internal struct QDPoint {
+ public short y;
+ public short x;
+
+ public QDPoint (short x, short y) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
+ internal struct CGPoint {
+ public float x;
+ public float y;
+
+ public CGPoint (int x, int y) {
+ this.x = (float)x;
+ this.y = (float)y;
+ }
+ }
+
+ internal struct HIRect {
+ public CGPoint origin;
+ public CGSize size;
+
+ public HIRect (int x, int y, int w, int h) {
+ this.origin = new CGPoint (x, y);
+ this.size = new CGSize (w, h);
+ }
+ }
+
+ internal struct HIViewID {
+ public uint type;
+ public uint id;
+
+ public HIViewID (uint type, uint id) {
+ this.type = type;
+ this.id = id;
+ }
+ }
+
+ internal struct EventTypeSpec {
+ public UInt32 eventClass;
+ public UInt32 eventKind;
+
+ public EventTypeSpec (UInt32 eventClass, UInt32 eventKind)
+ {
+ this.eventClass = eventClass;
+ this.eventKind = eventKind;
+ }
+ }
+
+ internal struct CarbonEvent {
+ public IntPtr hWnd;
+ public IntPtr evt;
+
+ public CarbonEvent (IntPtr hWnd, IntPtr evt)
+ {
+ this.hWnd = hWnd;
+ this.evt = evt;
+ }
+ }
+
+ internal struct RGBColor {
+ public short red;
+ public short green;
+ public short blue;
+ }
+
+ internal struct Rect {
+ public short top;
+ public short left;
+ public short bottom;
+ public short right;
+ }
+
+ internal struct Caret {
+ internal Timer Timer;
+ internal IntPtr Hwnd;
+ internal int X;
+ internal int Y;
+ internal int Width;
+ internal int Height;
+ internal int Visible;
+ internal bool On;
+ internal bool Paused;
+ }
+
+ internal struct Hover {
+ internal Timer Timer;
+ internal IntPtr Hwnd;
+ internal int X;
+ internal int Y;
+ internal int Interval;
+ }
+
+ internal struct CGAffineTransform {
+ internal float a;
+ internal float b;
+ internal float c;
+ internal float d;
+ internal float tx;
+ internal float ty;
+ }
+
+ internal struct MouseTrackingRegionID {
+ public uint signature;
+ public uint id;
+
+ public MouseTrackingRegionID (uint signature, uint id) {
+ this.signature = signature;
+ this.id = id;
+ }
+ }
+
+ internal struct ProcessSerialNumber {
+ public ulong highLongOfPSN;
+ public ulong lowLongOfPSN;
+ }
+}
diff --git a/source/ShiftUI/Internal/SystemInformation.cs b/source/ShiftUI/Internal/SystemInformation.cs
new file mode 100644
index 0000000..a27f039
--- /dev/null
+++ b/source/ShiftUI/Internal/SystemInformation.cs
@@ -0,0 +1,611 @@
+// 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,2006 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Miguel de Icaza ([email protected]).
+// Peter Bartok ([email protected])
+//
+
+// NOT COMPLETE
+
+using System;
+using System.Drawing;
+using System.ComponentModel;
+
+namespace ShiftUI
+{
+ public class SystemInformation
+ {
+ private SystemInformation ()
+ {
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int ActiveWindowTrackingDelay { get { return XplatUI.ActiveWindowTrackingDelay; } }
+
+ public static ArrangeDirection ArrangeDirection {
+ get {
+ return ThemeEngine.Current.ArrangeDirection;
+ }
+ }
+
+ public static ArrangeStartingPosition ArrangeStartingPosition {
+ get {
+ return ThemeEngine.Current.ArrangeStartingPosition;
+ }
+ }
+
+ public static BootMode BootMode {
+ get {
+ return BootMode.Normal;
+ }
+ }
+
+ public static Size Border3DSize {
+ get {
+ return ThemeEngine.Current.Border3DSize;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int BorderMultiplierFactor { get { return ThemeEngine.Current.BorderMultiplierFactor; } }
+
+ public static Size BorderSize {
+ get {
+ return ThemeEngine.Current.BorderSize;
+ }
+ }
+
+ public static Size CaptionButtonSize {
+ get {
+ return ThemeEngine.Current.CaptionButtonSize;
+ }
+ }
+
+ public static int CaptionHeight {
+ get {
+ return ThemeEngine.Current.CaptionHeight;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int CaretBlinkTime { get { return XplatUI.CaretBlinkTime; } }
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int CaretWidth { get { return XplatUI.CaretWidth; } }
+
+ public static string ComputerName {
+ get {
+ return Environment.MachineName;
+ }
+ }
+
+ public static Size CursorSize {
+ get {
+ return XplatUI.CursorSize;
+ }
+ }
+
+ public static bool DbcsEnabled {
+ get {
+ return false;
+ }
+ }
+
+ public static bool DebugOS {
+ get {
+ return false;
+ }
+ }
+
+ public static Size DoubleClickSize {
+ get {
+ return ThemeEngine.Current.DoubleClickSize;
+ }
+ }
+
+ public static int DoubleClickTime {
+ get {
+ return ThemeEngine.Current.DoubleClickTime;
+ }
+ }
+
+ public static bool DragFullWindows {
+ get {
+ return XplatUI.DragFullWindows;
+ }
+ }
+
+ public static Size DragSize {
+ get {
+ return XplatUI.DragSize;
+ }
+ }
+
+ public static Size FixedFrameBorderSize {
+ get {
+ return ThemeEngine.Current.FixedFrameBorderSize;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int FontSmoothingContrast { get { return XplatUI.FontSmoothingContrast; } }
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int FontSmoothingType { get { return XplatUI.FontSmoothingType; } }
+
+ public static Size FrameBorderSize {
+ get {
+ return ThemeEngine.Current.FrameBorderSize;
+ }
+ }
+
+ public static bool HighContrast {
+ get {
+ return false;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int HorizontalFocusThickness { get { return ThemeEngine.Current.HorizontalFocusThickness; } }
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int HorizontalResizeBorderThickness { get { return XplatUI.HorizontalResizeBorderThickness; } }
+
+ public static int HorizontalScrollBarArrowWidth {
+ get {
+ return ThemeEngine.Current.HorizontalScrollBarArrowWidth;
+ }
+ }
+
+ public static int HorizontalScrollBarHeight {
+ get {
+ return ThemeEngine.Current.HorizontalScrollBarHeight;
+ }
+ }
+
+ public static int HorizontalScrollBarThumbWidth {
+ get {
+ return ThemeEngine.Current.HorizontalScrollBarThumbWidth;
+ }
+ }
+
+ public static Size IconSize {
+ get {
+ return XplatUI.IconSize;
+ }
+ }
+
+ public static int IconHorizontalSpacing {
+ get {
+ return IconSpacingSize.Width;
+ }
+ }
+
+ public static int IconVerticalSpacing {
+ get {
+ return IconSpacingSize.Height;
+ }
+ }
+
+ public static Size IconSpacingSize {
+ get {
+ return ThemeEngine.Current.IconSpacingSize;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsActiveWindowTrackingEnabled {
+ get { return XplatUI.IsActiveWindowTrackingEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsComboBoxAnimationEnabled {
+ get { return XplatUI.IsComboBoxAnimationEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsDropShadowEnabled {
+ get { return XplatUI.IsDropShadowEnabled; }
+ }
+
+ public static bool IsFlatMenuEnabled {
+ get { return false; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsFontSmoothingEnabled {
+ get { return XplatUI.IsFontSmoothingEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsHotTrackingEnabled {
+ get { return XplatUI.IsHotTrackingEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsIconTitleWrappingEnabled {
+ get { return XplatUI.IsIconTitleWrappingEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsKeyboardPreferred {
+ get { return XplatUI.IsKeyboardPreferred; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsListBoxSmoothScrollingEnabled {
+ get { return XplatUI.IsListBoxSmoothScrollingEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsMenuAnimationEnabled {
+ get { return XplatUI.IsMenuAnimationEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsMenuFadeEnabled {
+ get { return XplatUI.IsMenuFadeEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsMinimizeRestoreAnimationEnabled {
+ get { return XplatUI.IsMinimizeRestoreAnimationEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsSelectionFadeEnabled {
+ get { return XplatUI.IsSelectionFadeEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsSnapToDefaultEnabled {
+ get { return XplatUI.IsSnapToDefaultEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsTitleBarGradientEnabled {
+ get { return XplatUI.IsTitleBarGradientEnabled; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool IsToolTipAnimationEnabled {
+ get { return XplatUI.IsToolTipAnimationEnabled; }
+ }
+
+ public static int KanjiWindowHeight {
+ get {
+ return 0;
+ }
+ }
+
+ public static int KeyboardDelay {
+ get {
+ return XplatUI.KeyboardDelay;
+ }
+ }
+
+ public static int KeyboardSpeed {
+ get {
+ return XplatUI.KeyboardSpeed;
+ }
+ }
+
+ public static Size MaxWindowTrackSize {
+ get {
+ return XplatUI.MaxWindowTrackSize;
+ }
+ }
+
+ public static bool MenuAccessKeysUnderlined {
+ get {
+ return ThemeEngine.Current.MenuAccessKeysUnderlined;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static Size MenuBarButtonSize {
+ get { return ThemeEngine.Current.MenuBarButtonSize; }
+ }
+
+ public static Size MenuButtonSize {
+ get {
+ return ThemeEngine.Current.MenuButtonSize;
+ }
+ }
+
+ public static Size MenuCheckSize {
+ get {
+ return ThemeEngine.Current.MenuCheckSize;
+ }
+ }
+
+ public static Font MenuFont {
+ get {
+ // note: we MUST return a clone of the Font instance as anyone
+ // can dispose it. However we shouldn't expect the theme to do
+ // the cloning for performance reason
+ return (Font) ThemeEngine.Current.MenuFont.Clone ();
+ }
+ }
+
+ public static int MenuHeight {
+ get {
+ return ThemeEngine.Current.MenuHeight;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int MenuShowDelay { get { return XplatUI.MenuShowDelay; } }
+
+ public static bool MidEastEnabled {
+ get {
+ return false; // ??? how do we decide?
+ }
+ }
+
+ public static Size MinimizedWindowSize {
+ get {
+ return XplatUI.MinimizedWindowSize;
+ }
+ }
+
+ public static Size MinimizedWindowSpacingSize {
+ get {
+ return XplatUI.MinimizedWindowSpacingSize;
+ }
+ }
+
+ public static Size MinimumWindowSize {
+ get {
+ return XplatUI.MinimumWindowSize;
+ }
+ }
+
+ public static Size MinWindowTrackSize {
+ get {
+ return XplatUI.MinWindowTrackSize;
+ }
+ }
+
+ public static int MonitorCount {
+ get {
+ return Screen.AllScreens.Length;
+ }
+ }
+
+ public static bool MonitorsSameDisplayFormat {
+ get {
+ return true;
+ }
+ }
+
+ public static int MouseButtons {
+ get {
+ return XplatUI.MouseButtonCount;
+ }
+ }
+
+ public static bool MouseButtonsSwapped {
+ get {
+ return XplatUI.MouseButtonsSwapped;
+ }
+ }
+
+ public static Size MouseHoverSize {
+ get {
+ return XplatUI.MouseHoverSize;
+ }
+ }
+
+ public static int MouseHoverTime {
+ get {
+ return XplatUI.MouseHoverTime;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int MouseSpeed {
+ get { return XplatUI.MouseSpeed; }
+ }
+
+ public static int MouseWheelScrollDelta {
+ get {
+ return XplatUI.MouseWheelScrollDelta;
+ }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public static bool MousePresent {
+ get {
+ return true;
+ }
+ }
+
+ public static bool MouseWheelPresent {
+ get {
+ return XplatUI.MouseWheelPresent;
+ }
+ }
+
+ public static int MouseWheelScrollLines {
+ get {
+ return ThemeEngine.Current.MouseWheelScrollLines;
+ }
+ }
+
+ public static bool NativeMouseWheelSupport {
+ get {
+ return MouseWheelPresent;
+ }
+ }
+
+ public static bool Network {
+ get {
+ return true;
+ }
+ }
+
+ public static bool PenWindows {
+ get {
+ return false;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static LeftRightAlignment PopupMenuAlignment {
+ get { return XplatUI.PopupMenuAlignment; }
+ }
+
+ [MonoTODO ("Only implemented for Win32.")]
+ public static PowerStatus PowerStatus {
+ get { return XplatUI.PowerStatus; }
+ }
+
+ public static Size PrimaryMonitorMaximizedWindowSize {
+ get {
+ var workingArea = Screen.PrimaryScreen.WorkingArea;
+ return new Size (workingArea.Width, workingArea.Height);
+ }
+ }
+
+ public static Size PrimaryMonitorSize {
+ get {
+ var bounds = Screen.PrimaryScreen.Bounds;
+ return new Size (bounds.Width, bounds.Height);
+ }
+ }
+
+ public static bool RightAlignedMenus {
+ get {
+ return ThemeEngine.Current.RightAlignedMenus;
+ }
+ }
+
+ public static ScreenOrientation ScreenOrientation {
+ get { return ScreenOrientation.Angle0; }
+ }
+
+ public static bool Secure {
+ get {
+ return true;
+ }
+ }
+
+ public static bool ShowSounds {
+ get {
+ return false;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int SizingBorderWidth {
+ get { return XplatUI.SizingBorderWidth; }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static Size SmallCaptionButtonSize {
+ get { return XplatUI.SmallCaptionButtonSize; }
+ }
+
+ public static Size SmallIconSize {
+ get {
+ return XplatUI.SmallIconSize;
+ }
+ }
+
+ public static bool TerminalServerSession {
+ get {
+ return false;
+ }
+ }
+
+ public static Size ToolWindowCaptionButtonSize {
+ get {
+ return ThemeEngine.Current.ToolWindowCaptionButtonSize;
+ }
+ }
+
+ public static int ToolWindowCaptionHeight {
+ get {
+ return ThemeEngine.Current.ToolWindowCaptionHeight;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static bool UIEffectsEnabled {
+ get { return XplatUI.UIEffectsEnabled; }
+ }
+
+ public static string UserDomainName {
+ get {
+ return Environment.UserDomainName;
+ }
+ }
+
+ public static bool UserInteractive {
+ get {
+ return Environment.UserInteractive;
+ }
+ }
+
+ public static string UserName {
+ get {
+ return Environment.UserName;
+ }
+ }
+
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int VerticalFocusThickness { get { return ThemeEngine.Current.VerticalFocusThickness; } }
+ [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")]
+ public static int VerticalResizeBorderThickness { get { return XplatUI.VerticalResizeBorderThickness; } }
+
+ public static int VerticalScrollBarArrowHeight {
+ get {
+ return ThemeEngine.Current.VerticalScrollBarArrowHeight;
+ }
+ }
+
+ public static int VerticalScrollBarThumbHeight {
+ get {
+ return ThemeEngine.Current.VerticalScrollBarThumbHeight;
+ }
+ }
+
+ public static int VerticalScrollBarWidth {
+ get {
+ return ThemeEngine.Current.VerticalScrollBarWidth;
+ }
+ }
+
+ public static Rectangle VirtualScreen {
+ get {
+ var rect = new Rectangle ();
+ foreach (var screen in Screen.AllScreens)
+ rect = Rectangle.Union (rect, screen.Bounds);
+ return rect;
+ }
+ }
+
+ public static Rectangle WorkingArea {
+ get {
+ return Screen.PrimaryScreen.WorkingArea;
+ }
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/SystemParameter.cs b/source/ShiftUI/Internal/SystemParameter.cs
new file mode 100644
index 0000000..fd4f7c1
--- /dev/null
+++ b/source/ShiftUI/Internal/SystemParameter.cs
@@ -0,0 +1,49 @@
+//
+// SystemParameter.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+using System.Runtime.InteropServices;
+
+namespace ShiftUI
+{
+ [ComVisible(true)]
+ public enum SystemParameter
+ {
+ DropShadow = 0,
+ FlatMenu = 1,
+ FontSmoothingContrastMetric = 2,
+ FontSmoothingTypeMetric = 3,
+ MenuFadeEnabled = 4,
+ SelectionFade = 5,
+ ToolTipAnimationMetric = 6,
+ UIEffects = 7,
+ CaretWidthMetric = 8,
+ VerticalFocusThicknessMetric = 9,
+ HorizontalFocusThicknessMetric = 10
+ }
+}
diff --git a/source/ShiftUI/Internal/TableLayout.cs b/source/ShiftUI/Internal/TableLayout.cs
new file mode 100644
index 0000000..f32ca96
--- /dev/null
+++ b/source/ShiftUI/Internal/TableLayout.cs
@@ -0,0 +1,603 @@
+//
+// TableLayout.cs
+//
+// 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) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+#undef TABLE_DEBUG
+
+using System;
+using System.Drawing;
+
+namespace ShiftUI.Layout
+{
+ internal class TableLayout : LayoutEngine
+ {
+ private static Widget dummy_Widget = new Widget ("Dummy"); // Used as a placeholder for row/col spans
+
+ public TableLayout () : base ()
+ {
+ }
+
+ public override void InitLayout (object child, BoundsSpecified specified)
+ {
+ base.InitLayout (child, specified);
+ }
+
+ // There are 3 steps to doing a table layout:
+ // 1) Figure out which row/column each Widget goes into
+ // 2) Figure out the sizes of each row/column
+ // 3) Size and position each Widget
+ public override bool Layout (object container, LayoutEventArgs args)
+ {
+ TableLayoutPanel panel = container as TableLayoutPanel;
+ TableLayoutSettings settings = panel.LayoutSettings;
+
+#if TABLE_DEBUG
+ Console.WriteLine ("Beginning layout on panel: {0}, Widget count: {1}, col/row count: {2}x{3}", panel.Name, panel.Widgets.Count, settings.ColumnCount, settings.RowCount);
+#endif
+
+ // STEP 1:
+ // - Figure out which row/column each Widget goes into
+ // - Store data in the TableLayoutPanel.actual_positions
+ panel.actual_positions = CalculateWidgetPositions (panel, Math.Max (settings.ColumnCount, 1), Math.Max (settings.RowCount, 1));
+
+ // STEP 2:
+ // - Figure out the sizes of each row/column
+ // - Store data in the TableLayoutPanel.widths/heights
+ CalculateColumnRowSizes (panel, panel.actual_positions.GetLength (0), panel.actual_positions.GetLength (1));
+
+ // STEP 3:
+ // - Size and position each Widget
+ LayoutWidgets(panel);
+
+#if TABLE_DEBUG
+ Console.WriteLine ("-- CalculatedPositions:");
+ OutputWidgetGrid (panel.actual_positions, panel);
+
+ Console.WriteLine ("Finished layout on panel: {0}", panel.Name);
+ Console.WriteLine ();
+#endif
+
+ return false;
+ }
+
+ internal Widget[,] CalculateWidgetPositions (TableLayoutPanel panel, int columns, int rows)
+ {
+ Widget[,] grid = new Widget[columns, rows];
+
+ TableLayoutSettings settings = panel.LayoutSettings;
+
+ // First place all Widgets that have an explicit col/row
+ foreach (Widget c in panel.Widgets) {
+ int col = settings.GetColumn (c);
+ int row = settings.GetRow (c);
+ if (col >= 0 && row >= 0) {
+ if (col >= columns)
+ return CalculateWidgetPositions (panel, col + 1, rows);
+ if (row >= rows)
+ return CalculateWidgetPositions (panel, columns, row + 1);
+
+ if (grid[col, row] == null) {
+ int col_span = Math.Min (settings.GetColumnSpan (c), columns);
+ int row_span = Math.Min (settings.GetRowSpan (c), rows);
+
+ if (col + col_span > columns) {
+ if (row + 1 < rows) {
+ grid[col, row] = dummy_Widget;
+ row++;
+ col = 0;
+ }
+ else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns)
+ return CalculateWidgetPositions (panel, columns + 1, rows);
+ else
+ throw new ArgumentException ();
+ }
+
+ if (row + row_span > rows) {
+ if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddRows)
+ return CalculateWidgetPositions (panel, columns, rows + 1);
+ else
+ throw new ArgumentException ();
+ }
+
+ grid[col, row] = c;
+
+ // Fill in the rest of this Widget's row/column extent with dummy
+ // Widgets, so that other Widgets don't get put there.
+ for (int i = 0; i < col_span; i++)
+ for (int j = 0; j < row_span; j++)
+ if (i != 0 || j != 0)
+ grid[col + i, row + j] = dummy_Widget;
+ }
+ }
+ }
+
+ int x_pointer = 0;
+ int y_pointer = 0;
+
+ // Fill in gaps with Widgets that do not have an explicit col/row
+ foreach (Widget c in panel.Widgets) {
+ int col = settings.GetColumn (c);
+ int row = settings.GetRow (c);
+
+ if ((col >= 0 && col < columns) && (row >= 0 && row < rows) && (grid[col, row] == c || grid[col, row] == dummy_Widget))
+ continue;
+
+ for (int y = y_pointer; y < rows; y++) {
+ y_pointer = y;
+ x_pointer = 0;
+
+ for (int x = x_pointer; x < columns; x++) {
+ x_pointer = x;
+
+ if (grid[x, y] == null) {
+ int col_span = Math.Min (settings.GetColumnSpan (c), columns);
+ int row_span = Math.Min (settings.GetRowSpan (c), rows);
+
+ if (x + col_span > columns) {
+ if (y + 1 < rows)
+ break;
+ else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns)
+ return CalculateWidgetPositions (panel, columns + 1, rows);
+ else
+ throw new ArgumentException ();
+ }
+
+ if (y + row_span > rows) {
+ if (x + 1 < columns)
+ break;
+ else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddRows)
+ return CalculateWidgetPositions (panel, columns, rows + 1);
+ else
+ throw new ArgumentException ();
+ }
+
+ grid[x, y] = c;
+
+ // Fill in the rest of this Widget's row/column extent with dummy
+ // Widgets, so that other Widgets don't get put there.
+ for (int i = 0; i < col_span; i++)
+ for (int j = 0; j < row_span; j++)
+ if (i != 0 || j != 0)
+ grid[x + i, y + j] = dummy_Widget;
+
+ // I know someone will kill me for using a goto, but
+ // sometimes they really are the easiest way...
+ goto Found;
+ } else {
+ // MS adds the Widgets only to the first row if
+ // GrowStyle is AddColumns and RowCount is 0,
+ // so interrupt the search for a free horizontal cell
+ // beyond the first one in the given vertical
+ if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns &&
+ settings.RowCount == 0)
+ break;
+ }
+ }
+ }
+
+ // MS adds rows instead of columns even when GrowStyle is AddColumns,
+ // but RowCount is 0.
+ TableLayoutPanelGrowStyle adjustedGrowStyle = settings.GrowStyle;
+ if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns) {
+ if (settings.RowCount == 0)
+ adjustedGrowStyle = TableLayoutPanelGrowStyle.AddRows;
+ }
+
+ switch (adjustedGrowStyle) {
+ case TableLayoutPanelGrowStyle.AddColumns:
+ return CalculateWidgetPositions (panel, columns + 1, rows);
+ case TableLayoutPanelGrowStyle.AddRows:
+ default:
+ return CalculateWidgetPositions (panel, columns, rows + 1);
+ case TableLayoutPanelGrowStyle.FixedSize:
+ throw new ArgumentException ();
+ }
+
+ Found: ;
+ }
+
+ return grid;
+ }
+
+ private void CalculateColumnRowSizes (TableLayoutPanel panel, int columns, int rows)
+ {
+ TableLayoutSettings settings = panel.LayoutSettings;
+
+ panel.column_widths = new int[panel.actual_positions.GetLength (0)];
+ panel.row_heights = new int[panel.actual_positions.GetLength (1)];
+
+ int border_width = TableLayoutPanel.GetCellBorderWidth (panel.CellBorderStyle);
+
+ Rectangle parentDisplayRectangle = panel.DisplayRectangle;
+
+ TableLayoutColumnStyleCollection col_styles = new TableLayoutColumnStyleCollection (panel);
+
+ foreach (ColumnStyle cs in settings.ColumnStyles)
+ col_styles.Add( new ColumnStyle(cs.SizeType, cs.Width));
+
+ TableLayoutRowStyleCollection row_styles = new TableLayoutRowStyleCollection (panel);
+
+ foreach (RowStyle rs in settings.RowStyles)
+ row_styles.Add (new RowStyle (rs.SizeType, rs.Height));
+
+ // If we have more columns than columnstyles, temporarily add enough columnstyles
+ if (columns > col_styles.Count)
+ {
+ for (int i = col_styles.Count; i < columns; i++)
+ col_styles.Add(new ColumnStyle());
+ }
+
+ // Same for rows..
+ if (rows > row_styles.Count)
+ {
+ for (int i = row_styles.Count; i < rows; i++)
+ row_styles.Add (new RowStyle ());
+ }
+
+ while (row_styles.Count > rows)
+ row_styles.RemoveAt (row_styles.Count - 1);
+ while (col_styles.Count > columns)
+ col_styles.RemoveAt (col_styles.Count - 1);
+
+ // Find the largest column-span/row-span values.
+ int max_colspan = 0, max_rowspan = 0;
+ foreach (Widget c in panel.Widgets) {
+ max_colspan = Math.Max (max_colspan, settings.GetColumnSpan (c));
+ max_rowspan = Math.Max (max_rowspan, settings.GetRowSpan (c));
+ }
+
+ // Figure up all the column widths
+ int total_width = parentDisplayRectangle.Width - (border_width * (columns + 1));
+ int index = 0;
+
+ // First assign all the Absolute sized columns..
+ foreach (ColumnStyle cs in col_styles) {
+ if (cs.SizeType == SizeType.Absolute) {
+ panel.column_widths[index] = (int)cs.Width;
+ total_width -= (int)cs.Width;
+ }
+
+ index++;
+ }
+
+ // Next, assign all the AutoSize columns to the width of their widest
+ // Widget. If the table-layout is auto-sized, then make sure that
+ // no column with Percent styling clips its contents.
+ // (per http://msdn.microsoft.com/en-us/library/ms171690.aspx)
+ for (int colspan = 0; colspan < max_colspan; ++colspan)
+ {
+ for (index = colspan; index < col_styles.Count - colspan; ++index)
+ {
+ ColumnStyle cs = col_styles[index];
+ if (cs.SizeType == SizeType.AutoSize
+ || (panel.AutoSize && cs.SizeType == SizeType.Percent))
+ {
+ int max_width = panel.column_widths[index];
+
+ // Find the widest Widget in the column
+ for (int i = 0; i < rows; i ++)
+ {
+ Widget c = panel.actual_positions[index - colspan, i];
+
+ if (c != null && c != dummy_Widget && c.VisibleInternal)
+ {
+ // Skip any Widgets not being sized in this pass.
+ if (settings.GetColumnSpan (c) != colspan + 1)
+ continue;
+
+ // Calculate the maximum Widget width.
+ if (c.AutoSize)
+ max_width = Math.Max (max_width, c.PreferredSize.Width + c.Margin.Horizontal);
+ else
+ max_width = Math.Max (max_width, c.ExplicitBounds.Width + c.Margin.Horizontal);
+ max_width = Math.Max (max_width, c.Width + c.Margin.Left + c.Margin.Right);
+ }
+ }
+
+ // Subtract the width of prior columns, if any.
+ for (int i = Math.Max (index - colspan, 0); i < index; ++i)
+ max_width -= panel.column_widths[i];
+
+ // If necessary, increase this column's width.
+ if (max_width > panel.column_widths[index])
+ {
+ max_width -= panel.column_widths[index];
+ panel.column_widths[index] += max_width;
+ total_width -= max_width;
+ }
+ }
+ }
+ }
+
+ index = 0;
+ float total_percent = 0;
+
+ // Finally, assign the remaining space to Percent columns, if any.
+ if (total_width > 0)
+ {
+ int percent_width = total_width;
+
+ // Find the total percent (not always 100%)
+ foreach (ColumnStyle cs in col_styles)
+ {
+ if (cs.SizeType == SizeType.Percent)
+ total_percent += cs.Width;
+ }
+
+ // Divvy up the space..
+ foreach (ColumnStyle cs in col_styles)
+ {
+ if (cs.SizeType == SizeType.Percent)
+ {
+ int width_change = (int)(((cs.Width / total_percent) * percent_width)
+ - panel.column_widths[index]);
+ if (width_change > 0)
+ {
+ panel.column_widths[index] += width_change;
+ total_width -= width_change;
+ }
+ }
+
+ index++;
+ }
+ }
+
+ if (total_width > 0)
+ {
+ // Find the last column that isn't an Absolute SizeType, and give it
+ // all this free space. (Absolute sized columns need to retain their
+ // absolute width if at all possible!)
+ int col = col_styles.Count - 1;
+ for (; col >= 0; --col)
+ {
+ if (col_styles[col].SizeType != SizeType.Absolute)
+ break;
+ }
+ if (col < 0)
+ col = col_styles.Count - 1;
+ panel.column_widths[col] += total_width;
+ }
+
+ // Figure up all the row heights
+ int total_height = parentDisplayRectangle.Height - (border_width * (rows + 1));
+ index = 0;
+
+ // First assign all the Absolute sized rows..
+ foreach (RowStyle rs in row_styles) {
+ if (rs.SizeType == SizeType.Absolute) {
+ panel.row_heights[index] = (int)rs.Height;
+ total_height -= (int)rs.Height;
+ }
+
+ index++;
+ }
+
+ index = 0;
+
+ // Next, assign all the AutoSize rows to the height of their tallest
+ // Widget. If the table-layout is auto-sized, then make sure that
+ // no row with Percent styling clips its contents.
+ // (per http://msdn.microsoft.com/en-us/library/ms171690.aspx)
+ for (int rowspan = 0; rowspan < max_rowspan; ++rowspan)
+ {
+ for (index = rowspan; index < row_styles.Count - rowspan; ++index)
+ {
+ RowStyle rs = row_styles[index];
+ if (rs.SizeType == SizeType.AutoSize
+ || (panel.AutoSize && rs.SizeType == SizeType.Percent))
+ {
+ int max_height = panel.row_heights[index];
+
+ // Find the tallest Widget in the row
+ for (int i = 0; i < columns; i++) {
+ Widget c = panel.actual_positions[i, index - rowspan];
+
+ if (c != null && c != dummy_Widget && c.VisibleInternal)
+ {
+ // Skip any Widgets not being sized in this pass.
+ if (settings.GetRowSpan (c) != rowspan + 1)
+ continue;
+
+ // Calculate the maximum Widget height.
+ if (c.AutoSize)
+ max_height = Math.Max (max_height, c.PreferredSize.Height + c.Margin.Vertical);
+ else
+ max_height = Math.Max (max_height, c.ExplicitBounds.Height + c.Margin.Vertical);
+ max_height = Math.Max (max_height, c.Height + c.Margin.Top + c.Margin.Bottom);
+ }
+ }
+
+ // Subtract the height of prior rows, if any.
+ for (int i = Math.Max (index - rowspan, 0); i < index; ++i)
+ max_height -= panel.row_heights[i];
+
+ // If necessary, increase this row's height.
+ if (max_height > panel.row_heights[index])
+ {
+ max_height -= panel.row_heights[index];
+ panel.row_heights[index] += max_height;
+ total_height -= max_height;
+ }
+ }
+ }
+ }
+
+ index = 0;
+ total_percent = 0;
+
+ // Finally, assign the remaining space to Percent rows, if any.
+ if (total_height > 0) {
+ int percent_height = total_height;
+
+ // Find the total percent (not always 100%)
+ foreach (RowStyle rs in row_styles) {
+ if (rs.SizeType == SizeType.Percent)
+ total_percent += rs.Height;
+ }
+
+ // Divvy up the space..
+ foreach (RowStyle rs in row_styles) {
+ if (rs.SizeType == SizeType.Percent) {
+ int height_change = (int)(((rs.Height / total_percent) * percent_height)
+ - panel.row_heights[index]);
+ if (height_change > 0)
+ {
+ panel.row_heights[index] += height_change;
+ total_height -= height_change;
+ }
+ }
+
+ index++;
+ }
+ }
+
+ if (total_height > 0)
+ {
+ // Find the last row that isn't an Absolute SizeType, and give it
+ // all this free space. (Absolute sized rows need to retain their
+ // absolute height if at all possible!)
+ int row = row_styles.Count - 1;
+ for (; row >= 0; --row)
+ {
+ if (row_styles[row].SizeType != SizeType.Absolute)
+ break;
+ }
+ if (row < 0)
+ row = row_styles.Count - 1;
+ panel.row_heights[row] += total_height;
+ }
+ }
+
+ private void LayoutWidgets (TableLayoutPanel panel)
+ {
+ TableLayoutSettings settings = panel.LayoutSettings;
+
+ int border_width = TableLayoutPanel.GetCellBorderWidth (panel.CellBorderStyle);
+
+ int columns = panel.actual_positions.GetLength(0);
+ int rows = panel.actual_positions.GetLength(1);
+
+ Point current_pos = new Point (panel.DisplayRectangle.Left + border_width, panel.DisplayRectangle.Top + border_width);
+
+ for (int y = 0; y < rows; y++)
+ {
+ for (int x = 0; x < columns; x++)
+ {
+ Widget c = panel.actual_positions[x,y];
+
+ if(c != null && c != dummy_Widget) {
+ Size preferred;
+
+ if (c.AutoSize)
+ preferred = c.PreferredSize;
+ else
+ preferred = c.ExplicitBounds.Size;
+
+ int new_x = 0;
+ int new_y = 0;
+ int new_width = 0;
+ int new_height = 0;
+
+ // Figure out the width of the Widget
+ int column_width = panel.column_widths[x];
+
+ for (int i = 1; i < Math.Min (settings.GetColumnSpan(c), panel.column_widths.Length); i++)
+ column_width += panel.column_widths[x + i];
+
+ if (c.Dock == DockStyle.Fill || c.Dock == DockStyle.Top || c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
+ new_width = column_width - c.Margin.Left - c.Margin.Right;
+ else
+ new_width = Math.Min (preferred.Width, column_width - c.Margin.Left - c.Margin.Right);
+
+ // Figure out the height of the Widget
+ int column_height = panel.row_heights[y];
+
+ for (int i = 1; i < Math.Min (settings.GetRowSpan (c), panel.row_heights.Length); i++)
+ column_height += panel.row_heights[y + i];
+
+ if (c.Dock == DockStyle.Fill || c.Dock == DockStyle.Left || c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
+ new_height = column_height - c.Margin.Top - c.Margin.Bottom;
+ else
+ new_height = Math.Min (preferred.Height, column_height - c.Margin.Top - c.Margin.Bottom);
+
+ // Figure out the left location of the Widget
+ if (c.Dock == DockStyle.Left || c.Dock == DockStyle.Fill || (c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)
+ new_x = current_pos.X + c.Margin.Left;
+ else if (c.Dock == DockStyle.Right || (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)
+ new_x = (current_pos.X + column_width) - new_width - c.Margin.Right;
+ else // (center Widget)
+ new_x = (current_pos.X + (column_width - c.Margin.Left - c.Margin.Right) / 2) + c.Margin.Left - (new_width / 2);
+
+ // Figure out the top location of the Widget
+ if (c.Dock == DockStyle.Top || c.Dock == DockStyle.Fill || (c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)
+ new_y = current_pos.Y + c.Margin.Top;
+ else if (c.Dock == DockStyle.Bottom || (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)
+ new_y = (current_pos.Y + column_height) - new_height - c.Margin.Bottom;
+ else // (center Widget)
+ new_y = (current_pos.Y + (column_height - c.Margin.Top - c.Margin.Bottom) / 2) + c.Margin.Top - (new_height / 2);
+
+ c.SetBoundsInternal (new_x, new_y, new_width, new_height, BoundsSpecified.None);
+ }
+
+ current_pos.Offset (panel.column_widths[x] + border_width, 0);
+ }
+
+ current_pos.Offset ((-1 * current_pos.X) + border_width + panel.DisplayRectangle.Left, panel.row_heights[y] + border_width);
+ }
+ }
+
+#if TABLE_DEBUG
+ private void OutputWidgetGrid (Widget[,] grid, TableLayoutPanel panel)
+ {
+ Console.WriteLine (" Size: {0}x{1}", grid.GetLength (0), grid.GetLength (1));
+
+ Console.Write (" ");
+
+ foreach (int i in panel.column_widths)
+ Console.Write (" {0}px ", i.ToString ().PadLeft (3));
+
+ Console.WriteLine ();
+
+ for (int y = 0; y < grid.GetLength (1); y++) {
+ Console.Write (" {0}px |", panel.row_heights[y].ToString ().PadLeft (3));
+
+ for (int x = 0; x < grid.GetLength (0); x++) {
+ if (grid[x, y] == null)
+ Console.Write (" --- |");
+ else if (string.IsNullOrEmpty (grid[x, y].Name))
+ Console.Write (" ??? |");
+ else
+ Console.Write (" {0} |", grid[x, y].Name.PadRight (5).Substring (0, 5));
+ }
+
+ Console.WriteLine ();
+ }
+ }
+#endif
+ }
+}
diff --git a/source/ShiftUI/Internal/TableLayoutSettings.cs b/source/ShiftUI/Internal/TableLayoutSettings.cs
new file mode 100644
index 0000000..786a98b
--- /dev/null
+++ b/source/ShiftUI/Internal/TableLayoutSettings.cs
@@ -0,0 +1,362 @@
+//
+// TableLayoutSettings.cs
+//
+// 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) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using ShiftUI.Layout;
+using System.Runtime.Serialization;
+
+namespace ShiftUI
+{
+ [Serializable]
+ [TypeConverter (typeof (TableLayoutSettingsTypeConverter))]
+ public sealed class TableLayoutSettings : LayoutSettings, ISerializable
+ {
+ private TableLayoutColumnStyleCollection column_styles;
+ private TableLayoutRowStyleCollection row_styles;
+ private TableLayoutPanelGrowStyle grow_style;
+ private int column_count;
+ private int row_count;
+ private Dictionary<Object, int> columns;
+ private Dictionary<Object, int> column_spans;
+ private Dictionary<Object, int> rows;
+ private Dictionary<Object, int> row_spans;
+ internal TableLayoutPanel panel;
+ internal bool isSerialized;
+
+ #region Internal Constructor
+ internal TableLayoutSettings (TableLayoutPanel panel)
+ {
+ this.column_styles = new TableLayoutColumnStyleCollection (panel);
+ this.row_styles = new TableLayoutRowStyleCollection (panel);
+ this.grow_style = TableLayoutPanelGrowStyle.AddRows;
+ this.column_count = 0;
+ this.row_count = 0;
+ this.columns = new Dictionary<object, int> ();
+ this.column_spans = new Dictionary<object, int> ();
+ this.rows = new Dictionary<object, int> ();
+ this.row_spans = new Dictionary<object, int> ();
+ this.panel = panel;
+ }
+
+ private TableLayoutSettings (SerializationInfo serializationInfo, StreamingContext context)
+ {
+ TypeConverter converter = TypeDescriptor.GetConverter (this);
+ string text = serializationInfo.GetString ("SerializedString");
+ if (!string.IsNullOrEmpty (text) && (converter != null)) {
+ TableLayoutSettings settings = converter.ConvertFromInvariantString (text) as TableLayoutSettings;
+ this.column_styles = settings.column_styles;
+ this.row_styles = settings.row_styles;
+ this.grow_style = settings.grow_style;
+ this.column_count = settings.column_count;
+ this.row_count = settings.row_count;
+ this.columns = settings.columns;
+ this.column_spans = settings.column_spans;
+ this.rows = settings.rows;
+ this.row_spans = settings.row_spans;
+ this.panel = settings.panel;
+ this.isSerialized = true;
+ }
+ }
+ #endregion
+
+ #region Public Properties
+ [DefaultValue (0)]
+ public int ColumnCount {
+ get { return this.column_count; }
+ set {
+ if (value < 0)
+ throw new ArgumentOutOfRangeException();
+
+ if (column_count != value) {
+ column_count = value;
+ if (panel != null)
+ panel.PerformLayout (panel, "ColumnCount");
+ }
+ }
+ }
+
+ //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
+ public TableLayoutColumnStyleCollection ColumnStyles {
+ get { return this.column_styles; }
+ }
+
+ [DefaultValue (TableLayoutPanelGrowStyle.AddRows)]
+ public TableLayoutPanelGrowStyle GrowStyle {
+ get { return this.grow_style; }
+ set {
+ if (!Enum.IsDefined (typeof(TableLayoutPanelGrowStyle), value))
+ throw new ArgumentException();
+
+ if (grow_style != value) {
+ grow_style = value;
+ if (panel != null)
+ panel.PerformLayout (panel, "GrowStyle");
+ }
+ }
+ }
+
+ public override LayoutEngine LayoutEngine {
+ get {
+ if (panel != null)
+ return panel.LayoutEngine;
+ return base.LayoutEngine;
+ }
+ }
+
+ [DefaultValue (0)]
+ public int RowCount {
+ get { return this.row_count; }
+ set {
+ if (value < 0)
+ throw new ArgumentOutOfRangeException ();
+
+ if (row_count != value) {
+ row_count = value;
+
+ if (panel != null)
+ panel.PerformLayout ();
+ }
+ }
+ }
+
+ //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
+ public TableLayoutRowStyleCollection RowStyles {
+ get { return row_styles; }
+ }
+ #endregion
+
+ #region Public Methods
+ [DefaultValue (-1)]
+ public TableLayoutPanelCellPosition GetCellPosition (Object control)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+
+ int column;
+ int row;
+
+ if (!columns.TryGetValue (control, out column))
+ {
+ if (!(control is Widget) || !columns.TryGetValue ((control as Widget).Name, out column))
+ column = -1;
+ }
+ if (!rows.TryGetValue (control, out row))
+ {
+ if (!(control is Widget) || !rows.TryGetValue ((control as Widget), out row))
+ row = -1;
+ }
+
+ return new TableLayoutPanelCellPosition (column, row);
+ }
+
+ [DefaultValue (-1)]
+ public int GetColumn (Object control)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+
+ int retval;
+
+ if (columns.TryGetValue (control, out retval))
+ return retval;
+ if ((control is Widget) && columns.TryGetValue ((control as Widget).Name, out retval))
+ return retval;
+
+ return -1;
+ }
+
+ public int GetColumnSpan (Object control)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+
+ int retval;
+
+ if (column_spans.TryGetValue (control, out retval))
+ return retval;
+ if ((control is Widget) && column_spans.TryGetValue ((control as Widget).Name, out retval))
+ return retval;
+
+ return 1;
+ }
+
+ [DefaultValue (-1)]
+ public int GetRow (Object control)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+
+ int retval;
+
+ if (rows.TryGetValue (control, out retval))
+ return retval;
+ if ((control is Widget) && rows.TryGetValue ((control as Widget).Name, out retval))
+ return retval;
+
+ return -1;
+ }
+
+ public int GetRowSpan (Object control)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+
+ int retval;
+
+ if (row_spans.TryGetValue (control, out retval))
+ return retval;
+ if ((control is Widget) && row_spans.TryGetValue ((control as Widget).Name, out retval))
+ return retval;
+
+ return 1;
+ }
+
+ [DefaultValue (-1)]
+ public void SetCellPosition (Object control, TableLayoutPanelCellPosition cellPosition)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+
+ columns[control] = cellPosition.Column;
+ rows[control] = cellPosition.Row;
+
+ if (panel != null)
+ panel.PerformLayout ();
+ }
+
+ public void SetColumn (Object control, int column)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+ if (column < -1)
+ throw new ArgumentException ();
+
+ columns[control] = column;
+
+ if (panel != null)
+ panel.PerformLayout ();
+ }
+
+ public void SetColumnSpan (Object control, int value)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+ if (value < -1)
+ throw new ArgumentException ();
+
+ column_spans[control] = value;
+
+ if (panel != null)
+ panel.PerformLayout ();
+ }
+
+ public void SetRow (Object control, int row)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+ if (row < -1)
+ throw new ArgumentException ();
+
+ rows[control] = row;
+
+ if (panel != null)
+ panel.PerformLayout ();
+ }
+
+ public void SetRowSpan (Object control, int value)
+ {
+ if (control == null)
+ throw new ArgumentNullException ();
+ if (value < -1)
+ throw new ArgumentException ();
+
+ row_spans[control] = value;
+
+ if (panel != null)
+ panel.PerformLayout ();
+ }
+ #endregion
+
+ #region Internal Methods
+ internal List<WidgetInfo> GetWidgets ()
+ {
+ List<WidgetInfo> list = new List<WidgetInfo>();
+ foreach (KeyValuePair <object, int> control in columns) {
+ WidgetInfo info = new WidgetInfo();
+ info.Widget = control.Key;
+ info.Col = GetColumn(control.Key);
+ info.ColSpan = GetColumnSpan (control.Key);
+ info.Row = GetRow (control.Key);
+ info.RowSpan = GetRowSpan (control.Key);
+ list.Add (info);
+ }
+ return list;
+ }
+
+ #endregion
+
+ #region ISerializable Members
+ void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context)
+ {
+ TableLayoutSettingsTypeConverter conv = new TableLayoutSettingsTypeConverter ();
+ string text = conv.ConvertToInvariantString (this);
+ si.AddValue ("SerializedString", text);
+ }
+ #endregion
+
+ internal class StyleConverter : TypeConverter
+ {
+ public override object ConvertFrom (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
+ {
+ if ((value == null) || !(value is String))
+ return base.ConvertFrom (context, culture, value);
+
+ return Enum.Parse (typeof (StyleConverter), (string)value, true);
+ }
+
+ public override object ConvertTo (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+ {
+ if ((value == null) || !(value is StyleConverter) || (destinationType != typeof (string)))
+ return base.ConvertTo (context, culture, value, destinationType);
+
+ return ((StyleConverter)value).ToString ();
+ }
+ }
+ }
+
+ internal struct WidgetInfo
+ {
+ public object Widget;
+ public int Row;
+ public int RowSpan;
+ public int Col;
+ public int ColSpan;
+ }
+}
diff --git a/source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs b/source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs
new file mode 100644
index 0000000..d9396b9
--- /dev/null
+++ b/source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs
@@ -0,0 +1,233 @@
+// 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) 2006 Novell, Inc.
+//
+
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Globalization;
+using System.Xml;
+using System.IO;
+using System.Collections.Generic;
+
+namespace ShiftUI.Layout
+{
+ public class TableLayoutSettingsTypeConverter : TypeConverter
+ {
+ public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof (string))
+ return true;
+
+ return base.CanConvertTo (context, destinationType);
+ }
+
+ public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof(string))
+ return true;
+
+ return base.CanConvertFrom (context, sourceType);
+ }
+
+
+
+ public override object ConvertTo (ITypeDescriptorContext context,
+ CultureInfo culture,
+ object value,
+ Type destinationType)
+ {
+ if (!(value is TableLayoutSettings) || destinationType != typeof (string))
+ return base.ConvertTo (context, culture, value, destinationType);
+
+ TableLayoutSettings settings = value as TableLayoutSettings;
+ StringWriter sw = new StringWriter ();
+ XmlTextWriter xw = new XmlTextWriter (sw);
+ xw.WriteStartDocument ();
+ List<WidgetInfo> list = settings.GetWidgets ();
+ xw.WriteStartElement ("TableLayoutSettings");
+ xw.WriteStartElement ("Widgets");
+
+ foreach (WidgetInfo info in list) {
+ xw.WriteStartElement ("Widget");
+ xw.WriteAttributeString ("Name", info.Widget.ToString ());
+ xw.WriteAttributeString ("Row", info.Row.ToString ());
+ xw.WriteAttributeString ("RowSpan", info.RowSpan.ToString ());
+ xw.WriteAttributeString ("Column", info.Col.ToString ());
+ xw.WriteAttributeString ("ColumnSpan", info.ColSpan.ToString ());
+ xw.WriteEndElement ();
+ }
+ xw.WriteEndElement ();
+
+
+ List<string> styles = new List<string> ();
+
+ foreach (ColumnStyle style in settings.ColumnStyles) {
+ styles.Add (style.SizeType.ToString ());
+ styles.Add (style.Width.ToString (CultureInfo.InvariantCulture));
+ }
+
+
+ xw.WriteStartElement ("Columns");
+ xw.WriteAttributeString ("Styles", String.Join (",", styles.ToArray ()));
+ xw.WriteEndElement ();
+
+ styles.Clear();
+ foreach (RowStyle style in settings.RowStyles) {
+ styles.Add (style.SizeType.ToString ());
+ styles.Add (style.Height.ToString (CultureInfo.InvariantCulture));
+ }
+
+ xw.WriteStartElement ("Rows");
+ xw.WriteAttributeString ("Styles", String.Join (",", styles.ToArray ()));
+ xw.WriteEndElement ();
+
+ xw.WriteEndElement ();
+ xw.WriteEndDocument ();
+ xw.Close ();
+
+ return sw.ToString ();
+
+ }
+
+ public override object ConvertFrom (ITypeDescriptorContext context,
+ CultureInfo culture,
+ object value)
+ {
+ if (!(value is string))
+ return base.ConvertFrom(context, culture, value);
+
+ XmlDocument xmldoc = new XmlDocument();
+ xmldoc.LoadXml (value as string);
+ TableLayoutSettings settings = new TableLayoutSettings(new TableLayoutPanel());
+ int count = ParseWidget (xmldoc, settings);
+ ParseColumnStyle (xmldoc, settings);
+ ParseRowStyle (xmldoc, settings);
+ settings.RowCount = count;
+
+
+ return settings;
+ }
+
+
+ private int ParseWidget (XmlDocument xmldoc, TableLayoutSettings settings)
+ {
+ int count = 0;
+ foreach (XmlNode node in xmldoc.GetElementsByTagName ("Widget")) {
+ if (node.Attributes["Name"] == null || string.IsNullOrEmpty(node.Attributes["Name"].Value))
+ continue;
+ if (node.Attributes["Row"] != null) {
+ settings.SetRow (node.Attributes["Name"].Value, GetValue (node.Attributes["Row"].Value));
+ count++;
+ }
+ if (node.Attributes["RowSpan"] != null) {
+ settings.SetRowSpan (node.Attributes["Name"].Value, GetValue (node.Attributes["RowSpan"].Value));
+ }
+ if (node.Attributes["Column"] != null)
+ settings.SetColumn (node.Attributes["Name"].Value, GetValue (node.Attributes["Column"].Value));
+ if (node.Attributes["ColumnSpan"] != null)
+ settings.SetColumnSpan (node.Attributes["Name"].Value, GetValue (node.Attributes["ColumnSpan"].Value));
+ }
+ return count;
+ }
+
+ private void ParseColumnStyle (XmlDocument xmldoc, TableLayoutSettings settings)
+ {
+ foreach (XmlNode node in xmldoc.GetElementsByTagName ("Columns")) {
+ if (node.Attributes["Styles"] == null)
+ continue;
+ string styles = node.Attributes["Styles"].Value;
+ if (string.IsNullOrEmpty (styles))
+ continue;
+ string[] list = BuggySplit (styles);
+ for (int i = 0; i < list.Length; i+=2) {
+ float width = 0f;
+ SizeType type = (SizeType) Enum.Parse (typeof (SizeType), list[i]);
+ float.TryParse (list[i+1], NumberStyles.Float, CultureInfo.InvariantCulture, out width);
+ settings.ColumnStyles.Add (new ColumnStyle (type, width));
+ }
+ }
+ }
+
+ private void ParseRowStyle (XmlDocument xmldoc, TableLayoutSettings settings)
+ {
+ foreach (XmlNode node in xmldoc.GetElementsByTagName ("Rows")) {
+ if (node.Attributes["Styles"] == null)
+ continue;
+ string styles = node.Attributes["Styles"].Value;
+ if (string.IsNullOrEmpty(styles))
+ continue;
+ string[] list = BuggySplit (styles);
+ for (int i = 0; i < list.Length; i += 2) {
+ float height = 0f;
+ SizeType type = (SizeType) Enum.Parse (typeof (SizeType), list[i]);
+ float.TryParse (list[i + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out height);
+ settings.RowStyles.Add (new RowStyle (type, height));
+ }
+ }
+ }
+
+ private int GetValue (string attValue)
+ {
+ int val = -1;
+ if (!string.IsNullOrEmpty (attValue)) {
+ int.TryParse (attValue, out val);
+ }
+ return val;
+ }
+
+ // .Net accidently uses the local culture separator, so
+ // Percent,50.0,Percent,50.0 can be
+ // Percent,50,0,Percent,50,0
+ // Make sure we can handle this
+ private string[] BuggySplit (string s)
+ {
+ List<string> l = new List<string> ();
+
+ string[] split = s.Split (',');
+
+ for (int i = 0; i < split.Length; i++) {
+ switch (split[i].ToLowerInvariant ()) {
+ case "autosize":
+ case "absolute":
+ case "percent":
+ l.Add (split[i]);
+ break;
+ default:
+ if (i + 1 < split.Length) {
+ float test;
+
+ if (float.TryParse (split[i + 1], out test)) {
+ l.Add (string.Format ("{0}.{1}", split[i], split[i + 1]));
+ i++;
+ } else
+ l.Add (split[i]);
+ } else
+ l.Add (split[i]);
+ break;
+ }
+ }
+
+ return l.ToArray ();
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/TextBoxTextRenderer.cs b/source/ShiftUI/Internal/TextBoxTextRenderer.cs
new file mode 100644
index 0000000..3e908f3
--- /dev/null
+++ b/source/ShiftUI/Internal/TextBoxTextRenderer.cs
@@ -0,0 +1,131 @@
+// 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) 2007 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Jonathan Pobst [email protected]
+//
+//
+
+using System;
+using System.Drawing;
+using System.Drawing.Text;
+using System.Text;
+using System.Collections;
+
+namespace ShiftUI
+{
+ internal class TextBoxTextRenderer
+ {
+ private static Size max_size;
+ private static bool use_textrenderer;
+ private static StringFormat sf_nonprinting;
+ private static StringFormat sf_printing;
+ private static Hashtable measure_cache;
+
+ static TextBoxTextRenderer ()
+ {
+ // On Windows, we want to use TextRenderer (GDI)
+ // On Linux, we want to use DrawString (GDI+)
+ // TextRenderer provides translation from TextRenderer to
+ // DrawString, but I doubt it's exact enough.
+ // Another option would be to put Pango here for Linux.
+ int platform = (int)Environment.OSVersion.Platform;
+
+ if (platform == 4 || platform == 128 || platform == 6)
+ use_textrenderer = false;
+ else
+ use_textrenderer = true;
+
+ // windows 2000 doesn't draw with gdi if bounds are In32.MaxValue
+ max_size = new Size (Int16.MaxValue, Int16.MaxValue);
+
+ sf_nonprinting = new StringFormat (StringFormat.GenericTypographic);
+ sf_nonprinting.Trimming = StringTrimming.None;
+ sf_nonprinting.FormatFlags = StringFormatFlags.DisplayFormatControl;
+ sf_nonprinting.HotkeyPrefix = HotkeyPrefix.None;
+
+ sf_printing = StringFormat.GenericTypographic;
+ sf_printing.HotkeyPrefix = HotkeyPrefix.None;
+
+ measure_cache = new Hashtable ();
+ }
+
+ public static void DrawText (Graphics g, string text, Font font, Color color, float x, float y, bool showNonPrint)
+ {
+ if (!use_textrenderer) {
+ if (showNonPrint)
+ g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (color), x, y, sf_nonprinting);
+ else
+ g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (color), x, y, sf_printing);
+ } else {
+ if (showNonPrint)
+ TextRenderer.DrawTextInternal (g, text, font, new Rectangle (new Point ((int)x, (int)y), max_size), color, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false);
+ else
+ TextRenderer.DrawTextInternal (g, text, font, new Rectangle (new Point ((int)x, (int)y), max_size), color, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false);
+ }
+ }
+
+ public static SizeF MeasureText (Graphics g, string text, Font font)
+ {
+ // Due to the way the TextBox currently works, it measures each
+ // character one at a time. And it does this alot. So here we
+ // are implementing a cache for each font/character combination
+ // measurement. Since the number of fonts and number of characters
+ // used tends to be small, this is a good performance gain for
+ // not too much memory.
+ if (text.Length == 1) {
+ // If g.VisibleClipBounds is {X=0, Y=0, Width=1, Height=1}, then some characters
+ // (in some fonts for some point sizes) return a different width then when the
+ // VisibleClipBounds has a different (usually but not always more reasonable) value.
+ // This state of the Graphics object can occur during initialization of text boxes
+ // with preset Text values. See https://bugzilla.xamarin.com/show_bug.cgi?id=26258
+ // for more details.
+ string sep;
+ var bounds = g.VisibleClipBounds;
+ if (bounds.Width == 1 && bounds.Height == 1 && bounds.X == 0 && bounds.Y == 0)
+ sep = "-1x1|";
+ else
+ sep = "|";
+ string key = font.GetHashCode ().ToString () + sep + text;
+
+ if (measure_cache.ContainsKey (key)) {
+ return (SizeF)measure_cache[key];
+ } else {
+ SizeF size;
+
+ if (!use_textrenderer)
+ size = g.MeasureString (text, font, 10000, sf_nonprinting);
+ else
+ size = TextRenderer.MeasureTextInternal (g, text, font, Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false);
+
+ measure_cache[key] = size;
+
+ return size;
+ }
+ }
+
+ if (!use_textrenderer)
+ return g.MeasureString (text, font, 10000, sf_nonprinting);
+ else
+ return TextRenderer.MeasureTextInternal (g, text, font, Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false);
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/TextControl.cs b/source/ShiftUI/Internal/TextControl.cs
new file mode 100644
index 0000000..65dd5c6
--- /dev/null
+++ b/source/ShiftUI/Internal/TextControl.cs
@@ -0,0 +1,4613 @@
+// 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-2006 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+// NOT COMPLETE
+
+// There's still plenty of things missing, I've got most of it planned, just hadn't had
+// the time to write it all yet.
+// Stuff missing (in no particular order):
+// - Align text after RecalculateLine
+// - Implement tag types for hotlinks, etc.
+// - Implement CaretPgUp/PgDown
+
+// NOTE:
+// selection_start.pos and selection_end.pos are 0-based
+// selection_start.pos = first selected char
+// selection_end.pos = first NOT-selected char
+//
+// FormatText methods are 1-based (as are all tags, LineTag.Start is 1 for
+// the first character on a line; the reason is that 0 is the position
+// *before* the first character on a line
+
+
+#undef Debug
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Drawing.Text;
+using System.Text;
+using RTF=ShiftUI.RTF;
+
+namespace ShiftUI {
+ internal enum LineColor {
+ Red = 0,
+ Black = 1
+ }
+
+ internal enum CaretSelection {
+ Position, // Selection=Caret
+ Word, // Selection=Word under caret
+ Line // Selection=Line under caret
+ }
+
+ [Flags]
+ internal enum FormatSpecified {
+ None,
+
+ BackColor = 2,
+ Font = 4,
+ Color = 8,
+ }
+
+ internal enum CaretDirection {
+ CharForward, // Move a char to the right
+ CharBack, // Move a char to the left
+ LineUp, // Move a line up
+ LineDown, // Move a line down
+ Home, // Move to the beginning of the line
+ End, // Move to the end of the line
+ PgUp, // Move one page up
+ PgDn, // Move one page down
+ CtrlPgUp, // Move caret to the first visible char in the viewport
+ CtrlPgDn, // Move caret to the last visible char in the viewport
+ CtrlHome, // Move to the beginning of the document
+ CtrlEnd, // Move to the end of the document
+ WordBack, // Move to the beginning of the previous word (or beginning of line)
+ WordForward, // Move to the beginning of the next word (or end of line)
+ SelectionStart, // Move to the beginning of the current selection
+ SelectionEnd, // Move to the end of the current selection
+ CharForwardNoWrap, // Move a char forward, but don't wrap onto the next line
+ CharBackNoWrap // Move a char backward, but don't wrap onto the previous line
+ }
+
+ internal enum LineEnding {
+ Wrap = 1, // line wraps to the next line
+ Limp = 2, // \r
+ Hard = 4, // \r\n
+ Soft = 8, // \r\r\n
+ Rich = 16, // \n
+
+ None = 0
+ }
+
+ internal class Document : ICloneable, IEnumerable {
+ #region Structures
+ // FIXME - go through code and check for places where
+ // we do explicit comparisons instead of using the compare overloads
+ internal struct Marker {
+ internal Line line;
+ internal LineTag tag;
+ internal int pos;
+ internal int height;
+
+ public static bool operator<(Marker lhs, Marker rhs) {
+ if (lhs.line.line_no < rhs.line.line_no) {
+ return true;
+ }
+
+ if (lhs.line.line_no == rhs.line.line_no) {
+ if (lhs.pos < rhs.pos) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static bool operator>(Marker lhs, Marker rhs) {
+ if (lhs.line.line_no > rhs.line.line_no) {
+ return true;
+ }
+
+ if (lhs.line.line_no == rhs.line.line_no) {
+ if (lhs.pos > rhs.pos) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static bool operator==(Marker lhs, Marker rhs) {
+ if ((lhs.line.line_no == rhs.line.line_no) && (lhs.pos == rhs.pos)) {
+ return true;
+ }
+ return false;
+ }
+
+ public static bool operator!=(Marker lhs, Marker rhs) {
+ if ((lhs.line.line_no != rhs.line.line_no) || (lhs.pos != rhs.pos)) {
+ return true;
+ }
+ return false;
+ }
+
+ public void Combine(Line move_to_line, int move_to_line_length) {
+ line = move_to_line;
+ pos += move_to_line_length;
+ tag = LineTag.FindTag(line, pos);
+ }
+
+ // This is for future use, right now Document.Split does it by hand, with some added shortcut logic
+ public void Split(Line move_to_line, int split_at) {
+ line = move_to_line;
+ pos -= split_at;
+ tag = LineTag.FindTag(line, pos);
+ }
+
+ public override bool Equals(object obj) {
+ return this==(Marker)obj;
+ }
+
+ public override int GetHashCode() {
+ return base.GetHashCode ();
+ }
+
+ public override string ToString() {
+ return "Marker Line " + line + ", Position " + pos;
+ }
+
+ }
+ #endregion Structures
+
+ #region Local Variables
+ private Line document;
+ private int lines;
+ private Line sentinel;
+ private int document_id;
+ private Random random = new Random();
+ internal string password_char;
+ private StringBuilder password_cache;
+ private bool calc_pass;
+ private int char_count;
+ private bool enable_links;
+
+ // For calculating widths/heights
+ public static readonly StringFormat string_format = new StringFormat (StringFormat.GenericTypographic);
+
+ private int recalc_suspended;
+ private bool recalc_pending;
+ private int recalc_start = 1; // This starts at one, since lines are 1 based
+ private int recalc_end;
+ private bool recalc_optimize;
+
+ private int update_suspended;
+ private bool update_pending;
+ private int update_start = 1;
+
+ internal bool multiline;
+ internal HorizontalAlignment alignment;
+ internal bool wrap;
+
+ internal UndoManager undo;
+
+ internal Marker caret;
+ internal Marker selection_start;
+ internal Marker selection_end;
+ internal bool selection_visible;
+ internal Marker selection_anchor;
+ internal Marker selection_prev;
+ internal bool selection_end_anchor;
+
+ internal int viewport_x;
+ internal int viewport_y; // The visible area of the document
+ internal int offset_x;
+ internal int offset_y;
+ internal int viewport_width;
+ internal int viewport_height;
+
+ internal int document_x; // Width of the document
+ internal int document_y; // Height of the document
+
+ internal int crlf_size; // 1 or 2, depending on whether we use \r\n or just \n
+
+ internal TextBoxBase owner; // Who's owning us?
+ static internal int caret_width = 1;
+ static internal int caret_shift = 1;
+
+ internal int left_margin = 2; // A left margin for all lines
+ internal int top_margin = 2;
+ internal int right_margin = 2;
+ #endregion // Local Variables
+
+ #region Constructors
+ internal Document (TextBoxBase owner)
+ {
+ lines = 0;
+
+ this.owner = owner;
+
+ multiline = true;
+ password_char = "";
+ calc_pass = false;
+ recalc_pending = false;
+
+ // Tree related stuff
+ sentinel = new Line (this, LineEnding.None);
+ sentinel.color = LineColor.Black;
+
+ document = sentinel;
+
+ // We always have a blank line
+ owner.HandleCreated += new EventHandler(owner_HandleCreated);
+ owner.VisibleChanged += new EventHandler(owner_VisibleChanged);
+
+ Add (1, String.Empty, owner.Font, owner.ForeColor, LineEnding.None);
+
+ undo = new UndoManager (this);
+
+ selection_visible = false;
+ selection_start.line = this.document;
+ selection_start.pos = 0;
+ selection_start.tag = selection_start.line.tags;
+ selection_end.line = this.document;
+ selection_end.pos = 0;
+ selection_end.tag = selection_end.line.tags;
+ selection_anchor.line = this.document;
+ selection_anchor.pos = 0;
+ selection_anchor.tag = selection_anchor.line.tags;
+ caret.line = this.document;
+ caret.pos = 0;
+ caret.tag = caret.line.tags;
+
+ viewport_x = 0;
+ viewport_y = 0;
+
+ offset_x = 0;
+ offset_y = 0;
+
+ crlf_size = 2;
+
+ // Default selection is empty
+
+ document_id = random.Next();
+
+ string_format.Trimming = StringTrimming.None;
+ string_format.FormatFlags = StringFormatFlags.DisplayFormatControl;
+
+ UpdateMargins ();
+ }
+ #endregion
+
+ #region Internal Properties
+ internal Line Root {
+ get {
+ return document;
+ }
+
+ set {
+ document = value;
+ }
+ }
+
+ // UIA: Method used via reflection in TextRangeProvider
+ internal int Lines {
+ get {
+ return lines;
+ }
+ }
+
+ internal Line CaretLine {
+ get {
+ return caret.line;
+ }
+ }
+
+ internal int CaretPosition {
+ get {
+ return caret.pos;
+ }
+ }
+
+ internal Point Caret {
+ get {
+ return new Point((int)caret.tag.Line.widths[caret.pos] + caret.line.X, caret.line.Y);
+ }
+ }
+
+ internal LineTag CaretTag {
+ get {
+ return caret.tag;
+ }
+
+ set {
+ caret.tag = value;
+ }
+ }
+
+ internal int CRLFSize {
+ get {
+ return crlf_size;
+ }
+
+ set {
+ crlf_size = value;
+ }
+ }
+
+ /// <summary>
+ /// Whether text is scanned for links
+ /// </summary>
+ internal bool EnableLinks {
+ get { return enable_links; }
+ set { enable_links = value; }
+ }
+
+ internal string PasswordChar {
+ get {
+ return password_char;
+ }
+
+ set {
+ password_char = value;
+ PasswordCache.Length = 0;
+ if ((password_char.Length != 0) && (password_char[0] != '\0')) {
+ calc_pass = true;
+ } else {
+ calc_pass = false;
+ }
+ }
+ }
+
+ private StringBuilder PasswordCache {
+ get {
+ if (password_cache == null)
+ password_cache = new StringBuilder();
+ return password_cache;
+ }
+ }
+
+ internal int ViewPortX {
+ get {
+ return viewport_x;
+ }
+
+ set {
+ viewport_x = value;
+ }
+ }
+
+ internal int Length {
+ get {
+ return char_count + lines - 1; // Add \n for each line but the last
+ }
+ }
+
+ private int CharCount {
+ get {
+ return char_count;
+ }
+
+ set {
+ char_count = value;
+
+ if (LengthChanged != null) {
+ LengthChanged(this, EventArgs.Empty);
+ }
+ }
+ }
+
+ internal int ViewPortY {
+ get {
+ return viewport_y;
+ }
+
+ set {
+ viewport_y = value;
+ }
+ }
+
+ internal int OffsetX
+ {
+ get
+ {
+ return offset_x;
+ }
+
+ set
+ {
+ offset_x = value;
+ }
+ }
+
+ internal int OffsetY
+ {
+ get
+ {
+ return offset_y;
+ }
+
+ set
+ {
+ offset_y = value;
+ }
+ }
+
+ internal int ViewPortWidth {
+ get {
+ return viewport_width;
+ }
+
+ set {
+ viewport_width = value;
+ }
+ }
+
+ internal int ViewPortHeight {
+ get {
+ return viewport_height;
+ }
+
+ set {
+ viewport_height = value;
+ }
+ }
+
+
+ internal int Width {
+ get {
+ return this.document_x;
+ }
+ }
+
+ internal int Height {
+ get {
+ return this.document_y;
+ }
+ }
+
+ internal bool SelectionVisible {
+ get {
+ return selection_visible;
+ }
+ }
+
+ internal bool Wrap {
+ get {
+ return wrap;
+ }
+
+ set {
+ wrap = value;
+ }
+ }
+
+ #endregion // Internal Properties
+
+ #region Private Methods
+
+ internal void UpdateMargins ()
+ {
+ switch (owner.actual_border_style) {
+ case BorderStyle.None:
+ left_margin = 0;
+ top_margin = 0;
+ right_margin = 1;
+ break;
+ case BorderStyle.FixedSingle:
+ left_margin = 2;
+ top_margin = 2;
+ right_margin = 3;
+ break;
+ case BorderStyle.Fixed3D:
+ left_margin = 1;
+ top_margin = 1;
+ right_margin = 2;
+ break;
+ }
+ }
+
+ internal void SuspendRecalc ()
+ {
+ if (recalc_suspended == 0) {
+ recalc_start = int.MaxValue;
+ recalc_end = int.MinValue;
+ }
+
+ recalc_suspended++;
+ }
+
+ internal void ResumeRecalc (bool immediate_update)
+ {
+ if (recalc_suspended > 0)
+ recalc_suspended--;
+
+ if (recalc_suspended == 0 && (immediate_update || recalc_pending) && !(recalc_start == int.MaxValue && recalc_end == int.MinValue)) {
+ RecalculateDocument (owner.CreateGraphicsInternal (), recalc_start, recalc_end, recalc_optimize);
+ recalc_pending = false;
+ }
+ }
+
+ internal void SuspendUpdate ()
+ {
+ update_suspended++;
+ }
+
+ internal void ResumeUpdate (bool immediate_update)
+ {
+ if (update_suspended > 0)
+ update_suspended--;
+
+ if (immediate_update && update_suspended == 0 && update_pending) {
+ UpdateView (GetLine (update_start), 0);
+ update_pending = false;
+ }
+ }
+
+ // For debugging
+ internal int DumpTree(Line line, bool with_tags) {
+ int total;
+
+ total = 1;
+
+ Console.Write("Line {0} [# {1}], Y: {2}, ending style: {3}, Text: '{4}'",
+ line.line_no, line.GetHashCode(), line.Y, line.ending,
+ line.text != null ? line.text.ToString() : "undefined");
+
+ if (line.left == sentinel) {
+ Console.Write(", left = sentinel");
+ } else if (line.left == null) {
+ Console.Write(", left = NULL");
+ }
+
+ if (line.right == sentinel) {
+ Console.Write(", right = sentinel");
+ } else if (line.right == null) {
+ Console.Write(", right = NULL");
+ }
+
+ Console.WriteLine("");
+
+ if (with_tags) {
+ LineTag tag;
+ int count;
+ int length;
+
+ tag = line.tags;
+ count = 1;
+ length = 0;
+ Console.Write(" Tags: ");
+ while (tag != null) {
+ Console.Write("{0} <{1}>-<{2}>", count++, tag.Start, tag.End
+ /*line.text.ToString (tag.start - 1, tag.length)*/);
+ length += tag.Length;
+
+ if (tag.Line != line) {
+ Console.Write("BAD line link");
+ throw new Exception("Bad line link in tree");
+ }
+ tag = tag.Next;
+ if (tag != null) {
+ Console.Write(", ");
+ }
+ }
+ if (length > line.text.Length) {
+ throw new Exception(String.Format("Length of tags more than length of text on line (expected {0} calculated {1})", line.text.Length, length));
+ } else if (length < line.text.Length) {
+ throw new Exception(String.Format("Length of tags less than length of text on line (expected {0} calculated {1})", line.text.Length, length));
+ }
+ Console.WriteLine("");
+ }
+ if (line.left != null) {
+ if (line.left != sentinel) {
+ total += DumpTree(line.left, with_tags);
+ }
+ } else {
+ if (line != sentinel) {
+ throw new Exception("Left should not be NULL");
+ }
+ }
+
+ if (line.right != null) {
+ if (line.right != sentinel) {
+ total += DumpTree(line.right, with_tags);
+ }
+ } else {
+ if (line != sentinel) {
+ throw new Exception("Right should not be NULL");
+ }
+ }
+
+ for (int i = 1; i <= this.lines; i++) {
+ if (GetLine(i) == null) {
+ throw new Exception(String.Format("Hole in line order, missing {0}", i));
+ }
+ }
+
+ if (line == this.Root) {
+ if (total < this.lines) {
+ throw new Exception(String.Format("Not enough nodes in tree, found {0}, expected {1}", total, this.lines));
+ } else if (total > this.lines) {
+ throw new Exception(String.Format("Too many nodes in tree, found {0}, expected {1}", total, this.lines));
+ }
+ }
+
+ return total;
+ }
+
+ private void SetSelectionVisible (bool value)
+ {
+ bool old_selection_visible = selection_visible;
+ selection_visible = value;
+
+ // cursor and selection are enemies, we can't have both in the same room at the same time
+ if (owner.IsHandleCreated && !owner.show_caret_w_selection)
+ XplatUI.CaretVisible (owner.Handle, !selection_visible);
+ if (UIASelectionChanged != null && (selection_visible || old_selection_visible))
+ UIASelectionChanged (this, EventArgs.Empty);
+ }
+
+ private void DecrementLines(int line_no) {
+ int current;
+
+ current = line_no;
+ while (current <= lines) {
+ GetLine(current).line_no--;
+ current++;
+ }
+ return;
+ }
+
+ private void IncrementLines(int line_no) {
+ int current;
+
+ current = this.lines;
+ while (current >= line_no) {
+ GetLine(current).line_no++;
+ current--;
+ }
+ return;
+ }
+
+ private void RebalanceAfterAdd(Line line1) {
+ Line line2;
+
+ while ((line1 != document) && (line1.parent.color == LineColor.Red)) {
+ if (line1.parent == line1.parent.parent.left) {
+ line2 = line1.parent.parent.right;
+
+ if ((line2 != null) && (line2.color == LineColor.Red)) {
+ line1.parent.color = LineColor.Black;
+ line2.color = LineColor.Black;
+ line1.parent.parent.color = LineColor.Red;
+ line1 = line1.parent.parent;
+ } else {
+ if (line1 == line1.parent.right) {
+ line1 = line1.parent;
+ RotateLeft(line1);
+ }
+
+ line1.parent.color = LineColor.Black;
+ line1.parent.parent.color = LineColor.Red;
+
+ RotateRight(line1.parent.parent);
+ }
+ } else {
+ line2 = line1.parent.parent.left;
+
+ if ((line2 != null) && (line2.color == LineColor.Red)) {
+ line1.parent.color = LineColor.Black;
+ line2.color = LineColor.Black;
+ line1.parent.parent.color = LineColor.Red;
+ line1 = line1.parent.parent;
+ } else {
+ if (line1 == line1.parent.left) {
+ line1 = line1.parent;
+ RotateRight(line1);
+ }
+
+ line1.parent.color = LineColor.Black;
+ line1.parent.parent.color = LineColor.Red;
+ RotateLeft(line1.parent.parent);
+ }
+ }
+ }
+ document.color = LineColor.Black;
+ }
+
+ private void RebalanceAfterDelete(Line line1) {
+ Line line2;
+
+ while ((line1 != document) && (line1.color == LineColor.Black)) {
+ if (line1 == line1.parent.left) {
+ line2 = line1.parent.right;
+ if (line2.color == LineColor.Red) {
+ line2.color = LineColor.Black;
+ line1.parent.color = LineColor.Red;
+ RotateLeft(line1.parent);
+ line2 = line1.parent.right;
+ }
+ if ((line2.left.color == LineColor.Black) && (line2.right.color == LineColor.Black)) {
+ line2.color = LineColor.Red;
+ line1 = line1.parent;
+ } else {
+ if (line2.right.color == LineColor.Black) {
+ line2.left.color = LineColor.Black;
+ line2.color = LineColor.Red;
+ RotateRight(line2);
+ line2 = line1.parent.right;
+ }
+ line2.color = line1.parent.color;
+ line1.parent.color = LineColor.Black;
+ line2.right.color = LineColor.Black;
+ RotateLeft(line1.parent);
+ line1 = document;
+ }
+ } else {
+ line2 = line1.parent.left;
+ if (line2.color == LineColor.Red) {
+ line2.color = LineColor.Black;
+ line1.parent.color = LineColor.Red;
+ RotateRight(line1.parent);
+ line2 = line1.parent.left;
+ }
+ if ((line2.right.color == LineColor.Black) && (line2.left.color == LineColor.Black)) {
+ line2.color = LineColor.Red;
+ line1 = line1.parent;
+ } else {
+ if (line2.left.color == LineColor.Black) {
+ line2.right.color = LineColor.Black;
+ line2.color = LineColor.Red;
+ RotateLeft(line2);
+ line2 = line1.parent.left;
+ }
+ line2.color = line1.parent.color;
+ line1.parent.color = LineColor.Black;
+ line2.left.color = LineColor.Black;
+ RotateRight(line1.parent);
+ line1 = document;
+ }
+ }
+ }
+ line1.color = LineColor.Black;
+ }
+
+ private void RotateLeft(Line line1) {
+ Line line2 = line1.right;
+
+ line1.right = line2.left;
+
+ if (line2.left != sentinel) {
+ line2.left.parent = line1;
+ }
+
+ if (line2 != sentinel) {
+ line2.parent = line1.parent;
+ }
+
+ if (line1.parent != null) {
+ if (line1 == line1.parent.left) {
+ line1.parent.left = line2;
+ } else {
+ line1.parent.right = line2;
+ }
+ } else {
+ document = line2;
+ }
+
+ line2.left = line1;
+ if (line1 != sentinel) {
+ line1.parent = line2;
+ }
+ }
+
+ private void RotateRight(Line line1) {
+ Line line2 = line1.left;
+
+ line1.left = line2.right;
+
+ if (line2.right != sentinel) {
+ line2.right.parent = line1;
+ }
+
+ if (line2 != sentinel) {
+ line2.parent = line1.parent;
+ }
+
+ if (line1.parent != null) {
+ if (line1 == line1.parent.right) {
+ line1.parent.right = line2;
+ } else {
+ line1.parent.left = line2;
+ }
+ } else {
+ document = line2;
+ }
+
+ line2.right = line1;
+ if (line1 != sentinel) {
+ line1.parent = line2;
+ }
+ }
+
+
+ internal void UpdateView(Line line, int pos) {
+ if (!owner.IsHandleCreated) {
+ return;
+ }
+
+ if (update_suspended > 0) {
+ update_start = Math.Min (update_start, line.line_no);
+ // update_end = Math.Max (update_end, line.line_no);
+ // recalc_optimize = true;
+ update_pending = true;
+ return;
+ }
+
+ // Optimize invalidation based on Line alignment
+ if (RecalculateDocument(owner.CreateGraphicsInternal(), line.line_no, line.line_no, true)) {
+ // Lineheight changed, invalidate the rest of the document
+ if ((line.Y - viewport_y) >=0 ) {
+ // We formatted something that's in view, only draw parts of the screen
+ owner.Invalidate(new Rectangle(
+ offset_x,
+ line.Y - viewport_y + offset_y,
+ viewport_width,
+ owner.Height - (line.Y - viewport_y)));
+ } else {
+ // The tag was above the visible area, draw everything
+ owner.Invalidate();
+ }
+ } else {
+ switch(line.alignment) {
+ case HorizontalAlignment.Left: {
+ owner.Invalidate(new Rectangle(
+ line.X + ((int)line.widths[pos] - viewport_x - 1) + offset_x,
+ line.Y - viewport_y + offset_y,
+ viewport_width,
+ line.height + 1));
+ break;
+ }
+
+ case HorizontalAlignment.Center: {
+ owner.Invalidate(new Rectangle(
+ line.X + offset_x,
+ line.Y - viewport_y + offset_y,
+ viewport_width,
+ line.height + 1));
+ break;
+ }
+
+ case HorizontalAlignment.Right: {
+ owner.Invalidate(new Rectangle(
+ line.X + offset_x,
+ line.Y - viewport_y + offset_y,
+ (int)line.widths[pos + 1] - viewport_x + line.X,
+ line.height + 1));
+ break;
+ }
+ }
+ }
+ }
+
+
+ // Update display from line, down line_count lines; pos is unused, but required for the signature
+ internal void UpdateView(Line line, int line_count, int pos) {
+ if (!owner.IsHandleCreated) {
+ return;
+ }
+
+ if (recalc_suspended > 0) {
+ recalc_start = Math.Min (recalc_start, line.line_no);
+ recalc_end = Math.Max (recalc_end, line.line_no + line_count);
+ recalc_optimize = true;
+ recalc_pending = true;
+ return;
+ }
+
+ int start_line_top = line.Y;
+
+ Line end_line = GetLine (line.line_no + line_count);
+ if (end_line == null)
+ end_line = GetLine (lines);
+
+ if (end_line == null)
+ return;
+
+ int end_line_bottom = end_line.Y + end_line.height;
+
+ if (RecalculateDocument(owner.CreateGraphicsInternal(), line.line_no, line.line_no + line_count, true)) {
+ // Lineheight changed, invalidate the rest of the document
+ if ((line.Y - viewport_y) >=0 ) {
+ // We formatted something that's in view, only draw parts of the screen
+ owner.Invalidate(new Rectangle(
+ offset_x,
+ line.Y - viewport_y + offset_y,
+ viewport_width,
+ owner.Height - (line.Y - viewport_y)));
+ } else {
+ // The tag was above the visible area, draw everything
+ owner.Invalidate();
+ }
+ } else {
+ int x = 0 - viewport_x + offset_x;
+ int w = viewport_width;
+ int y = Math.Min (start_line_top - viewport_y, line.Y - viewport_y) + offset_y;
+ int h = Math.Max (end_line_bottom - y, end_line.Y + end_line.height - y);
+
+ owner.Invalidate (new Rectangle (x, y, w, h));
+ }
+ }
+
+ /// <summary>
+ /// Scans the next paragraph for http:/ ftp:/ www. https:/ etc and marks the tags
+ /// as links.
+ /// </summary>
+ /// <param name="start_line">The line to start on</param>
+ /// <param name="link_changed">marks as true if something is changed</param>
+ private void ScanForLinks (Line start_line, ref bool link_changed)
+ {
+ Line current_line = start_line;
+ StringBuilder line_no_breaks = new StringBuilder ();
+ StringBuilder line_link_record = new StringBuilder ();
+ ArrayList cumulative_length_list = new ArrayList ();
+ bool update_caret_tag = false;
+
+ cumulative_length_list.Add (0);
+
+ while (current_line != null) {
+ line_no_breaks.Append (current_line.text);
+
+ if (link_changed == false)
+ current_line.LinkRecord (line_link_record);
+
+ current_line.ClearLinks ();
+
+ cumulative_length_list.Add (line_no_breaks.Length);
+
+ if (current_line.ending == LineEnding.Wrap)
+ current_line = GetLine (current_line.LineNo + 1);
+ else
+ break;
+ }
+
+ // search for protocols.. make sure www. is first!
+ string [] search_terms = new string [] { "www.", "http:/", "ftp:/", "https:/" };
+ int search_found = 0;
+ int index_found = 0;
+ string line_no_breaks_string = line_no_breaks.ToString ();
+ int line_no_breaks_index = 0;
+ int link_end = 0;
+
+ while (true) {
+ if (line_no_breaks_index >= line_no_breaks_string.Length)
+ break;
+
+ index_found = FirstIndexOfAny (line_no_breaks_string, search_terms, line_no_breaks_index, out search_found);
+
+ //no links found on this line
+ if (index_found == -1)
+ break;
+
+ if (search_found == 0) {
+ // if we are at the end of the line to analyse and the end of the line
+ // is "www." then there are no links here
+ if (line_no_breaks_string.Length == index_found + search_terms [0].Length)
+ break;
+
+ // if after www. we don't have a letter a digit or a @ or - or /
+ // then it is not a web address, we should continue searching
+ if (char.IsLetterOrDigit (line_no_breaks_string [index_found + search_terms [0].Length]) == false &&
+ "@/~".IndexOf (line_no_breaks_string [index_found + search_terms [0].Length].ToString ()) == -1) {
+ line_no_breaks_index = index_found + search_terms [0].Length;
+ continue;
+ }
+ }
+
+ link_end = line_no_breaks_string.Length - 1;
+ line_no_breaks_index = line_no_breaks_string.Length;
+
+ // we've found a link, we just need to find where it ends now
+ for (int i = index_found + search_terms [search_found].Length; i < line_no_breaks_string.Length; i++) {
+ if (line_no_breaks_string [i - 1] == '.') {
+ if (char.IsLetterOrDigit (line_no_breaks_string [i]) == false &&
+ "@/~".IndexOf (line_no_breaks_string [i].ToString ()) == -1) {
+ link_end = i - 1;
+ line_no_breaks_index = i;
+ break;
+ }
+ } else {
+ if (char.IsLetterOrDigit (line_no_breaks_string [i]) == false &&
+ "@-/:~.?=_&".IndexOf (line_no_breaks_string [i].ToString ()) == -1) {
+ link_end = i - 1;
+ line_no_breaks_index = i;
+ break;
+ }
+ }
+ }
+
+ string link_text = line_no_breaks_string.Substring (index_found, link_end - index_found + 1);
+ int current_cumulative = 0;
+
+ // we've found a link - index_found -> link_end
+ // now we just make all the tags as containing link and
+ // point them to the text for the whole link
+
+ current_line = start_line;
+
+ //find the line we start on
+ for (current_cumulative = 1; current_cumulative < cumulative_length_list.Count; current_cumulative++)
+ if ((int)cumulative_length_list [current_cumulative] > index_found)
+ break;
+
+ current_line = GetLine (start_line.LineNo + current_cumulative - 1);
+
+ // find the tag we start on
+ LineTag current_tag = current_line.FindTag (index_found - (int)cumulative_length_list [current_cumulative - 1] + 1);
+
+ if (current_tag.Start != (index_found - (int)cumulative_length_list [current_cumulative - 1]) + 1) {
+ if (current_tag == CaretTag)
+ update_caret_tag = true;
+
+ current_tag = current_tag.Break ((index_found - (int)cumulative_length_list [current_cumulative - 1]) + 1);
+ }
+
+ // set the tag
+ current_tag.IsLink = true;
+ current_tag.LinkText = link_text;
+
+ //go through each character
+ // find the tag we are in
+ // skip the number of characters in the tag
+ for (int i = 1; i < link_text.Length; i++) {
+ // on to a new word-wrapped line
+ if ((int)cumulative_length_list [current_cumulative] <= index_found + i) {
+
+ current_line = GetLine (start_line.LineNo + current_cumulative++);
+ current_tag = current_line.FindTag (index_found + i - (int)cumulative_length_list [current_cumulative - 1] + 1);
+
+ current_tag.IsLink = true;
+ current_tag.LinkText = link_text;
+
+ continue;
+ }
+
+ if (current_tag.End < index_found + 1 + i - (int)cumulative_length_list [current_cumulative - 1]) {
+ // skip empty tags in the middle of the URL
+ do {
+ current_tag = current_tag.Next;
+ } while (current_tag.Length == 0);
+
+ current_tag.IsLink = true;
+ current_tag.LinkText = link_text;
+ }
+ }
+
+ //if there are characters left in the tag after the link
+ // split the tag
+ // make the second part a non link
+ if (current_tag.End > (index_found + link_text.Length + 1) - (int)cumulative_length_list [current_cumulative - 1]) {
+ if (current_tag == CaretTag)
+ update_caret_tag = true;
+
+ current_tag.Break ((index_found + link_text.Length + 1) - (int)cumulative_length_list [current_cumulative - 1]);
+ }
+ }
+
+ if (update_caret_tag) {
+ CaretTag = LineTag.FindTag (CaretLine, CaretPosition);
+ link_changed = true;
+ } else {
+ if (link_changed == false) {
+ current_line = start_line;
+ StringBuilder new_link_record = new StringBuilder ();
+
+ while (current_line != null) {
+ current_line.LinkRecord (new_link_record);
+
+ if (current_line.ending == LineEnding.Wrap)
+ current_line = GetLine (current_line.LineNo + 1);
+ else
+ break;
+ }
+
+ if (new_link_record.Equals (line_link_record) == false)
+ link_changed = true;
+ }
+ }
+ }
+
+ private int FirstIndexOfAny (string haystack, string [] needles, int start_index, out int term_found)
+ {
+ term_found = -1;
+ int best_index = -1;
+
+ for (int i = 0; i < needles.Length; i++) {
+ int index = haystack.IndexOf (needles [i], start_index, StringComparison.InvariantCultureIgnoreCase);
+
+ if (index > -1) {
+ if (term_found > -1) {
+ if (index < best_index) {
+ best_index = index;
+ term_found = i;
+ }
+ } else {
+ best_index = index;
+ term_found = i;
+ }
+ }
+ }
+
+ return best_index;
+ }
+
+
+
+ private void InvalidateLinks (Rectangle clip)
+ {
+ for (int i = (owner.list_links.Count - 1); i >= 0; i--) {
+ TextBoxBase.LinkRectangle link = (TextBoxBase.LinkRectangle) owner.list_links [i];
+
+ if (clip.IntersectsWith (link.LinkAreaRectangle))
+ owner.list_links.RemoveAt (i);
+ }
+ }
+ #endregion // Private Methods
+
+ #region Internal Methods
+
+ internal void ScanForLinks (int start, int end, ref bool link_changed)
+ {
+ Line line = null;
+ LineEnding lastending = LineEnding.Rich;
+
+ // make sure we start scanning at the real begining of the line
+ while (true) {
+ if (start != 1 && GetLine (start - 1).ending == LineEnding.Wrap)
+ start--;
+ else
+ break;
+ }
+
+ for (int i = start; i <= end && i <= lines; i++) {
+ line = GetLine (i);
+
+ if (lastending != LineEnding.Wrap)
+ ScanForLinks (line, ref link_changed);
+
+ lastending = line.ending;
+
+ if (lastending == LineEnding.Wrap && (i + 1) <= end)
+ end++;
+ }
+ }
+
+ // Clear the document and reset state
+ internal void Empty() {
+
+ document = sentinel;
+ lines = 0;
+
+ // We always have a blank line
+ Add (1, String.Empty, owner.Font, owner.ForeColor, LineEnding.None);
+
+ this.RecalculateDocument(owner.CreateGraphicsInternal());
+ PositionCaret(0, 0);
+
+ SetSelectionVisible (false);
+
+ selection_start.line = this.document;
+ selection_start.pos = 0;
+ selection_start.tag = selection_start.line.tags;
+ selection_end.line = this.document;
+ selection_end.pos = 0;
+ selection_end.tag = selection_end.line.tags;
+ char_count = 0;
+
+ viewport_x = 0;
+ viewport_y = 0;
+
+ document_x = 0;
+ document_y = 0;
+
+ if (owner.IsHandleCreated)
+ owner.Invalidate ();
+ }
+
+ internal void PositionCaret(Line line, int pos) {
+ caret.tag = line.FindTag (pos);
+
+ MoveCaretToTextTag ();
+
+ caret.line = line;
+ caret.pos = pos;
+
+ if (owner.IsHandleCreated) {
+ if (owner.Focused) {
+ if (caret.height != caret.tag.Height)
+ XplatUI.CreateCaret (owner.Handle, caret_width, caret.height);
+ XplatUI.SetCaretPos(owner.Handle,
+ offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x,
+ offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift);
+ }
+
+ if (CaretMoved != null) CaretMoved(this, EventArgs.Empty);
+ }
+
+ // We set this at the end because we use the heights to determine whether or
+ // not we need to recreate the caret
+ caret.height = caret.tag.Height;
+
+ }
+
+ internal void PositionCaret(int x, int y) {
+ if (!owner.IsHandleCreated) {
+ return;
+ }
+
+ caret.tag = FindCursor(x, y, out caret.pos);
+
+ MoveCaretToTextTag ();
+
+ caret.line = caret.tag.Line;
+ caret.height = caret.tag.Height;
+
+ if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) {
+ XplatUI.CreateCaret (owner.Handle, caret_width, caret.height);
+ XplatUI.SetCaretPos(owner.Handle,
+ (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x + offset_x,
+ offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift);
+ }
+
+ if (CaretMoved != null) CaretMoved(this, EventArgs.Empty);
+ }
+
+ internal void CaretHasFocus() {
+ if ((caret.tag != null) && owner.IsHandleCreated) {
+ XplatUI.CreateCaret(owner.Handle, caret_width, caret.height);
+ XplatUI.SetCaretPos(owner.Handle,
+ offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x,
+ offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift);
+
+ DisplayCaret ();
+ }
+
+ if (owner.IsHandleCreated && SelectionLength () > 0) {
+ InvalidateSelectionArea ();
+ }
+ }
+
+ internal void CaretLostFocus() {
+ if (!owner.IsHandleCreated) {
+ return;
+ }
+ XplatUI.DestroyCaret(owner.Handle);
+ }
+
+ internal void AlignCaret ()
+ {
+ AlignCaret (true);
+ }
+
+ internal void AlignCaret(bool changeCaretTag) {
+ if (!owner.IsHandleCreated) {
+ return;
+ }
+
+ if (changeCaretTag) {
+ caret.tag = LineTag.FindTag (caret.line, caret.pos);
+
+ MoveCaretToTextTag ();
+ }
+
+ // if the caret has had SelectionFont changed to a
+ // different height, we reflect changes unless the new
+ // font is larger than the line (line recalculations
+ // ignore empty tags) in which case we make it equal
+ // the line height and then when text is entered
+ if (caret.tag.Height > caret.tag.Line.Height) {
+ caret.height = caret.line.height;
+ } else {
+ caret.height = caret.tag.Height;
+ }
+
+ if (owner.Focused) {
+ XplatUI.CreateCaret(owner.Handle, caret_width, caret.height);
+ XplatUI.SetCaretPos (owner.Handle,
+ offset_x + (int) caret.tag.Line.widths [caret.pos] + caret.line.X - viewport_x,
+ offset_y + caret.line.Y + viewport_y + caret_shift);
+ DisplayCaret ();
+ }
+
+ if (CaretMoved != null) CaretMoved(this, EventArgs.Empty);
+ }
+
+ internal void UpdateCaret() {
+ if (!owner.IsHandleCreated || caret.tag == null) {
+ return;
+ }
+
+ MoveCaretToTextTag ();
+
+ if (caret.tag.Height != caret.height) {
+ caret.height = caret.tag.Height;
+ if (owner.Focused) {
+ XplatUI.CreateCaret(owner.Handle, caret_width, caret.height);
+ }
+ }
+
+ if (owner.Focused) {
+ XplatUI.SetCaretPos(owner.Handle,
+ offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x,
+ offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift);
+ DisplayCaret ();
+ }
+
+ if (CaretMoved != null) CaretMoved(this, EventArgs.Empty);
+ }
+
+ internal void DisplayCaret() {
+ if (!owner.IsHandleCreated) {
+ return;
+ }
+
+ if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) {
+ XplatUI.CaretVisible(owner.Handle, true);
+ }
+ }
+
+ internal void HideCaret() {
+ if (!owner.IsHandleCreated) {
+ return;
+ }
+
+ if (owner.Focused) {
+ XplatUI.CaretVisible(owner.Handle, false);
+ }
+ }
+
+
+ internal void MoveCaretToTextTag ()
+ {
+ if (caret.tag == null || caret.tag.IsTextTag)
+ return;
+
+
+
+ if (caret.pos < caret.tag.Start) {
+ caret.tag = caret.tag.Previous;
+ } else {
+ caret.tag = caret.tag.Next;
+ }
+ }
+
+ internal void MoveCaret(CaretDirection direction) {
+ // FIXME should we use IsWordSeparator to detect whitespace, instead
+ // of looking for actual spaces in the Word move cases?
+
+ bool nowrap = false;
+ switch(direction) {
+ case CaretDirection.CharForwardNoWrap:
+ nowrap = true;
+ goto case CaretDirection.CharForward;
+ case CaretDirection.CharForward: {
+ caret.pos++;
+ if (caret.pos > caret.line.TextLengthWithoutEnding ()) {
+ if (!nowrap) {
+ // Go into next line
+ if (caret.line.line_no < this.lines) {
+ caret.line = GetLine(caret.line.line_no+1);
+ caret.pos = 0;
+ caret.tag = caret.line.tags;
+ } else {
+ caret.pos--;
+ }
+ } else {
+ // Single line; we stay where we are
+ caret.pos--;
+ }
+ } else {
+ if ((caret.tag.Start - 1 + caret.tag.Length) < caret.pos) {
+ caret.tag = caret.tag.Next;
+ }
+ }
+ UpdateCaret();
+ return;
+ }
+
+ case CaretDirection.CharBackNoWrap:
+ nowrap = true;
+ goto case CaretDirection.CharBack;
+ case CaretDirection.CharBack: {
+ if (caret.pos > 0) {
+ // caret.pos--; // folded into the if below
+
+ if (--caret.pos > 0) {
+ if (caret.tag.Start > caret.pos) {
+ caret.tag = caret.tag.Previous;
+ }
+ }
+ } else {
+ if (caret.line.line_no > 1 && !nowrap) {
+ caret.line = GetLine(caret.line.line_no - 1);
+ caret.pos = caret.line.TextLengthWithoutEnding ();
+ caret.tag = LineTag.FindTag(caret.line, caret.pos);
+ }
+ }
+ UpdateCaret();
+ return;
+ }
+
+ case CaretDirection.WordForward: {
+ int len;
+
+ len = caret.line.text.Length;
+ if (caret.pos < len) {
+ while ((caret.pos < len) && (caret.line.text[caret.pos] != ' ')) {
+ caret.pos++;
+ }
+ if (caret.pos < len) {
+ // Skip any whitespace
+ while ((caret.pos < len) && (caret.line.text[caret.pos] == ' ')) {
+ caret.pos++;
+ }
+ }
+ caret.tag = LineTag.FindTag(caret.line, caret.pos);
+ } else {
+ if (caret.line.line_no < this.lines) {
+ caret.line = GetLine(caret.line.line_no + 1);
+ caret.pos = 0;
+ caret.tag = caret.line.tags;
+ }
+ }
+ UpdateCaret();
+ return;
+ }
+
+ case CaretDirection.WordBack: {
+ if (caret.pos > 0) {
+ caret.pos--;
+
+ while ((caret.pos > 0) && (caret.line.text[caret.pos] == ' ')) {
+ caret.pos--;
+ }
+
+ while ((caret.pos > 0) && (caret.line.text[caret.pos] != ' ')) {
+ caret.pos--;
+ }
+
+ if (caret.line.text.ToString(caret.pos, 1) == " ") {
+ if (caret.pos != 0) {
+ caret.pos++;
+ } else {
+ caret.line = GetLine(caret.line.line_no - 1);
+ caret.pos = caret.line.text.Length;
+ }
+ }
+ caret.tag = LineTag.FindTag(caret.line, caret.pos);
+ } else {
+ if (caret.line.line_no > 1) {
+ caret.line = GetLine(caret.line.line_no - 1);
+ caret.pos = caret.line.text.Length;
+ caret.tag = LineTag.FindTag(caret.line, caret.pos);
+ }
+ }
+ UpdateCaret();
+ return;
+ }
+
+ case CaretDirection.LineUp: {
+ if (caret.line.line_no > 1) {
+ int pixel;
+
+ pixel = (int)caret.line.widths[caret.pos];
+ PositionCaret(pixel, GetLine(caret.line.line_no - 1).Y);
+
+ DisplayCaret ();
+ }
+ return;
+ }
+
+ case CaretDirection.LineDown: {
+ if (caret.line.line_no < lines) {
+ int pixel;
+
+ pixel = (int)caret.line.widths[caret.pos];
+ PositionCaret(pixel, GetLine(caret.line.line_no + 1).Y);
+
+ DisplayCaret ();
+ }
+ return;
+ }
+
+ case CaretDirection.Home: {
+ if (caret.pos > 0) {
+ caret.pos = 0;
+ caret.tag = caret.line.tags;
+ UpdateCaret();
+ }
+ return;
+ }
+
+ case CaretDirection.End: {
+ if (caret.pos < caret.line.TextLengthWithoutEnding ()) {
+ caret.pos = caret.line.TextLengthWithoutEnding ();
+ caret.tag = LineTag.FindTag(caret.line, caret.pos);
+ UpdateCaret();
+ }
+ return;
+ }
+
+ case CaretDirection.PgUp: {
+
+ if (caret.line.line_no == 1 && owner.richtext) {
+ owner.vscroll.Value = 0;
+ Line line = GetLine (1);
+ PositionCaret (line, 0);
+ }
+
+ int y_offset = caret.line.Y + caret.line.height - 1 - viewport_y;
+ int index;
+ LineTag top = FindCursor ((int) caret.line.widths [caret.pos],
+ viewport_y - viewport_height, out index);
+
+ owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height);
+ PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y);
+
+ return;
+ }
+
+ case CaretDirection.PgDn: {
+
+ if (caret.line.line_no == lines && owner.richtext) {
+ owner.vscroll.Value = owner.vscroll.Maximum - viewport_height + 1;
+ Line line = GetLine (lines);
+ PositionCaret (line, line.TextLengthWithoutEnding());
+ }
+
+ int y_offset = caret.line.Y - viewport_y;
+ int index;
+ LineTag top = FindCursor ((int) caret.line.widths [caret.pos],
+ viewport_y + viewport_height, out index);
+
+ owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height);
+ PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y);
+
+ return;
+ }
+
+ case CaretDirection.CtrlPgUp: {
+ PositionCaret(0, viewport_y);
+ DisplayCaret ();
+ return;
+ }
+
+ case CaretDirection.CtrlPgDn: {
+ Line line;
+ LineTag tag;
+ int index;
+
+ tag = FindCursor (0, viewport_y + viewport_height, out index);
+ if (tag.Line.line_no > 1) {
+ line = GetLine(tag.Line.line_no - 1);
+ } else {
+ line = tag.Line;
+ }
+ PositionCaret(line, line.Text.Length);
+ DisplayCaret ();
+ return;
+ }
+
+ case CaretDirection.CtrlHome: {
+ caret.line = GetLine(1);
+ caret.pos = 0;
+ caret.tag = caret.line.tags;
+
+ UpdateCaret();
+ return;
+ }
+
+ case CaretDirection.CtrlEnd: {
+ caret.line = GetLine(lines);
+ caret.pos = caret.line.TextLengthWithoutEnding ();
+ caret.tag = LineTag.FindTag(caret.line, caret.pos);
+
+ UpdateCaret();
+ return;
+ }
+
+ case CaretDirection.SelectionStart: {
+ caret.line = selection_start.line;
+ caret.pos = selection_start.pos;
+ caret.tag = selection_start.tag;
+
+ UpdateCaret();
+ return;
+ }
+
+ case CaretDirection.SelectionEnd: {
+ caret.line = selection_end.line;
+ caret.pos = selection_end.pos;
+ caret.tag = selection_end.tag;
+
+ UpdateCaret();
+ return;
+ }
+ }
+ }
+
+ internal void DumpDoc ()
+ {
+ Console.WriteLine ("<doc lines='{0}'>", lines);
+ for (int i = 1; i <= lines ; i++) {
+ Line line = GetLine (i);
+ Console.WriteLine ("<line no='{0}' ending='{1}'>", line.line_no, line.ending);
+
+ LineTag tag = line.tags;
+ while (tag != null) {
+ Console.Write ("\t<tag type='{0}' span='{1}->{2}' font='{3}' color='{4}'>",
+ tag.GetType (), tag.Start, tag.Length, tag.Font, tag.Color);
+ Console.Write (tag.Text ());
+ Console.WriteLine ("</tag>");
+ tag = tag.Next;
+ }
+ Console.WriteLine ("</line>");
+ }
+ Console.WriteLine ("</doc>");
+ }
+
+ // UIA: Used via reflection by TextProviderBehavior
+ internal void GetVisibleLineIndexes (Rectangle clip, out int start, out int end)
+ {
+ if (multiline) {
+ /* Expand the region slightly to be sure to
+ * paint the full extent of the line of text.
+ * See bug 464464.
+ */
+ start = GetLineByPixel(clip.Top + viewport_y - offset_y - 1, false).line_no;
+ end = GetLineByPixel(clip.Bottom + viewport_y - offset_y + 1, false).line_no;
+ } else {
+ start = GetLineByPixel(clip.Left + viewport_x - offset_x, false).line_no;
+ end = GetLineByPixel(clip.Right + viewport_x - offset_x, false).line_no;
+ }
+ }
+
+ internal void Draw (Graphics g, Rectangle clip)
+ {
+ Line line; // Current line being drawn
+ LineTag tag; // Current tag being drawn
+ int start; // First line to draw
+ int end; // Last line to draw
+ StringBuilder text; // String representing the current line
+ int line_no;
+ Color tag_color;
+ Color current_color;
+
+ // First, figure out from what line to what line we need to draw
+ GetVisibleLineIndexes (clip, out start, out end);
+
+ // remove links in the list (used for mouse down events) that are within the clip area.
+ InvalidateLinks (clip);
+
+ ///
+ /// We draw the single border ourself
+ ///
+ if (owner.actual_border_style == BorderStyle.FixedSingle) {
+ WidgetPaint.DrawBorder (g, owner.ClientRectangle, Color.Black, ButtonBorderStyle.Solid);
+ }
+
+ /// Make sure that we aren't drawing one more line then we need to
+ line = GetLine (end - 1);
+ if (line != null && clip.Bottom == offset_y + line.Y + line.height - viewport_y)
+ end--;
+
+ line_no = start;
+
+ #if Debug
+ DateTime n = DateTime.Now;
+ Console.WriteLine ("Started drawing: {0}s {1}ms", n.Second, n.Millisecond);
+ Console.WriteLine ("CLIP: {0}", clip);
+ Console.WriteLine ("S: {0}", GetLine (start).text);
+ Console.WriteLine ("E: {0}", GetLine (end).text);
+ #endif
+
+ // Non multiline selection can be handled outside of the loop
+ if (!multiline && selection_visible && owner.ShowSelection) {
+ g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight),
+ offset_x + selection_start.line.widths [selection_start.pos] +
+ selection_start.line.X - viewport_x,
+ offset_y + selection_start.line.Y,
+ (selection_end.line.X + selection_end.line.widths [selection_end.pos]) -
+ (selection_start.line.X + selection_start.line.widths [selection_start.pos]),
+ selection_start.line.height);
+ }
+
+ while (line_no <= end) {
+ line = GetLine (line_no);
+ float line_y = line.Y - viewport_y + offset_y;
+
+ tag = line.tags;
+ if (!calc_pass) {
+ text = line.text;
+ } else {
+ if (PasswordCache.Length < line.text.Length)
+ PasswordCache.Append(Char.Parse(password_char), line.text.Length - PasswordCache.Length);
+ else if (PasswordCache.Length > line.text.Length)
+ PasswordCache.Remove(line.text.Length, PasswordCache.Length - line.text.Length);
+ text = PasswordCache;
+ }
+
+ int line_selection_start = text.Length + 1;
+ int line_selection_end = text.Length + 1;
+ if (selection_visible && owner.ShowSelection &&
+ (line_no >= selection_start.line.line_no) &&
+ (line_no <= selection_end.line.line_no)) {
+
+ if (line_no == selection_start.line.line_no)
+ line_selection_start = selection_start.pos + 1;
+ else
+ line_selection_start = 1;
+
+ if (line_no == selection_end.line.line_no)
+ line_selection_end = selection_end.pos + 1;
+ else
+ line_selection_end = text.Length + 1;
+
+ if (line_selection_end == line_selection_start) {
+ // There isn't really selection
+ line_selection_start = text.Length + 1;
+ line_selection_end = line_selection_start;
+ } else if (multiline) {
+ // lets draw some selection baby!! (non multiline selection is drawn outside the loop)
+ g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight),
+ offset_x + line.widths [line_selection_start - 1] + line.X - viewport_x,
+ line_y, line.widths [line_selection_end - 1] - line.widths [line_selection_start - 1],
+ line.height);
+ }
+ }
+
+ current_color = line.tags.ColorToDisplay;
+ while (tag != null) {
+
+ // Skip empty tags
+ if (tag.Length == 0) {
+ tag = tag.Next;
+ continue;
+ }
+
+ if (((tag.X + tag.Width) < (clip.Left - viewport_x - offset_x)) &&
+ (tag.X > (clip.Right - viewport_x - offset_x))) {
+ tag = tag.Next;
+ continue;
+ }
+
+ if (tag.BackColor != Color.Empty) {
+ g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (tag.BackColor),
+ offset_x + tag.X + line.X - viewport_x,
+ line_y + tag.Shift, tag.Width, line.height);
+ }
+
+ tag_color = tag.ColorToDisplay;
+ current_color = tag_color;
+
+ if (!owner.Enabled) {
+ Color a = tag.Color;
+ Color b = ThemeEngine.Current.ColorWindowText;
+
+ if ((a.R == b.R) && (a.G == b.G) && (a.B == b.B))
+ tag_color = ThemeEngine.Current.ColorGrayText;
+
+ }
+
+ int tag_pos = tag.Start;
+ current_color = tag_color;
+ while (tag_pos < tag.Start + tag.Length) {
+ int old_tag_pos = tag_pos;
+
+ if (tag_pos >= line_selection_start && tag_pos < line_selection_end) {
+ current_color = ThemeEngine.Current.ColorHighlightText;
+ tag_pos = Math.Min (tag.End, line_selection_end);
+ } else if (tag_pos < line_selection_start) {
+ current_color = tag_color;
+ tag_pos = Math.Min (tag.End, line_selection_start);
+ } else {
+ current_color = tag_color;
+ tag_pos = tag.End;
+ }
+
+ Rectangle text_size;
+
+ tag.Draw (g, current_color,
+ offset_x + line.X - viewport_x,
+ line_y + tag.Shift,
+ old_tag_pos - 1, Math.Min (tag.Start + tag.Length, tag_pos) - 1,
+ text.ToString (), out text_size, tag.IsLink);
+
+ if (tag.IsLink) {
+ TextBoxBase.LinkRectangle link = new TextBoxBase.LinkRectangle (text_size);
+ link.LinkTag = tag;
+ owner.list_links.Add (link);
+ }
+ }
+ tag = tag.Next;
+ }
+
+ line.DrawEnding (g, line_y);
+ line_no++;
+ }
+ }
+
+ private int GetLineEnding (string line, int start, out LineEnding ending)
+ {
+ int res;
+ int rich_index;
+
+ if (start >= line.Length) {
+ ending = LineEnding.Wrap;
+ return -1;
+ }
+
+ res = line.IndexOf ('\r', start);
+ rich_index = line.IndexOf ('\n', start);
+
+ // Handle the case where we find both of them, and the \n is before the \r
+ if (res != -1 && rich_index != -1)
+ if (rich_index < res) {
+ ending = LineEnding.Rich;
+ return rich_index;
+ }
+
+ if (res != -1) {
+ if (res + 2 < line.Length && line [res + 1] == '\r' && line [res + 2] == '\n') {
+ ending = LineEnding.Soft;
+ return res;
+ }
+ if (res + 1 < line.Length && line [res + 1] == '\n') {
+ ending = LineEnding.Hard;
+ return res;
+ }
+ ending = LineEnding.Limp;
+ return res;
+ }
+
+ if (rich_index != -1) {
+ ending = LineEnding.Rich;
+ return rich_index;
+ }
+
+ ending = LineEnding.Wrap;
+ return line.Length;
+ }
+
+ // Get the line ending, but only of the types specified
+ private int GetLineEnding (string line, int start, out LineEnding ending, LineEnding type)
+ {
+ int index = start;
+ int last_length = 0;
+
+ do {
+ index = GetLineEnding (line, index + last_length, out ending);
+ last_length = LineEndingLength (ending);
+ } while
+ ((ending & type) != ending && index != -1);
+
+ return index == -1 ? line.Length : index;
+ }
+
+ internal int LineEndingLength (LineEnding ending)
+ {
+ switch (ending) {
+ case LineEnding.Limp:
+ case LineEnding.Rich:
+ return 1;
+ case LineEnding.Hard:
+ return 2;
+ case LineEnding.Soft:
+ return 3;
+ }
+
+ return 0;
+ }
+
+ internal string LineEndingToString (LineEnding ending)
+ {
+ switch (ending) {
+ case LineEnding.Limp:
+ return "\r";
+ case LineEnding.Hard:
+ return "\r\n";
+ case LineEnding.Soft:
+ return "\r\r\n";
+ case LineEnding.Rich:
+ return "\n";
+ }
+
+ return string.Empty;
+ }
+
+ internal LineEnding StringToLineEnding (string ending)
+ {
+ switch (ending) {
+ case "\r":
+ return LineEnding.Limp;
+ case "\r\n":
+ return LineEnding.Hard;
+ case "\r\r\n":
+ return LineEnding.Soft;
+ case "\n":
+ return LineEnding.Rich;
+ default:
+ return LineEnding.None;
+ }
+ }
+
+ internal void Insert (Line line, int pos, bool update_caret, string s)
+ {
+ Insert (line, pos, update_caret, s, line.FindTag (pos));
+ }
+
+ // Insert text at the given position; use formatting at insertion point for inserted text
+ internal void Insert (Line line, int pos, bool update_caret, string s, LineTag tag)
+ {
+ int break_index;
+ int base_line;
+ int old_line_count;
+ int count = 1;
+ LineEnding ending;
+ Line split_line;
+
+ // Don't recalculate while we mess around
+ SuspendRecalc ();
+
+ base_line = line.line_no;
+ old_line_count = lines;
+
+ // Discard chars after any possible -unlikely- end of file
+ int eof_index = s.IndexOf ('\0');
+ if (eof_index != -1)
+ s = s.Substring (0, eof_index);
+
+ break_index = GetLineEnding (s, 0, out ending, LineEnding.Hard | LineEnding.Rich);
+
+ // There are no line feeds in our text to be pasted
+ if (break_index == s.Length) {
+ line.InsertString (pos, s, tag);
+ } else {
+ // Add up to the first line feed to our current position
+ line.InsertString (pos, s.Substring (0, break_index + LineEndingLength (ending)), tag);
+
+ // Split the rest of the original line to a new line
+ Split (line, pos + (break_index + LineEndingLength (ending)));
+ line.ending = ending;
+ break_index += LineEndingLength (ending);
+ split_line = GetLine (line.line_no + 1);
+
+ // Insert brand new lines for any more line feeds in the inserted string
+ while (true) {
+ int next_break = GetLineEnding (s, break_index, out ending, LineEnding.Hard | LineEnding.Rich);
+
+ if (next_break == s.Length)
+ break;
+
+ string line_text = s.Substring (break_index, next_break - break_index +
+ LineEndingLength (ending));
+
+ Add (base_line + count, line_text, line.alignment, tag.Font, tag.Color, ending);
+
+ Line last = GetLine (base_line + count);
+ last.ending = ending;
+
+ count++;
+ break_index = next_break + LineEndingLength (ending);
+ }
+
+ // Add the remainder of the insert text to the split
+ // part of the original line
+ split_line.InsertString (0, s.Substring (break_index));
+ }
+
+ // Allow the document to recalculate things
+ ResumeRecalc (false);
+
+ // Update our character count
+ CharCount += s.Length;
+
+ UpdateView (line, lines - old_line_count + 1, pos);
+
+ // Move the caret to the end of the inserted text if requested
+ if (update_caret) {
+ Line l = GetLine (line.line_no + lines - old_line_count);
+ PositionCaret (l, l.text.Length);
+ DisplayCaret ();
+ }
+ }
+
+ // Inserts a string at the given position
+ internal void InsertString (Line line, int pos, string s)
+ {
+ // Update our character count
+ CharCount += s.Length;
+
+ // Insert the text into the Line
+ line.InsertString (pos, s);
+ }
+
+ // Inserts a character at the current caret position
+ internal void InsertCharAtCaret (char ch, bool move_caret)
+ {
+ caret.line.InsertString (caret.pos, ch.ToString(), caret.tag);
+
+ // Update our character count
+ CharCount++;
+
+ undo.RecordTyping (caret.line, caret.pos, ch);
+
+ UpdateView (caret.line, caret.pos);
+
+ if (move_caret) {
+ caret.pos++;
+ UpdateCaret ();
+ SetSelectionToCaret (true);
+ }
+ }
+
+ internal void InsertPicture (Line line, int pos, RTF.Picture picture)
+ {
+ //LineTag next_tag;
+ LineTag tag;
+ int len;
+
+ len = 1;
+
+ // Just a place holder basically
+ line.text.Insert (pos, "I");
+
+ PictureTag picture_tag = new PictureTag (line, pos + 1, picture);
+
+ tag = LineTag.FindTag (line, pos);
+ picture_tag.CopyFormattingFrom (tag);
+ /*next_tag = */tag.Break (pos + 1);
+ picture_tag.Previous = tag;
+ picture_tag.Next = tag.Next;
+ tag.Next = picture_tag;
+
+ //
+ // Picture tags need to be surrounded by text tags
+ //
+ if (picture_tag.Next == null) {
+ picture_tag.Next = new LineTag (line, pos + 1);
+ picture_tag.Next.CopyFormattingFrom (tag);
+ picture_tag.Next.Previous = picture_tag;
+ }
+
+ tag = picture_tag.Next;
+ while (tag != null) {
+ tag.Start += len;
+ tag = tag.Next;
+ }
+
+ line.Grow (len);
+ line.recalc = true;
+
+ UpdateView (line, pos);
+ }
+
+ internal void DeleteMultiline (Line start_line, int pos, int length)
+ {
+ Marker start = new Marker ();
+ Marker end = new Marker ();
+ int start_index = LineTagToCharIndex (start_line, pos);
+
+ start.line = start_line;
+ start.pos = pos;
+ start.tag = LineTag.FindTag (start_line, pos);
+
+ CharIndexToLineTag (start_index + length, out end.line,
+ out end.tag, out end.pos);
+
+ SuspendUpdate ();
+
+ if (start.line == end.line) {
+ DeleteChars (start.line, pos, end.pos - pos);
+ } else {
+
+ // Delete first and last lines
+ DeleteChars (start.line, start.pos, start.line.text.Length - start.pos);
+ DeleteChars (end.line, 0, end.pos);
+
+ int current = start.line.line_no + 1;
+ if (current < end.line.line_no) {
+ for (int i = end.line.line_no - 1; i >= current; i--) {
+ Delete (i);
+ }
+ }
+
+ // BIG FAT WARNING - selection_end.line might be stale due
+ // to the above Delete() call. DONT USE IT before hitting the end of this method!
+
+ // Join start and end
+ Combine (start.line.line_no, current);
+ }
+
+ ResumeUpdate (true);
+ }
+
+
+ // Deletes n characters at the given position; it will not delete past line limits
+ // pos is 0-based
+ public void DeleteChars (Line line, int pos, int count)
+ {
+ // Reduce our character count
+ CharCount -= count;
+
+ line.DeleteCharacters (pos, count);
+
+ if (pos >= line.TextLengthWithoutEnding ()) {
+ LineEnding ending = line.ending;
+ GetLineEnding (line.text.ToString (), 0, out ending);
+
+ if (ending != line.ending) {
+ line.ending = ending;
+
+ if (!multiline) {
+ UpdateView (line, lines, pos);
+ owner.Invalidate ();
+ return;
+ }
+ }
+ }
+ if (!multiline) {
+ UpdateView (line, lines, pos);
+ owner.Invalidate ();
+ } else
+ UpdateView (line, pos);
+ }
+
+ // Deletes a character at or after the given position (depending on forward); it will not delete past line limits
+ public void DeleteChar (Line line, int pos, bool forward)
+ {
+ if ((pos == 0 && forward == false) || (pos == line.text.Length && forward == true))
+ return;
+
+ undo.BeginUserAction ("Delete");
+
+ if (forward) {
+ undo.RecordDeleteString (line, pos, line, pos + 1);
+ DeleteChars (line, pos, 1);
+ } else {
+ undo.RecordDeleteString (line, pos - 1, line, pos);
+ DeleteChars (line, pos - 1, 1);
+ }
+
+ undo.EndUserAction ();
+ }
+
+ // Combine two lines
+ internal void Combine(int FirstLine, int SecondLine) {
+ Combine(GetLine(FirstLine), GetLine(SecondLine));
+ }
+
+ internal void Combine(Line first, Line second) {
+ LineTag last;
+ int shift;
+
+ // strip the ending off of the first lines text
+ first.text.Length = first.text.Length - LineEndingLength (first.ending);
+
+ // Combine the two tag chains into one
+ last = first.tags;
+
+ // Maintain the line ending style
+ first.ending = second.ending;
+
+ while (last.Next != null) {
+ last = last.Next;
+ }
+
+ // need to get the shift before setting the next tag since that effects length
+ shift = last.Start + last.Length - 1;
+ last.Next = second.tags;
+ last.Next.Previous = last;
+
+ // Fix up references within the chain
+ last = last.Next;
+ while (last != null) {
+ last.Line = first;
+ last.Start += shift;
+ last = last.Next;
+ }
+
+ // Combine both lines' strings
+ first.text.Insert(first.text.Length, second.text.ToString());
+ first.Grow(first.text.Length);
+
+ // Remove the reference to our (now combined) tags from the doomed line
+ second.tags = null;
+
+ // Renumber lines
+ DecrementLines(first.line_no + 2); // first.line_no + 1 will be deleted, so we need to start renumbering one later
+
+ // Mop up
+ first.recalc = true;
+ first.height = 0; // This forces RecalcDocument/UpdateView to redraw from this line on
+ first.Streamline(lines);
+
+ // Update Caret, Selection, etc
+ if (caret.line == second) {
+ caret.Combine(first, shift);
+ }
+ if (selection_anchor.line == second) {
+ selection_anchor.Combine(first, shift);
+ }
+ if (selection_start.line == second) {
+ selection_start.Combine(first, shift);
+ }
+ if (selection_end.line == second) {
+ selection_end.Combine(first, shift);
+ }
+
+ #if Debug
+ Line check_first;
+ Line check_second;
+
+ check_first = GetLine(first.line_no);
+ check_second = GetLine(check_first.line_no + 1);
+
+ Console.WriteLine("Pre-delete: Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y);
+ #endif
+
+ this.Delete(second);
+
+ #if Debug
+ check_first = GetLine(first.line_no);
+ check_second = GetLine(check_first.line_no + 1);
+
+ Console.WriteLine("Post-delete Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y);
+ #endif
+ }
+
+ // Split the line at the position into two
+ internal void Split(int LineNo, int pos) {
+ Line line;
+ LineTag tag;
+
+ line = GetLine(LineNo);
+ tag = LineTag.FindTag(line, pos);
+ Split(line, tag, pos);
+ }
+
+ internal void Split(Line line, int pos) {
+ LineTag tag;
+
+ tag = LineTag.FindTag(line, pos);
+ Split(line, tag, pos);
+ }
+
+ ///<summary>Split line at given tag and position into two lines</summary>
+ ///if more space becomes available on previous line
+ internal void Split(Line line, LineTag tag, int pos) {
+ LineTag new_tag;
+ Line new_line;
+ bool move_caret;
+ bool move_sel_start;
+ bool move_sel_end;
+
+ move_caret = false;
+ move_sel_start = false;
+ move_sel_end = false;
+
+#if DEBUG
+ SanityCheck();
+
+ if (tag.End < pos)
+ throw new Exception ("Split called with the wrong tag");
+#endif
+
+ // Adjust selection and cursors
+ if (caret.line == line && caret.pos >= pos) {
+ move_caret = true;
+ }
+ if (selection_start.line == line && selection_start.pos > pos) {
+ move_sel_start = true;
+ }
+
+ if (selection_end.line == line && selection_end.pos > pos) {
+ move_sel_end = true;
+ }
+
+ // cover the easy case first
+ if (pos == line.text.Length) {
+ Add (line.line_no + 1, String.Empty, line.alignment, tag.Font, tag.Color, line.ending);
+
+ new_line = GetLine (line.line_no + 1);
+
+ if (move_caret) {
+ caret.line = new_line;
+ caret.tag = new_line.tags;
+ caret.pos = 0;
+
+ if (selection_visible == false) {
+ SetSelectionToCaret (true);
+ }
+ }
+
+ if (move_sel_start) {
+ selection_start.line = new_line;
+ selection_start.pos = 0;
+ selection_start.tag = new_line.tags;
+ }
+
+ if (move_sel_end) {
+ selection_end.line = new_line;
+ selection_end.pos = 0;
+ selection_end.tag = new_line.tags;
+ }
+
+#if DEBUG
+ SanityCheck ();
+#endif
+ return;
+ }
+
+ // We need to move the rest of the text into the new line
+ Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.Font, tag.Color, line.ending);
+
+ // Now transfer our tags from this line to the next
+ new_line = GetLine(line.line_no + 1);
+
+ line.recalc = true;
+ new_line.recalc = true;
+
+ //make sure that if we are at the end of a tag, we start on the begining
+ //of a new one, if one exists... Stops us creating an empty tag and
+ //make the operation easier.
+ if (tag.Next != null && (tag.Next.Start - 1) == pos)
+ tag = tag.Next;
+
+ if ((tag.Start - 1) == pos) {
+ int shift;
+
+ // We can simply break the chain and move the tag into the next line
+
+ // if the tag we are moving is the first, create an empty tag
+ // for the line we are leaving behind
+ if (tag == line.tags) {
+ new_tag = new LineTag(line, 1);
+ new_tag.CopyFormattingFrom (tag);
+ line.tags = new_tag;
+ }
+
+ if (tag.Previous != null) {
+ tag.Previous.Next = null;
+ }
+ new_line.tags = tag;
+ tag.Previous = null;
+ tag.Line = new_line;
+
+ // Walk the list and correct the start location of the tags we just bumped into the next line
+ shift = tag.Start - 1;
+
+ new_tag = tag;
+ while (new_tag != null) {
+ new_tag.Start -= shift;
+ new_tag.Line = new_line;
+ new_tag = new_tag.Next;
+ }
+ } else {
+ int shift;
+
+ new_tag = new LineTag (new_line, 1);
+ new_tag.Next = tag.Next;
+ new_tag.CopyFormattingFrom (tag);
+ new_line.tags = new_tag;
+ if (new_tag.Next != null) {
+ new_tag.Next.Previous = new_tag;
+ }
+ tag.Next = null;
+
+ shift = pos;
+ new_tag = new_tag.Next;
+ while (new_tag != null) {
+ new_tag.Start -= shift;
+ new_tag.Line = new_line;
+ new_tag = new_tag.Next;
+
+ }
+ }
+
+ if (move_caret) {
+ caret.line = new_line;
+ caret.pos = caret.pos - pos;
+ caret.tag = caret.line.FindTag(caret.pos);
+
+ if (selection_visible == false) {
+ SetSelectionToCaret (true);
+ move_sel_start = false;
+ move_sel_end = false;
+ }
+ }
+
+ if (move_sel_start) {
+ selection_start.line = new_line;
+ selection_start.pos = selection_start.pos - pos;
+ if (selection_start.Equals(selection_end))
+ selection_start.tag = new_line.FindTag(selection_start.pos);
+ else
+ selection_start.tag = new_line.FindTag (selection_start.pos + 1);
+ }
+
+ if (move_sel_end) {
+ selection_end.line = new_line;
+ selection_end.pos = selection_end.pos - pos;
+ selection_end.tag = new_line.FindTag(selection_end.pos);
+ }
+
+ CharCount -= line.text.Length - pos;
+ line.text.Remove(pos, line.text.Length - pos);
+#if DEBUG
+ SanityCheck ();
+#endif
+ }
+
+#if DEBUG
+ private void SanityCheck () {
+ for (int i = 1; i < lines; i++) {
+ LineTag tag = GetLine (i).tags;
+
+ if (tag.Start != 1)
+ throw new Exception ("Line doesn't start at the begining");
+
+ int start = 1;
+ tag = tag.Next;
+
+ while (tag != null) {
+ if (tag.Start == start)
+ throw new Exception ("Empty tag!");
+
+ if (tag.Start < start)
+ throw new Exception ("Insane!!");
+
+ start = tag.Start;
+ tag = tag.Next;
+ }
+ }
+ }
+#endif
+
+ // Adds a line of text, with given font.
+ // Bumps any line at that line number that already exists down
+ internal void Add (int LineNo, string Text, Font font, Color color, LineEnding ending)
+ {
+ Add (LineNo, Text, alignment, font, color, ending);
+ }
+
+ internal void Add (int LineNo, string Text, HorizontalAlignment align, Font font, Color color, LineEnding ending)
+ {
+ Line add;
+ Line line;
+ int line_no;
+
+ CharCount += Text.Length;
+
+ if (LineNo<1 || Text == null) {
+ if (LineNo<1) {
+ throw new ArgumentNullException("LineNo", "Line numbers must be positive");
+ } else {
+ throw new ArgumentNullException("Text", "Cannot insert NULL line");
+ }
+ }
+
+ add = new Line (this, LineNo, Text, align, font, color, ending);
+
+ line = document;
+ while (line != sentinel) {
+ add.parent = line;
+ line_no = line.line_no;
+
+ if (LineNo > line_no) {
+ line = line.right;
+ } else if (LineNo < line_no) {
+ line = line.left;
+ } else {
+ // Bump existing line numbers; walk all nodes to the right of this one and increment line_no
+ IncrementLines(line.line_no);
+ line = line.left;
+ }
+ }
+
+ add.left = sentinel;
+ add.right = sentinel;
+
+ if (add.parent != null) {
+ if (LineNo > add.parent.line_no) {
+ add.parent.right = add;
+ } else {
+ add.parent.left = add;
+ }
+ } else {
+ // Root node
+ document = add;
+ }
+
+ RebalanceAfterAdd(add);
+
+ lines++;
+ }
+
+ internal virtual void Clear() {
+ lines = 0;
+ CharCount = 0;
+ document = sentinel;
+ }
+
+ public virtual object Clone() {
+ Document clone;
+
+ clone = new Document(null);
+
+ clone.lines = this.lines;
+ clone.document = (Line)document.Clone();
+
+ return clone;
+ }
+
+ private void Delete (int LineNo)
+ {
+ Line line;
+
+ if (LineNo > lines)
+ return;
+
+ line = GetLine (LineNo);
+
+ CharCount -= line.text.Length;
+
+ DecrementLines (LineNo + 1);
+ Delete (line);
+ }
+
+ private void Delete(Line line1) {
+ Line line2;// = new Line();
+ Line line3;
+
+ if ((line1.left == sentinel) || (line1.right == sentinel)) {
+ line3 = line1;
+ } else {
+ line3 = line1.right;
+ while (line3.left != sentinel) {
+ line3 = line3.left;
+ }
+ }
+
+ if (line3.left != sentinel) {
+ line2 = line3.left;
+ } else {
+ line2 = line3.right;
+ }
+
+ line2.parent = line3.parent;
+ if (line3.parent != null) {
+ if(line3 == line3.parent.left) {
+ line3.parent.left = line2;
+ } else {
+ line3.parent.right = line2;
+ }
+ } else {
+ document = line2;
+ }
+
+ if (line3 != line1) {
+ LineTag tag;
+
+ if (selection_start.line == line3) {
+ selection_start.line = line1;
+ }
+
+ if (selection_end.line == line3) {
+ selection_end.line = line1;
+ }
+
+ if (selection_anchor.line == line3) {
+ selection_anchor.line = line1;
+ }
+
+ if (caret.line == line3) {
+ caret.line = line1;
+ }
+
+
+ line1.alignment = line3.alignment;
+ line1.ascent = line3.ascent;
+ line1.hanging_indent = line3.hanging_indent;
+ line1.height = line3.height;
+ line1.indent = line3.indent;
+ line1.line_no = line3.line_no;
+ line1.recalc = line3.recalc;
+ line1.right_indent = line3.right_indent;
+ line1.ending = line3.ending;
+ line1.space = line3.space;
+ line1.tags = line3.tags;
+ line1.text = line3.text;
+ line1.widths = line3.widths;
+ line1.offset = line3.offset;
+
+ tag = line1.tags;
+ while (tag != null) {
+ tag.Line = line1;
+ tag = tag.Next;
+ }
+ }
+
+ if (line3.color == LineColor.Black)
+ RebalanceAfterDelete(line2);
+
+ this.lines--;
+ }
+
+ // Invalidates the start line until the end of the viewstate
+ internal void InvalidateLinesAfter (Line start) {
+ owner.Invalidate (new Rectangle (0, start.Y - viewport_y, viewport_width, viewport_height - start.Y));
+ }
+
+ // Invalidate a section of the document to trigger redraw
+ internal void Invalidate(Line start, int start_pos, Line end, int end_pos) {
+ Line l1;
+ Line l2;
+ int p1;
+ int p2;
+
+ if ((start == end) && (start_pos == end_pos)) {
+ return;
+ }
+
+ if (end_pos == -1) {
+ end_pos = end.text.Length;
+ }
+
+ // figure out what's before what so the logic below is straightforward
+ if (start.line_no < end.line_no) {
+ l1 = start;
+ p1 = start_pos;
+
+ l2 = end;
+ p2 = end_pos;
+ } else if (start.line_no > end.line_no) {
+ l1 = end;
+ p1 = end_pos;
+
+ l2 = start;
+ p2 = start_pos;
+ } else {
+ if (start_pos < end_pos) {
+ l1 = start;
+ p1 = start_pos;
+
+ l2 = end;
+ p2 = end_pos;
+ } else {
+ l1 = end;
+ p1 = end_pos;
+
+ l2 = start;
+ p2 = start_pos;
+ }
+
+ int endpoint = (int) l1.widths [p2];
+ if (p2 == l1.text.Length + 1) {
+ endpoint = (int) viewport_width;
+ }
+
+ #if Debug
+ Console.WriteLine("Invaliding backwards from {0}:{1} to {2}:{3} {4}",
+ l1.line_no, p1, l2.line_no, p2,
+ new Rectangle(
+ (int)l1.widths[p1] + l1.X - viewport_x,
+ l1.Y - viewport_y,
+ (int)l1.widths[p2],
+ l1.height
+ )
+ );
+ #endif
+
+ owner.Invalidate(new Rectangle (
+ offset_x + (int)l1.widths[p1] + l1.X - viewport_x,
+ offset_y + l1.Y - viewport_y,
+ endpoint - (int) l1.widths [p1] + 1,
+ l1.height));
+ return;
+ }
+
+ #if Debug
+ Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} Start => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, (int)l1.widths[p1] + l1.X - viewport_x, l1.Y - viewport_y, viewport_width, l1.height);
+ Console.WriteLine ("invalidate start line: {0} position: {1}", l1.text, p1);
+ #endif
+
+ // Three invalidates:
+ // First line from start
+ owner.Invalidate(new Rectangle(
+ offset_x + (int)l1.widths[p1] + l1.X - viewport_x,
+ offset_y + l1.Y - viewport_y,
+ viewport_width,
+ l1.height));
+
+
+ // lines inbetween
+ if ((l1.line_no + 1) < l2.line_no) {
+ int y;
+
+ y = GetLine(l1.line_no + 1).Y;
+ owner.Invalidate(new Rectangle(
+ offset_x,
+ offset_y + y - viewport_y,
+ viewport_width,
+ l2.Y - y));
+
+ #if Debug
+ Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} Middle => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, 0, y - viewport_y, viewport_width, l2.Y - y);
+ #endif
+ }
+
+
+ // Last line to end
+ owner.Invalidate(new Rectangle(
+ offset_x + (int)l2.widths[0] + l2.X - viewport_x,
+ offset_y + l2.Y - viewport_y,
+ (int)l2.widths[p2] + 1,
+ l2.height));
+
+ #if Debug
+ Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} End => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, (int)l2.widths[0] + l2.X - viewport_x, l2.Y - viewport_y, (int)l2.widths[p2] + 1, l2.height);
+ #endif
+ }
+
+ /// <summary>Select text around caret</summary>
+ internal void ExpandSelection(CaretSelection mode, bool to_caret) {
+ if (to_caret) {
+ // We're expanding the selection to the caret position
+ switch(mode) {
+ case CaretSelection.Line: {
+ // Invalidate the selection delta
+ if (caret > selection_prev) {
+ Invalidate(selection_prev.line, 0, caret.line, caret.line.text.Length);
+ } else {
+ Invalidate(selection_prev.line, selection_prev.line.text.Length, caret.line, 0);
+ }
+
+ if (caret.line.line_no <= selection_anchor.line.line_no) {
+ selection_start.line = caret.line;
+ selection_start.tag = caret.line.tags;
+ selection_start.pos = 0;
+
+ selection_end.line = selection_anchor.line;
+ selection_end.tag = selection_anchor.tag;
+ selection_end.pos = selection_anchor.pos;
+
+ selection_end_anchor = true;
+ } else {
+ selection_start.line = selection_anchor.line;
+ selection_start.pos = selection_anchor.height;
+ selection_start.tag = selection_anchor.line.FindTag(selection_anchor.height + 1);
+
+ selection_end.line = caret.line;
+ selection_end.tag = caret.line.tags;
+ selection_end.pos = caret.line.text.Length;
+
+ selection_end_anchor = false;
+ }
+ selection_prev.line = caret.line;
+ selection_prev.tag = caret.tag;
+ selection_prev.pos = caret.pos;
+
+ break;
+ }
+
+ case CaretSelection.Word: {
+ int start_pos;
+ int end_pos;
+
+ start_pos = FindWordSeparator(caret.line, caret.pos, false);
+ end_pos = FindWordSeparator(caret.line, caret.pos, true);
+
+
+ // Invalidate the selection delta
+ if (caret > selection_prev) {
+ Invalidate(selection_prev.line, selection_prev.pos, caret.line, end_pos);
+ } else {
+ Invalidate(selection_prev.line, selection_prev.pos, caret.line, start_pos);
+ }
+ if (caret < selection_anchor) {
+ selection_start.line = caret.line;
+ selection_start.tag = caret.line.FindTag(start_pos + 1);
+ selection_start.pos = start_pos;
+
+ selection_end.line = selection_anchor.line;
+ selection_end.tag = selection_anchor.tag;
+ selection_end.pos = selection_anchor.pos;
+
+ selection_prev.line = caret.line;
+ selection_prev.tag = caret.tag;
+ selection_prev.pos = start_pos;
+
+ selection_end_anchor = true;
+ } else {
+ selection_start.line = selection_anchor.line;
+ selection_start.pos = selection_anchor.height;
+ selection_start.tag = selection_anchor.line.FindTag(selection_anchor.height + 1);
+
+ selection_end.line = caret.line;
+ selection_end.tag = caret.line.FindTag(end_pos);
+ selection_end.pos = end_pos;
+
+ selection_prev.line = caret.line;
+ selection_prev.tag = caret.tag;
+ selection_prev.pos = end_pos;
+
+ selection_end_anchor = false;
+ }
+ break;
+ }
+
+ case CaretSelection.Position: {
+ SetSelectionToCaret(false);
+ return;
+ }
+ }
+ } else {
+ // We're setting the selection 'around' the caret position
+ switch(mode) {
+ case CaretSelection.Line: {
+ this.Invalidate(caret.line, 0, caret.line, caret.line.text.Length);
+
+ selection_start.line = caret.line;
+ selection_start.tag = caret.line.tags;
+ selection_start.pos = 0;
+
+ selection_end.line = caret.line;
+ selection_end.pos = caret.line.text.Length;
+ selection_end.tag = caret.line.FindTag(selection_end.pos);
+
+ selection_anchor.line = selection_end.line;
+ selection_anchor.tag = selection_end.tag;
+ selection_anchor.pos = selection_end.pos;
+ selection_anchor.height = 0;
+
+ selection_prev.line = caret.line;
+ selection_prev.tag = caret.tag;
+ selection_prev.pos = caret.pos;
+
+ this.selection_end_anchor = true;
+
+ break;
+ }
+
+ case CaretSelection.Word: {
+ int start_pos;
+ int end_pos;
+
+ start_pos = FindWordSeparator(caret.line, caret.pos, false);
+ end_pos = FindWordSeparator(caret.line, caret.pos, true);
+
+ this.Invalidate(selection_start.line, start_pos, caret.line, end_pos);
+
+ selection_start.line = caret.line;
+ selection_start.tag = caret.line.FindTag(start_pos + 1);
+ selection_start.pos = start_pos;
+
+ selection_end.line = caret.line;
+ selection_end.tag = caret.line.FindTag(end_pos);
+ selection_end.pos = end_pos;
+
+ selection_anchor.line = selection_end.line;
+ selection_anchor.tag = selection_end.tag;
+ selection_anchor.pos = selection_end.pos;
+ selection_anchor.height = start_pos;
+
+ selection_prev.line = caret.line;
+ selection_prev.tag = caret.tag;
+ selection_prev.pos = caret.pos;
+
+ this.selection_end_anchor = true;
+
+ break;
+ }
+ }
+ }
+
+ SetSelectionVisible (!(selection_start == selection_end));
+ }
+
+ internal void SetSelectionToCaret(bool start) {
+ if (start) {
+ // Invalidate old selection; selection is being reset to empty
+ this.Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+
+ selection_start.line = caret.line;
+ selection_start.tag = caret.tag;
+ selection_start.pos = caret.pos;
+
+ // start always also selects end
+ selection_end.line = caret.line;
+ selection_end.tag = caret.tag;
+ selection_end.pos = caret.pos;
+
+ selection_anchor.line = caret.line;
+ selection_anchor.tag = caret.tag;
+ selection_anchor.pos = caret.pos;
+ } else {
+ // Invalidate from previous end to caret (aka new end)
+ if (selection_end_anchor) {
+ if (selection_start != caret) {
+ this.Invalidate(selection_start.line, selection_start.pos, caret.line, caret.pos);
+ }
+ } else {
+ if (selection_end != caret) {
+ this.Invalidate(selection_end.line, selection_end.pos, caret.line, caret.pos);
+ }
+ }
+
+ if (caret < selection_anchor) {
+ selection_start.line = caret.line;
+ selection_start.tag = caret.tag;
+ selection_start.pos = caret.pos;
+
+ selection_end.line = selection_anchor.line;
+ selection_end.tag = selection_anchor.tag;
+ selection_end.pos = selection_anchor.pos;
+
+ selection_end_anchor = true;
+ } else {
+ selection_start.line = selection_anchor.line;
+ selection_start.tag = selection_anchor.tag;
+ selection_start.pos = selection_anchor.pos;
+
+ selection_end.line = caret.line;
+ selection_end.tag = caret.tag;
+ selection_end.pos = caret.pos;
+
+ selection_end_anchor = false;
+ }
+ }
+
+ SetSelectionVisible (!(selection_start == selection_end));
+ }
+
+ internal void SetSelection(Line start, int start_pos, Line end, int end_pos) {
+ if (selection_visible) {
+ Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+ }
+
+ if ((end.line_no < start.line_no) || ((end == start) && (end_pos <= start_pos))) {
+ selection_start.line = end;
+ selection_start.tag = LineTag.FindTag(end, end_pos);
+ selection_start.pos = end_pos;
+
+ selection_end.line = start;
+ selection_end.tag = LineTag.FindTag(start, start_pos);
+ selection_end.pos = start_pos;
+
+ selection_end_anchor = true;
+ } else {
+ selection_start.line = start;
+ selection_start.tag = LineTag.FindTag(start, start_pos);
+ selection_start.pos = start_pos;
+
+ selection_end.line = end;
+ selection_end.tag = LineTag.FindTag(end, end_pos);
+ selection_end.pos = end_pos;
+
+ selection_end_anchor = false;
+ }
+
+ selection_anchor.line = start;
+ selection_anchor.tag = selection_start.tag;
+ selection_anchor.pos = start_pos;
+
+ if (((start == end) && (start_pos == end_pos)) || start == null || end == null) {
+ SetSelectionVisible (false);
+ } else {
+ SetSelectionVisible (true);
+ Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+ }
+ }
+
+ internal void SetSelectionStart(Line start, int start_pos, bool invalidate) {
+ // Invalidate from the previous to the new start pos
+ if (invalidate)
+ Invalidate(selection_start.line, selection_start.pos, start, start_pos);
+
+ selection_start.line = start;
+ selection_start.pos = start_pos;
+ selection_start.tag = LineTag.FindTag(start, start_pos);
+
+ selection_anchor.line = start;
+ selection_anchor.pos = start_pos;
+ selection_anchor.tag = selection_start.tag;
+
+ selection_end_anchor = false;
+
+
+ if ((selection_end.line != selection_start.line) || (selection_end.pos != selection_start.pos)) {
+ SetSelectionVisible (true);
+ } else {
+ SetSelectionVisible (false);
+ }
+
+ if (invalidate)
+ Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+ }
+
+ internal void SetSelectionStart(int character_index, bool invalidate) {
+ Line line;
+ LineTag tag;
+ int pos;
+
+ if (character_index < 0) {
+ return;
+ }
+
+ CharIndexToLineTag(character_index, out line, out tag, out pos);
+ SetSelectionStart(line, pos, invalidate);
+ }
+
+ internal void SetSelectionEnd(Line end, int end_pos, bool invalidate) {
+
+ if (end == selection_end.line && end_pos == selection_start.pos) {
+ selection_anchor.line = selection_start.line;
+ selection_anchor.tag = selection_start.tag;
+ selection_anchor.pos = selection_start.pos;
+
+ selection_end.line = selection_start.line;
+ selection_end.tag = selection_start.tag;
+ selection_end.pos = selection_start.pos;
+
+ selection_end_anchor = false;
+ } else if ((end.line_no < selection_anchor.line.line_no) || ((end == selection_anchor.line) && (end_pos <= selection_anchor.pos))) {
+ selection_start.line = end;
+ selection_start.tag = LineTag.FindTag(end, end_pos);
+ selection_start.pos = end_pos;
+
+ selection_end.line = selection_anchor.line;
+ selection_end.tag = selection_anchor.tag;
+ selection_end.pos = selection_anchor.pos;
+
+ selection_end_anchor = true;
+ } else {
+ selection_start.line = selection_anchor.line;
+ selection_start.tag = selection_anchor.tag;
+ selection_start.pos = selection_anchor.pos;
+
+ selection_end.line = end;
+ selection_end.tag = LineTag.FindTag(end, end_pos);
+ selection_end.pos = end_pos;
+
+ selection_end_anchor = false;
+ }
+
+ if ((selection_end.line != selection_start.line) || (selection_end.pos != selection_start.pos)) {
+ SetSelectionVisible (true);
+ if (invalidate)
+ Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+ } else {
+ SetSelectionVisible (false);
+ // ?? Do I need to invalidate here, tests seem to work without it, but I don't think they should :-s
+ }
+ }
+
+ internal void SetSelectionEnd(int character_index, bool invalidate) {
+ Line line;
+ LineTag tag;
+ int pos;
+
+ if (character_index < 0) {
+ return;
+ }
+
+ CharIndexToLineTag(character_index, out line, out tag, out pos);
+ SetSelectionEnd(line, pos, invalidate);
+ }
+
+ internal void SetSelection(Line start, int start_pos) {
+ if (selection_visible) {
+ Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+ }
+
+ selection_start.line = start;
+ selection_start.pos = start_pos;
+ selection_start.tag = LineTag.FindTag(start, start_pos);
+
+ selection_end.line = start;
+ selection_end.tag = selection_start.tag;
+ selection_end.pos = start_pos;
+
+ selection_anchor.line = start;
+ selection_anchor.tag = selection_start.tag;
+ selection_anchor.pos = start_pos;
+
+ selection_end_anchor = false;
+ SetSelectionVisible (false);
+ }
+
+ internal void InvalidateSelectionArea() {
+ Invalidate (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+ }
+
+ // Return the current selection, as string
+ internal string GetSelection() {
+ // We return String.Empty if there is no selection
+ if ((selection_start.pos == selection_end.pos) && (selection_start.line == selection_end.line)) {
+ return string.Empty;
+ }
+
+ if (selection_start.line == selection_end.line) {
+ return selection_start.line.text.ToString (selection_start.pos, selection_end.pos - selection_start.pos);
+ } else {
+ StringBuilder sb;
+ int i;
+ int start;
+ int end;
+
+ sb = new StringBuilder();
+ start = selection_start.line.line_no;
+ end = selection_end.line.line_no;
+
+ sb.Append(selection_start.line.text.ToString(selection_start.pos, selection_start.line.text.Length - selection_start.pos));
+
+ if ((start + 1) < end) {
+ for (i = start + 1; i < end; i++) {
+ sb.Append(GetLine(i).text.ToString());
+ }
+ }
+
+ sb.Append(selection_end.line.text.ToString(0, selection_end.pos));
+
+ return sb.ToString();
+ }
+ }
+
+ internal void ReplaceSelection(string s, bool select_new) {
+ int i;
+
+ int selection_start_pos = LineTagToCharIndex (selection_start.line, selection_start.pos);
+ SuspendRecalc ();
+
+ // First, delete any selected text
+ if ((selection_start.pos != selection_end.pos) || (selection_start.line != selection_end.line)) {
+ if (selection_start.line == selection_end.line) {
+ undo.RecordDeleteString (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+
+ DeleteChars (selection_start.line, selection_start.pos, selection_end.pos - selection_start.pos);
+
+ // The tag might have been removed, we need to recalc it
+ selection_start.tag = selection_start.line.FindTag(selection_start.pos + 1);
+ } else {
+ int start;
+ int end;
+
+ start = selection_start.line.line_no;
+ end = selection_end.line.line_no;
+
+ undo.RecordDeleteString (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+
+ InvalidateLinesAfter(selection_start.line);
+
+ // Delete first line
+ DeleteChars (selection_start.line, selection_start.pos, selection_start.line.text.Length - selection_start.pos);
+ selection_start.line.recalc = true;
+
+ // Delete last line
+ DeleteChars(selection_end.line, 0, selection_end.pos);
+
+ start++;
+ if (start < end) {
+ for (i = end - 1; i >= start; i--) {
+ Delete(i);
+ }
+ }
+
+ // BIG FAT WARNING - selection_end.line might be stale due
+ // to the above Delete() call. DONT USE IT before hitting the end of this method!
+
+ // Join start and end
+ Combine(selection_start.line.line_no, start);
+ }
+ }
+
+
+ Insert(selection_start.line, selection_start.pos, false, s);
+ undo.RecordInsertString (selection_start.line, selection_start.pos, s);
+ ResumeRecalc (false);
+
+ Line begin_update_line = selection_start.line;
+ int begin_update_pos = selection_start.pos;
+
+ if (!select_new) {
+ CharIndexToLineTag(selection_start_pos + s.Length, out selection_start.line,
+ out selection_start.tag, out selection_start.pos);
+
+ selection_end.line = selection_start.line;
+ selection_end.pos = selection_start.pos;
+ selection_end.tag = selection_start.tag;
+ selection_anchor.line = selection_start.line;
+ selection_anchor.pos = selection_start.pos;
+ selection_anchor.tag = selection_start.tag;
+
+ SetSelectionVisible (false);
+ } else {
+ CharIndexToLineTag(selection_start_pos, out selection_start.line,
+ out selection_start.tag, out selection_start.pos);
+
+ CharIndexToLineTag(selection_start_pos + s.Length, out selection_end.line,
+ out selection_end.tag, out selection_end.pos);
+
+ selection_anchor.line = selection_start.line;
+ selection_anchor.pos = selection_start.pos;
+ selection_anchor.tag = selection_start.tag;
+
+ SetSelectionVisible (true);
+ }
+
+ PositionCaret (selection_start.line, selection_start.pos);
+ UpdateView (begin_update_line, selection_end.line.line_no - begin_update_line.line_no, begin_update_pos);
+ }
+
+ internal void CharIndexToLineTag(int index, out Line line_out, out LineTag tag_out, out int pos) {
+ Line line;
+ LineTag tag;
+ int i;
+ int chars;
+ int start;
+
+ chars = 0;
+
+ for (i = 1; i <= lines; i++) {
+ line = GetLine(i);
+
+ start = chars;
+ chars += line.text.Length;
+
+ if (index <= chars) {
+ // we found the line
+ tag = line.tags;
+
+ while (tag != null) {
+ if (index < (start + tag.Start + tag.Length - 1)) {
+ line_out = line;
+ tag_out = LineTag.GetFinalTag (tag);
+ pos = index - start;
+ return;
+ }
+ if (tag.Next == null) {
+ Line next_line;
+
+ next_line = GetLine(line.line_no + 1);
+
+ if (next_line != null) {
+ line_out = next_line;
+ tag_out = LineTag.GetFinalTag (next_line.tags);
+ pos = 0;
+ return;
+ } else {
+ line_out = line;
+ tag_out = LineTag.GetFinalTag (tag);
+ pos = line_out.text.Length;
+ return;
+ }
+ }
+ tag = tag.Next;
+ }
+ }
+ }
+
+ line_out = GetLine(lines);
+ tag = line_out.tags;
+ while (tag.Next != null) {
+ tag = tag.Next;
+ }
+ tag_out = tag;
+ pos = line_out.text.Length;
+ }
+
+ internal int LineTagToCharIndex(Line line, int pos) {
+ int i;
+ int length;
+
+ // Count first and last line
+ length = 0;
+
+ // Count the lines in the middle
+
+ for (i = 1; i < line.line_no; i++) {
+ length += GetLine(i).text.Length;
+ }
+
+ length += pos;
+
+ return length;
+ }
+
+ internal int SelectionLength() {
+ if ((selection_start.pos == selection_end.pos) && (selection_start.line == selection_end.line)) {
+ return 0;
+ }
+
+ if (selection_start.line == selection_end.line) {
+ return selection_end.pos - selection_start.pos;
+ } else {
+ int i;
+ int start;
+ int end;
+ int length;
+
+ // Count first and last line
+ length = selection_start.line.text.Length - selection_start.pos + selection_end.pos + crlf_size;
+
+ // Count the lines in the middle
+ start = selection_start.line.line_no + 1;
+ end = selection_end.line.line_no;
+
+ if (start < end) {
+ for (i = start; i < end; i++) {
+ Line line = GetLine (i);
+ length += line.text.Length + LineEndingLength (line.ending);
+ }
+ }
+
+ return length;
+ }
+
+
+ }
+
+
+ // UIA: Method used via reflection in TextRangeProvider
+
+ /// <summary>Give it a Line number and it returns the Line object at with that line number</summary>
+ internal Line GetLine(int LineNo) {
+ Line line = document;
+
+ while (line != sentinel) {
+ if (LineNo == line.line_no) {
+ return line;
+ } else if (LineNo < line.line_no) {
+ line = line.left;
+ } else {
+ line = line.right;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>Retrieve the previous tag; walks line boundaries</summary>
+ internal LineTag PreviousTag(LineTag tag) {
+ Line l;
+
+ if (tag.Previous != null) {
+ return tag.Previous;
+ }
+
+ // Next line
+ if (tag.Line.line_no == 1) {
+ return null;
+ }
+
+ l = GetLine(tag.Line.line_no - 1);
+ if (l != null) {
+ LineTag t;
+
+ t = l.tags;
+ while (t.Next != null) {
+ t = t.Next;
+ }
+ return t;
+ }
+
+ return null;
+ }
+
+ /// <summary>Retrieve the next tag; walks line boundaries</summary>
+ internal LineTag NextTag(LineTag tag) {
+ Line l;
+
+ if (tag.Next != null) {
+ return tag.Next;
+ }
+
+ // Next line
+ l = GetLine(tag.Line.line_no + 1);
+ if (l != null) {
+ return l.tags;
+ }
+
+ return null;
+ }
+
+ internal Line ParagraphStart(Line line) {
+ Line lastline = line;
+ do {
+ if (line.line_no <= 1)
+ break;
+
+ line = lastline;
+ lastline = GetLine (line.line_no - 1);
+ } while (lastline.ending == LineEnding.Wrap);
+
+ return line;
+ }
+
+ internal Line ParagraphEnd(Line line) {
+ Line l;
+
+ while (line.ending == LineEnding.Wrap) {
+ l = GetLine(line.line_no + 1);
+ if ((l == null) || (l.ending != LineEnding.Wrap)) {
+ break;
+ }
+ line = l;
+ }
+ return line;
+ }
+
+ /// <summary>Give it a pixel offset coordinate and it returns the Line covering that are (offset
+ /// is either X or Y depending on if we are multiline
+ /// </summary>
+ internal Line GetLineByPixel (int offset, bool exact)
+ {
+ Line line = document;
+ Line last = null;
+
+ if (multiline) {
+ while (line != sentinel) {
+ last = line;
+ if ((offset >= line.Y) && (offset < (line.Y+line.height))) {
+ return line;
+ } else if (offset < line.Y) {
+ line = line.left;
+ } else {
+ line = line.right;
+ }
+ }
+ } else {
+ while (line != sentinel) {
+ last = line;
+ if ((offset >= line.X) && (offset < (line.X + line.Width)))
+ return line;
+ else if (offset < line.X)
+ line = line.left;
+ else
+ line = line.right;
+ }
+ }
+
+ if (exact) {
+ return null;
+ }
+ return last;
+ }
+
+ // UIA: Method used via reflection in TextProviderBehavior
+
+ // Give it x/y pixel coordinates and it returns the Tag at that position
+ internal LineTag FindCursor (int x, int y, out int index)
+ {
+ Line line;
+
+ x -= offset_x;
+ y -= offset_y;
+
+ line = GetLineByPixel (multiline ? y : x, false);
+
+ LineTag tag = line.GetTag (x);
+
+ if (tag.Length == 0 && tag.Start == 1)
+ index = 0;
+ else
+ index = tag.GetCharIndex (x - line.align_shift);
+
+ return tag;
+ }
+
+ /// <summary>Format area of document in specified font and color</summary>
+ /// <param name="start_pos">1-based start position on start_line</param>
+ /// <param name="end_pos">1-based end position on end_line </param>
+ internal void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, Font font,
+ Color color, Color back_color, FormatSpecified specified)
+ {
+ Line l;
+
+ // First, format the first line
+ if (start_line != end_line) {
+ // First line
+ LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, font, color, back_color, specified);
+
+ // Format last line
+ LineTag.FormatText(end_line, 1, end_pos, font, color, back_color, specified);
+
+ // Now all the lines inbetween
+ for (int i = start_line.line_no + 1; i < end_line.line_no; i++) {
+ l = GetLine(i);
+ LineTag.FormatText(l, 1, l.text.Length, font, color, back_color, specified);
+ }
+ } else {
+ // Special case, single line
+ LineTag.FormatText(start_line, start_pos, end_pos - start_pos, font, color, back_color, specified);
+
+ if ((end_pos - start_pos) == 0 && CaretTag.Length != 0)
+ CaretTag = CaretTag.Next;
+ }
+ }
+
+ internal void RecalculateAlignments ()
+ {
+ Line line;
+ int line_no;
+
+ line_no = 1;
+
+
+
+ while (line_no <= lines) {
+ line = GetLine(line_no);
+
+ if (line != null) {
+ switch (line.alignment) {
+ case HorizontalAlignment.Left:
+ line.align_shift = 0;
+ break;
+ case HorizontalAlignment.Center:
+ line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2;
+ break;
+ case HorizontalAlignment.Right:
+ line.align_shift = viewport_width - (int)line.widths[line.text.Length] - right_margin;
+ break;
+ }
+ }
+
+ line_no++;
+ }
+ return;
+ }
+
+ /// <summary>Calculate formatting for the whole document</summary>
+ internal bool RecalculateDocument(Graphics g) {
+ return RecalculateDocument(g, 1, this.lines, false);
+ }
+
+ /// <summary>Calculate formatting starting at a certain line</summary>
+ internal bool RecalculateDocument(Graphics g, int start) {
+ return RecalculateDocument(g, start, this.lines, false);
+ }
+
+ /// <summary>Calculate formatting within two given line numbers</summary>
+ internal bool RecalculateDocument(Graphics g, int start, int end) {
+ return RecalculateDocument(g, start, end, false);
+ }
+
+ /// <summary>With optimize on, returns true if line heights changed</summary>
+ internal bool RecalculateDocument(Graphics g, int start, int end, bool optimize) {
+ Line line;
+ int line_no;
+ int offset;
+ int new_width;
+ bool changed;
+ int shift;
+
+ if (recalc_suspended > 0) {
+ recalc_pending = true;
+ recalc_start = Math.Min (recalc_start, start);
+ recalc_end = Math.Max (recalc_end, end);
+ recalc_optimize = optimize;
+ return false;
+ }
+
+ // Fixup the positions, they can go kinda nuts
+ // (this is suspend and resume recalc - they set them to 1 and max)
+ start = Math.Max (start, 1);
+ end = Math.Min (end, lines);
+
+ offset = GetLine(start).offset;
+ line_no = start;
+ new_width = 0;
+ shift = this.lines;
+ if (!optimize) {
+ changed = true; // We always return true if we run non-optimized
+ } else {
+ changed = false;
+ }
+
+ while (line_no <= (end + this.lines - shift)) {
+ line = GetLine(line_no++);
+ line.offset = offset;
+
+ // if we are not calculating a password
+ if (!calc_pass) {
+ if (!optimize) {
+ line.RecalculateLine(g, this);
+ } else {
+ if (line.recalc && line.RecalculateLine(g, this)) {
+ changed = true;
+ // If the height changed, all subsequent lines change
+ end = this.lines;
+ shift = this.lines;
+ }
+ }
+ } else {
+ if (!optimize) {
+ line.RecalculatePasswordLine(g, this);
+ } else {
+ if (line.recalc && line.RecalculatePasswordLine(g, this)) {
+ changed = true;
+ // If the height changed, all subsequent lines change
+ end = this.lines;
+ shift = this.lines;
+ }
+ }
+ }
+
+ if (line.widths[line.text.Length] > new_width) {
+ new_width = (int)line.widths[line.text.Length];
+ }
+
+ // Calculate alignment
+ if (line.alignment != HorizontalAlignment.Left) {
+ if (line.alignment == HorizontalAlignment.Center) {
+ line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2;
+ } else {
+ line.align_shift = viewport_width - (int)line.widths[line.text.Length] - 1;
+ }
+ }
+
+ if (multiline)
+ offset += line.height;
+ else
+ offset += (int) line.widths [line.text.Length];
+
+ if (line_no > lines) {
+ break;
+ }
+ }
+
+ if (document_x != new_width) {
+ document_x = new_width;
+ if (WidthChanged != null) {
+ WidthChanged(this, null);
+ }
+ }
+
+ RecalculateAlignments();
+
+ line = GetLine(lines);
+
+ if (document_y != line.Y + line.height) {
+ document_y = line.Y + line.height;
+ if (HeightChanged != null) {
+ HeightChanged(this, null);
+ }
+ }
+
+ // scan for links and tell us if its all
+ // changed, so we can update everything
+ if (EnableLinks)
+ ScanForLinks (start, end, ref changed);
+
+ UpdateCaret();
+ return changed;
+ }
+
+ internal int Size() {
+ return lines;
+ }
+
+ private void owner_HandleCreated(object sender, EventArgs e) {
+ RecalculateDocument(owner.CreateGraphicsInternal());
+ AlignCaret();
+ }
+
+ private void owner_VisibleChanged(object sender, EventArgs e) {
+ if (owner.Visible) {
+ RecalculateDocument(owner.CreateGraphicsInternal());
+ }
+ }
+
+ internal static bool IsWordSeparator (char ch)
+ {
+ switch (ch) {
+ case ' ':
+ case '\t':
+ case '(':
+ case ')':
+ case '\r':
+ case '\n':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ internal int FindWordSeparator(Line line, int pos, bool forward) {
+ int len;
+
+ len = line.text.Length;
+
+ if (forward) {
+ for (int i = pos + 1; i < len; i++) {
+ if (IsWordSeparator(line.Text[i])) {
+ return i + 1;
+ }
+ }
+ return len;
+ } else {
+ for (int i = pos - 1; i > 0; i--) {
+ if (IsWordSeparator(line.Text[i - 1])) {
+ return i;
+ }
+ }
+ return 0;
+ }
+ }
+
+ /* Search document for text */
+ internal bool FindChars(char[] chars, Marker start, Marker end, out Marker result) {
+ Line line;
+ int line_no;
+ int pos;
+ int line_len;
+
+ // Search for occurence of any char in the chars array
+ result = new Marker();
+
+ line = start.line;
+ line_no = start.line.line_no;
+ pos = start.pos;
+ while (line_no <= end.line.line_no) {
+ line_len = line.text.Length;
+ while (pos < line_len) {
+ for (int i = 0; i < chars.Length; i++) {
+ if (line.text[pos] == chars[i]) {
+ // Special case
+ if ((line.line_no == end.line.line_no) && (pos >= end.pos)) {
+ return false;
+ }
+
+ result.line = line;
+ result.pos = pos;
+ return true;
+ }
+ }
+ pos++;
+ }
+
+ pos = 0;
+ line_no++;
+ line = GetLine(line_no);
+ }
+
+ return false;
+ }
+
+ // This version does not build one big string for searching, instead it handles
+ // line-boundaries, which is faster and less memory intensive
+ // FIXME - Depending on culture stuff we might have to create a big string and use culturespecific
+ // search stuff and change it to accept and return positions instead of Markers (which would match
+ // RichTextBox behaviour better but would be inconsistent with the rest of TextControl)
+ internal bool Find(string search, Marker start, Marker end, out Marker result, RichTextBoxFinds options) {
+ Marker last;
+ string search_string;
+ Line line;
+ int line_no;
+ int pos;
+ int line_len;
+ int current;
+ bool word;
+ bool word_option;
+ bool ignore_case;
+ bool reverse;
+ char c;
+
+ result = new Marker();
+ word_option = ((options & RichTextBoxFinds.WholeWord) != 0);
+ ignore_case = ((options & RichTextBoxFinds.MatchCase) == 0);
+ reverse = ((options & RichTextBoxFinds.Reverse) != 0);
+
+ line = start.line;
+ line_no = start.line.line_no;
+ pos = start.pos;
+ current = 0;
+
+ // Prep our search string, lowercasing it if we do case-independent matching
+ if (ignore_case) {
+ StringBuilder sb;
+ sb = new StringBuilder(search);
+ for (int i = 0; i < sb.Length; i++) {
+ sb[i] = Char.ToLower(sb[i]);
+ }
+ search_string = sb.ToString();
+ } else {
+ search_string = search;
+ }
+
+ // We need to check if the character before our start position is a wordbreak
+ if (word_option) {
+ if (line_no == 1) {
+ if ((pos == 0) || (IsWordSeparator(line.text[pos - 1]))) {
+ word = true;
+ } else {
+ word = false;
+ }
+ } else {
+ if (pos > 0) {
+ if (IsWordSeparator(line.text[pos - 1])) {
+ word = true;
+ } else {
+ word = false;
+ }
+ } else {
+ // Need to check the end of the previous line
+ Line prev_line;
+
+ prev_line = GetLine(line_no - 1);
+ if (prev_line.ending == LineEnding.Wrap) {
+ if (IsWordSeparator(prev_line.text[prev_line.text.Length - 1])) {
+ word = true;
+ } else {
+ word = false;
+ }
+ } else {
+ word = true;
+ }
+ }
+ }
+ } else {
+ word = false;
+ }
+
+ // To avoid duplication of this loop with reverse logic, we search
+ // through the document, remembering the last match and when returning
+ // report that last remembered match
+
+ last = new Marker();
+ last.height = -1; // Abused - we use it to track change
+
+ while (line_no <= end.line.line_no) {
+ if (line_no != end.line.line_no) {
+ line_len = line.text.Length;
+ } else {
+ line_len = end.pos;
+ }
+
+ while (pos < line_len) {
+
+ if (word_option && (current == search_string.Length)) {
+ if (IsWordSeparator(line.text[pos])) {
+ if (!reverse) {
+ goto FindFound;
+ } else {
+ last = result;
+ current = 0;
+ }
+ } else {
+ current = 0;
+ }
+ }
+
+ if (ignore_case) {
+ c = Char.ToLower(line.text[pos]);
+ } else {
+ c = line.text[pos];
+ }
+
+ if (c == search_string[current]) {
+
+ if (current == 0) {
+ result.line = line;
+ result.pos = pos;
+ }
+ if (!word_option || (word_option && (word || (current > 0)))) {
+ current++;
+ }
+
+ if (!word_option && (current == search_string.Length)) {
+ if (!reverse) {
+ goto FindFound;
+ } else {
+ last = result;
+ current = 0;
+ }
+ }
+ } else {
+ current = 0;
+ }
+ pos++;
+
+ if (!word_option) {
+ continue;
+ }
+
+ if (IsWordSeparator(c)) {
+ word = true;
+ } else {
+ word = false;
+ }
+ }
+
+ if (word_option) {
+ // Mark that we just saw a word boundary
+ if (line.ending != LineEnding.Wrap || line.line_no == lines - 1) {
+ word = true;
+ }
+
+ if (current == search_string.Length) {
+ if (word) {
+ if (!reverse) {
+ goto FindFound;
+ } else {
+ last = result;
+ current = 0;
+ }
+ } else {
+ current = 0;
+ }
+ }
+ }
+
+ pos = 0;
+ line_no++;
+ line = GetLine(line_no);
+ }
+
+ if (reverse) {
+ if (last.height != -1) {
+ result = last;
+ return true;
+ }
+ }
+
+ return false;
+
+ FindFound:
+ if (!reverse) {
+// if ((line.line_no == end.line.line_no) && (pos >= end.pos)) {
+// return false;
+// }
+ return true;
+ }
+
+ result = last;
+ return true;
+
+ }
+
+ /* Marker stuff */
+ internal void GetMarker(out Marker mark, bool start) {
+ mark = new Marker();
+
+ if (start) {
+ mark.line = GetLine(1);
+ mark.tag = mark.line.tags;
+ mark.pos = 0;
+ } else {
+ mark.line = GetLine(lines);
+ mark.tag = mark.line.tags;
+ while (mark.tag.Next != null) {
+ mark.tag = mark.tag.Next;
+ }
+ mark.pos = mark.line.text.Length;
+ }
+ }
+ #endregion // Internal Methods
+
+ #region Events
+ internal event EventHandler CaretMoved;
+ internal event EventHandler WidthChanged;
+ internal event EventHandler HeightChanged;
+ internal event EventHandler LengthChanged;
+ internal event EventHandler UIASelectionChanged;
+ #endregion // Events
+
+ #region Administrative
+ public IEnumerator GetEnumerator() {
+ // FIXME
+ return null;
+ }
+
+ public override bool Equals(object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (!(obj is Document)) {
+ return false;
+ }
+
+ if (obj == this) {
+ return true;
+ }
+
+ if (ToString().Equals(((Document)obj).ToString())) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public override int GetHashCode() {
+ return document_id;
+ }
+
+ public override string ToString() {
+ return "document " + this.document_id;
+ }
+ #endregion // Administrative
+ }
+
+ internal class PictureTag : LineTag {
+
+ internal RTF.Picture picture;
+
+ internal PictureTag (Line line, int start, RTF.Picture picture) : base (line, start)
+ {
+ this.picture = picture;
+ }
+
+ public override bool IsTextTag {
+ get { return false; }
+ }
+
+ public override SizeF SizeOfPosition (Graphics dc, int pos)
+ {
+ return picture.Size;
+ }
+
+ internal override int MaxHeight ()
+ {
+ return (int) (picture.Height + 0.5F);
+ }
+
+ public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end)
+ {
+ picture.DrawImage (dc, xoff + Line.widths [start], y, false);
+ }
+
+ public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, string text)
+ {
+ picture.DrawImage (dc, xoff + + Line.widths [start], y, false);
+ }
+
+ public override string Text ()
+ {
+ return "I";
+ }
+ }
+
+ internal class UndoManager {
+
+ internal enum ActionType {
+
+ Typing,
+
+ // This is basically just cut & paste
+ InsertString,
+ DeleteString,
+
+ UserActionBegin,
+ UserActionEnd
+ }
+
+ internal class Action {
+ internal ActionType type;
+ internal int line_no;
+ internal int pos;
+ internal object data;
+ }
+
+ #region Local Variables
+ private Document document;
+ private Stack undo_actions;
+ private Stack redo_actions;
+
+ //private int caret_line;
+ //private int caret_pos;
+
+ // When performing an action, we lock the queue, so that the action can't be undone
+ private bool locked;
+ #endregion // Local Variables
+
+ #region Constructors
+ internal UndoManager (Document document)
+ {
+ this.document = document;
+ undo_actions = new Stack (50);
+ redo_actions = new Stack (50);
+ }
+ #endregion // Constructors
+
+ #region Properties
+ internal bool CanUndo {
+ get { return undo_actions.Count > 0; }
+ }
+
+ internal bool CanRedo {
+ get { return redo_actions.Count > 0; }
+ }
+
+ internal string UndoActionName {
+ get {
+ foreach (Action action in undo_actions) {
+ if (action.type == ActionType.UserActionBegin)
+ return (string) action.data;
+ if (action.type == ActionType.Typing)
+ return String.Format ("Typing");
+ }
+ return String.Empty;
+ }
+ }
+
+ internal string RedoActionName {
+ get {
+ foreach (Action action in redo_actions) {
+ if (action.type == ActionType.UserActionBegin)
+ return (string) action.data;
+ if (action.type == ActionType.Typing)
+ return String.Format ("Typing");
+ }
+ return String.Empty;
+ }
+ }
+ #endregion // Properties
+
+ #region Internal Methods
+ internal void Clear ()
+ {
+ undo_actions.Clear();
+ redo_actions.Clear();
+ }
+
+ internal bool Undo ()
+ {
+ Action action;
+ bool user_action_finished = false;
+
+ if (undo_actions.Count == 0)
+ return false;
+
+ locked = true;
+ do {
+ Line start;
+ action = (Action) undo_actions.Pop ();
+
+ // Put onto redo stack
+ redo_actions.Push(action);
+
+ // Do the thing
+ switch(action.type) {
+
+ case ActionType.UserActionBegin:
+ user_action_finished = true;
+ break;
+
+ case ActionType.UserActionEnd:
+ // noop
+ break;
+
+ case ActionType.InsertString:
+ start = document.GetLine (action.line_no);
+ document.SuspendUpdate ();
+ document.DeleteMultiline (start, action.pos, ((string) action.data).Length + 1);
+ document.PositionCaret (start, action.pos);
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+ break;
+
+ case ActionType.Typing:
+ start = document.GetLine (action.line_no);
+ document.SuspendUpdate ();
+ document.DeleteMultiline (start, action.pos, ((StringBuilder) action.data).Length);
+ document.PositionCaret (start, action.pos);
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+
+ // This is an open ended operation, so only a single typing operation can be undone at once
+ user_action_finished = true;
+ break;
+
+ case ActionType.DeleteString:
+ start = document.GetLine (action.line_no);
+ document.SuspendUpdate ();
+ Insert (start, action.pos, (Line) action.data, true);
+ document.ResumeUpdate (true);
+ break;
+ }
+ } while (!user_action_finished && undo_actions.Count > 0);
+
+ locked = false;
+
+ return true;
+ }
+
+ internal bool Redo ()
+ {
+ Action action;
+ bool user_action_finished = false;
+
+ if (redo_actions.Count == 0)
+ return false;
+
+ locked = true;
+ do {
+ Line start;
+ int start_index;
+
+ action = (Action) redo_actions.Pop ();
+ undo_actions.Push (action);
+
+ switch (action.type) {
+
+ case ActionType.UserActionBegin:
+ // Noop
+ break;
+
+ case ActionType.UserActionEnd:
+ user_action_finished = true;
+ break;
+
+ case ActionType.InsertString:
+ start = document.GetLine (action.line_no);
+ document.SuspendUpdate ();
+ start_index = document.LineTagToCharIndex (start, action.pos);
+ document.InsertString (start, action.pos, (string) action.data);
+ document.CharIndexToLineTag (start_index + ((string) action.data).Length,
+ out document.caret.line, out document.caret.tag,
+ out document.caret.pos);
+ document.UpdateCaret ();
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+ break;
+
+ case ActionType.Typing:
+ start = document.GetLine (action.line_no);
+ document.SuspendUpdate ();
+ start_index = document.LineTagToCharIndex (start, action.pos);
+ document.InsertString (start, action.pos, ((StringBuilder) action.data).ToString ());
+ document.CharIndexToLineTag (start_index + ((StringBuilder) action.data).Length,
+ out document.caret.line, out document.caret.tag,
+ out document.caret.pos);
+ document.UpdateCaret ();
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+
+ // This is an open ended operation, so only a single typing operation can be undone at once
+ user_action_finished = true;
+ break;
+
+ case ActionType.DeleteString:
+ start = document.GetLine (action.line_no);
+ document.SuspendUpdate ();
+ document.DeleteMultiline (start, action.pos, ((Line) action.data).text.Length);
+ document.PositionCaret (start, action.pos);
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+
+ break;
+ }
+ } while (!user_action_finished && redo_actions.Count > 0);
+
+ locked = false;
+
+ return true;
+ }
+ #endregion // Internal Methods
+
+ #region Private Methods
+
+ public void BeginUserAction (string name)
+ {
+ if (locked)
+ return;
+
+ // Nuke the redo queue
+ redo_actions.Clear ();
+
+ Action ua = new Action ();
+ ua.type = ActionType.UserActionBegin;
+ ua.data = name;
+
+ undo_actions.Push (ua);
+ }
+
+ public void EndUserAction ()
+ {
+ if (locked)
+ return;
+
+ Action ua = new Action ();
+ ua.type = ActionType.UserActionEnd;
+
+ undo_actions.Push (ua);
+ }
+
+ // start_pos, end_pos = 1 based
+ public void RecordDeleteString (Line start_line, int start_pos, Line end_line, int end_pos)
+ {
+ if (locked)
+ return;
+
+ // Nuke the redo queue
+ redo_actions.Clear ();
+
+ Action a = new Action ();
+
+ // We cant simply store the string, because then formatting would be lost
+ a.type = ActionType.DeleteString;
+ a.line_no = start_line.line_no;
+ a.pos = start_pos;
+ a.data = Duplicate (start_line, start_pos, end_line, end_pos);
+
+ undo_actions.Push(a);
+ }
+
+ public void RecordInsertString (Line line, int pos, string str)
+ {
+ if (locked || str.Length == 0)
+ return;
+
+ // Nuke the redo queue
+ redo_actions.Clear ();
+
+ Action a = new Action ();
+
+ a.type = ActionType.InsertString;
+ a.data = str;
+ a.line_no = line.line_no;
+ a.pos = pos;
+
+ undo_actions.Push (a);
+ }
+
+ public void RecordTyping (Line line, int pos, char ch)
+ {
+ if (locked)
+ return;
+
+ // Nuke the redo queue
+ redo_actions.Clear ();
+
+ Action a = null;
+
+ if (undo_actions.Count > 0)
+ a = (Action) undo_actions.Peek ();
+
+ if (a == null || a.type != ActionType.Typing) {
+ a = new Action ();
+ a.type = ActionType.Typing;
+ a.data = new StringBuilder ();
+ a.line_no = line.line_no;
+ a.pos = pos;
+
+ undo_actions.Push (a);
+ }
+
+ StringBuilder data = (StringBuilder) a.data;
+ data.Append (ch);
+ }
+
+ // start_pos = 1-based
+ // end_pos = 1-based
+ public Line Duplicate(Line start_line, int start_pos, Line end_line, int end_pos)
+ {
+ Line ret;
+ Line line;
+ Line current;
+ LineTag tag;
+ LineTag current_tag;
+ int start;
+ int end;
+ int tag_start;
+
+ line = new Line (start_line.document, start_line.ending);
+ ret = line;
+
+ for (int i = start_line.line_no; i <= end_line.line_no; i++) {
+ current = document.GetLine(i);
+
+ if (start_line.line_no == i) {
+ start = start_pos;
+ } else {
+ start = 0;
+ }
+
+ if (end_line.line_no == i) {
+ end = end_pos;
+ } else {
+ end = current.text.Length;
+ }
+
+ if (end_pos == 0)
+ continue;
+
+ // Text for the tag
+ line.text = new StringBuilder (current.text.ToString (start, end - start));
+
+ // Copy tags from start to start+length onto new line
+ current_tag = current.FindTag (start + 1);
+ while ((current_tag != null) && (current_tag.Start <= end)) {
+ if ((current_tag.Start <= start) && (start < (current_tag.Start + current_tag.Length))) {
+ // start tag is within this tag
+ tag_start = start;
+ } else {
+ tag_start = current_tag.Start;
+ }
+
+ tag = new LineTag(line, tag_start - start + 1);
+ tag.CopyFormattingFrom (current_tag);
+
+ current_tag = current_tag.Next;
+
+ // Add the new tag to the line
+ if (line.tags == null) {
+ line.tags = tag;
+ } else {
+ LineTag tail;
+ tail = line.tags;
+
+ while (tail.Next != null) {
+ tail = tail.Next;
+ }
+ tail.Next = tag;
+ tag.Previous = tail;
+ }
+ }
+
+ if ((i + 1) <= end_line.line_no) {
+ line.ending = current.ending;
+
+ // Chain them (we use right/left as next/previous)
+ line.right = new Line (start_line.document, start_line.ending);
+ line.right.left = line;
+ line = line.right;
+ }
+ }
+
+ return ret;
+ }
+
+ // Insert multi-line text at the given position; use formatting at insertion point for inserted text
+ internal void Insert(Line line, int pos, Line insert, bool select)
+ {
+ Line current;
+ LineTag tag;
+ int offset;
+ int lines;
+ Line first;
+
+ // Handle special case first
+ if (insert.right == null) {
+
+ // Single line insert
+ document.Split(line, pos);
+
+ if (insert.tags == null) {
+ return; // Blank line
+ }
+
+ //Insert our tags at the end
+ tag = line.tags;
+
+ while (tag.Next != null) {
+ tag = tag.Next;
+ }
+
+ offset = tag.Start + tag.Length - 1;
+
+ tag.Next = insert.tags;
+ line.text.Insert(offset, insert.text.ToString());
+
+ // Adjust start locations
+ tag = tag.Next;
+ while (tag != null) {
+ tag.Start += offset;
+ tag.Line = line;
+ tag = tag.Next;
+ }
+ // Put it back together
+ document.Combine(line.line_no, line.line_no + 1);
+
+ if (select) {
+ document.SetSelectionStart (line, pos, false);
+ document.SetSelectionEnd (line, pos + insert.text.Length, false);
+ }
+
+ document.UpdateView(line, pos);
+ return;
+ }
+
+ first = line;
+ lines = 1;
+ current = insert;
+
+ while (current != null) {
+
+ if (current == insert) {
+ // Inserting the first line we split the line (and make space)
+ document.Split(line.line_no, pos);
+ //Insert our tags at the end of the line
+ tag = line.tags;
+
+
+ if (tag != null && tag.Length != 0) {
+ while (tag.Next != null) {
+ tag = tag.Next;
+ }
+ offset = tag.Start + tag.Length - 1;
+ tag.Next = current.tags;
+ tag.Next.Previous = tag;
+
+ tag = tag.Next;
+
+ } else {
+ offset = 0;
+ line.tags = current.tags;
+ line.tags.Previous = null;
+ tag = line.tags;
+ }
+
+ line.ending = current.ending;
+ } else {
+ document.Split(line.line_no, 0);
+ offset = 0;
+ line.tags = current.tags;
+ line.tags.Previous = null;
+ line.ending = current.ending;
+ tag = line.tags;
+ }
+
+ // Adjust start locations and line pointers
+ while (tag != null) {
+ tag.Start += offset - 1;
+ tag.Line = line;
+ tag = tag.Next;
+ }
+
+ line.text.Insert(offset, current.text.ToString());
+ line.Grow(line.text.Length);
+
+ line.recalc = true;
+ line = document.GetLine(line.line_no + 1);
+
+ // FIXME? Test undo of line-boundaries
+ if ((current.right == null) && (current.tags.Length != 0)) {
+ document.Combine(line.line_no - 1, line.line_no);
+ }
+ current = current.right;
+ lines++;
+
+ }
+
+ // Recalculate our document
+ document.UpdateView(first, lines, pos);
+ return;
+ }
+ #endregion // Private Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/TextFormatFlags.cs b/source/ShiftUI/Internal/TextFormatFlags.cs
new file mode 100644
index 0000000..6e2c798
--- /dev/null
+++ b/source/ShiftUI/Internal/TextFormatFlags.cs
@@ -0,0 +1,62 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Author:
+// Pedro Martínez Juliá <[email protected]>
+//
+using System;
+
+
+
+namespace ShiftUI {
+
+ [FlagsAttribute()]
+ public enum TextFormatFlags {
+ Left = 0,
+ Top = 0,
+ Default = 0,
+ GlyphOverhangPadding = 0,
+ HorizontalCenter = 1,
+ Right = 2,
+ VerticalCenter = 4,
+ Bottom = 8,
+ WordBreak = 16,
+ SingleLine = 32,
+ ExpandTabs = 64,
+ NoClipping = 256,
+ ExternalLeading = 512,
+ NoPrefix = 2048,
+ Internal = 4096,
+ TextBoxControl = 8192,
+ PathEllipsis = 16384,
+ EndEllipsis = 32768,
+ ModifyString = 65536,
+ RightToLeft = 131072,
+ WordEllipsis = 262144,
+ NoFullWidthCharacterBreak = 524288,
+ HidePrefix = 1048576,
+ PrefixOnly = 2097152,
+ PreserveGraphicsClipping = 16777216,
+ PreserveGraphicsTranslateTransform = 33554432,
+ NoPadding = 268435456,
+ LeftAndRightPadding = 536870912
+ }
+} \ No newline at end of file
diff --git a/source/ShiftUI/Internal/TextRenderer.cs b/source/ShiftUI/Internal/TextRenderer.cs
new file mode 100644
index 0000000..89b3dfa
--- /dev/null
+++ b/source/ShiftUI/Internal/TextRenderer.cs
@@ -0,0 +1,527 @@
+//
+// TextRenderer.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+// This has become a monster class for all things text measuring and drawing.
+//
+// The public API is MeasureText/DrawText, which uses GDI on Win32, and
+// GDI+ on other platforms.
+//
+// There is an internal API MeasureTextInternal/DrawTextInternal, which allows
+// you to pass a flag of whether to use GDI or GDI+. This is used mainly for
+// Widgets that have the UseCompatibleTextRendering flag.
+//
+// There are also thread-safe versions of MeasureString/MeasureCharacterRanges
+// for things that want to measure strings without having a Graphics object.
+
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Drawing.Text;
+using System;
+
+namespace ShiftUI
+{
+ public sealed class TextRenderer
+ {
+ private TextRenderer ()
+ {
+ }
+
+ #region Public Methods
+ public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor)
+ {
+ DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, false);
+ }
+
+ public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor)
+ {
+ DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
+ }
+
+ public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor)
+ {
+ DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, false);
+ }
+
+ public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags)
+ {
+ DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, false);
+ }
+
+ public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor)
+ {
+ DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
+ }
+
+ public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags)
+ {
+ DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, false);
+ }
+
+ public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags)
+ {
+ DrawTextInternal (dc, text, font, pt, foreColor, backColor, flags, false);
+ }
+
+ public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags)
+ {
+ DrawTextInternal (dc, text, font, bounds, foreColor, backColor, flags, false);
+ }
+
+ public static Size MeasureText (string text, Font font)
+ {
+ return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, false);
+ }
+
+ public static Size MeasureText (IDeviceContext dc, string text, Font font)
+ {
+ return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, false);
+ }
+
+ public static Size MeasureText (string text, Font font, Size proposedSize)
+ {
+ return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, false);
+ }
+
+ public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize)
+ {
+ return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, false);
+ }
+
+ public static Size MeasureText (string text, Font font, Size proposedSize, TextFormatFlags flags)
+ {
+ return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, false);
+ }
+
+ public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags)
+ {
+ return MeasureTextInternal (dc, text, font, proposedSize, flags, false);
+ }
+ #endregion
+
+ #region Internal Methods That Do Stuff
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
+ {
+ if (dc == null)
+ throw new ArgumentNullException ("dc");
+
+ if (text == null || text.Length == 0)
+ return;
+
+ // We use MS GDI API's unless told not to, or we aren't on Windows
+ if (!useDrawString && !XplatUI.RunningOnUnix) {
+ if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter || (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
+ flags |= TextFormatFlags.SingleLine;
+
+ // Calculate the text bounds (there is often padding added)
+ Rectangle new_bounds = PadRectangle (bounds, flags);
+ new_bounds.Offset ((int)(dc as Graphics).Transform.OffsetX, (int)(dc as Graphics).Transform.OffsetY);
+
+ IntPtr hdc = IntPtr.Zero;
+ bool clear_clip_region = false;
+
+ // If we need to use the graphics clipping region, add it to our hdc
+ if ((flags & TextFormatFlags.PreserveGraphicsClipping) == TextFormatFlags.PreserveGraphicsClipping) {
+ Graphics graphics = (Graphics)dc;
+ Region clip_region = graphics.Clip;
+
+ if (!clip_region.IsInfinite (graphics)) {
+ IntPtr hrgn = clip_region.GetHrgn (graphics);
+ hdc = dc.GetHdc ();
+ SelectClipRgn (hdc, hrgn);
+ DeleteObject (hrgn);
+
+ clear_clip_region = true;
+ }
+ }
+
+ if (hdc == IntPtr.Zero)
+ hdc = dc.GetHdc ();
+
+ // Set the fore color
+ if (foreColor != Color.Empty)
+ SetTextColor (hdc, ColorTranslator.ToWin32 (foreColor));
+
+ // Set the back color
+ if (backColor != Color.Transparent && backColor != Color.Empty) {
+ SetBkMode (hdc, 2); //1-Transparent, 2-Opaque
+ SetBkColor (hdc, ColorTranslator.ToWin32 (backColor));
+ }
+ else {
+ SetBkMode (hdc, 1); //1-Transparent, 2-Opaque
+ }
+
+ XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new_bounds);
+
+ IntPtr prevobj;
+
+ if (font != null) {
+ prevobj = SelectObject (hdc, font.ToHfont ());
+ Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
+ prevobj = SelectObject (hdc, prevobj);
+ DeleteObject (prevobj);
+ }
+ else {
+ Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
+ }
+
+ if (clear_clip_region)
+ SelectClipRgn (hdc, IntPtr.Zero);
+
+ dc.ReleaseHdc ();
+ }
+ // Use Graphics.DrawString as a fallback method
+ else {
+ Graphics g;
+ IntPtr hdc = IntPtr.Zero;
+
+ if (dc is Graphics)
+ g = (Graphics)dc;
+ else {
+ hdc = dc.GetHdc ();
+ g = Graphics.FromHdc (hdc);
+ }
+
+ StringFormat sf = FlagsToStringFormat (flags);
+
+ Rectangle new_bounds = PadDrawStringRectangle (bounds, flags);
+
+ g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (foreColor), new_bounds, sf);
+
+ if (!(dc is Graphics)) {
+ g.Dispose ();
+ dc.ReleaseHdc ();
+ }
+ }
+ }
+
+ internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
+ {
+ if (!useMeasureString && !XplatUI.RunningOnUnix) {
+ // Tell DrawText to calculate size instead of draw
+ flags |= (TextFormatFlags)1024; // DT_CALCRECT
+
+ IntPtr hdc = dc.GetHdc ();
+
+ XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new Rectangle (Point.Empty, proposedSize));
+
+ IntPtr prevobj;
+
+ if (font != null) {
+ prevobj = SelectObject (hdc, font.ToHfont ());
+ Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
+ prevobj = SelectObject (hdc, prevobj);
+ DeleteObject (prevobj);
+ }
+ else {
+ Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
+ }
+
+ dc.ReleaseHdc ();
+
+ // Really, I am just making something up here, which as far as I can tell, MS
+ // just makes something up as well. This will require lots of tweaking to match MS. :(
+ Size retval = r.ToRectangle ().Size;
+
+ if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0) {
+ retval.Width += 6;
+ retval.Width += (int)retval.Height / 8;
+ }
+
+ return retval;
+ }
+ else {
+ StringFormat sf = FlagsToStringFormat (flags);
+
+ Size retval;
+
+ int proposedWidth;
+ if (proposedSize.Width == 0)
+ proposedWidth = Int32.MaxValue;
+ else {
+ proposedWidth = proposedSize.Width;
+ if ((flags & TextFormatFlags.NoPadding) == 0)
+ proposedWidth -= 9;
+ }
+ if (dc is Graphics)
+ retval = (dc as Graphics).MeasureString (text, font, proposedWidth, sf).ToSize ();
+ else
+ retval = TextRenderer.MeasureString (text, font, proposedWidth, sf).ToSize ();
+
+ if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0)
+ retval.Width += 9;
+
+ return retval;
+ }
+ }
+ #endregion
+
+#region Internal Methods That Are Just Overloads
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, bool useDrawString)
+ {
+ DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, useDrawString);
+ }
+
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, bool useDrawString)
+ {
+ DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
+ }
+
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, bool useDrawString)
+ {
+ DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, useDrawString);
+ }
+
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags, bool useDrawString)
+ {
+ DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, useDrawString);
+ }
+
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, bool useDrawString)
+ {
+ DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
+ }
+
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
+ {
+ DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, useDrawString);
+ }
+
+ internal static Size MeasureTextInternal (string text, Font font, bool useMeasureString)
+ {
+ return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
+ }
+
+ internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
+ {
+ Size sz = MeasureTextInternal (dc, text, font, useDrawString);
+ DrawTextInternal (dc, text, font, new Rectangle (pt, sz), foreColor, backColor, flags, useDrawString);
+ }
+
+ internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, bool useMeasureString)
+ {
+ return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
+ }
+
+ internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, bool useMeasureString)
+ {
+ return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
+ }
+
+ internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, bool useMeasureString)
+ {
+ return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
+ }
+
+ internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
+ {
+ return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, useMeasureString);
+ }
+#endregion
+
+ #region Thread-Safe Static Graphics Methods
+ internal static SizeF MeasureString (string text, Font font)
+ {
+ return Hwnd.GraphicsContext.MeasureString (text, font);
+ }
+
+ internal static SizeF MeasureString (string text, Font font, int width)
+ {
+ return Hwnd.GraphicsContext.MeasureString (text, font, width);
+ }
+
+ internal static SizeF MeasureString (string text, Font font, SizeF layoutArea)
+ {
+ return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea);
+ }
+
+ internal static SizeF MeasureString (string text, Font font, int width, StringFormat format)
+ {
+ return Hwnd.GraphicsContext.MeasureString (text, font, width, format);
+ }
+
+ internal static SizeF MeasureString (string text, Font font, PointF origin, StringFormat stringFormat)
+ {
+ return Hwnd.GraphicsContext.MeasureString (text, font, origin, stringFormat);
+ }
+
+ internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat)
+ {
+ return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat);
+ }
+
+ internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat, out int charactersFitted, out int linesFilled)
+ {
+ return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat, out charactersFitted, out linesFilled);
+ }
+
+ internal static Region[] MeasureCharacterRanges (string text, Font font, RectangleF layoutRect, StringFormat stringFormat)
+ {
+ return Hwnd.GraphicsContext.MeasureCharacterRanges (text, font, layoutRect, stringFormat);
+ }
+
+ internal static SizeF GetDpi ()
+ {
+ return new SizeF (Hwnd.GraphicsContext.DpiX, Hwnd.GraphicsContext.DpiY);
+ }
+ #endregion
+
+#region Private Methods
+ private static StringFormat FlagsToStringFormat (TextFormatFlags flags)
+ {
+ StringFormat sf = new StringFormat ();
+
+ // Translation table: http://msdn.microsoft.com/msdnmag/issues/06/03/TextRendering/default.aspx?fig=true#fig4
+
+ // Horizontal Alignment
+ if ((flags & TextFormatFlags.HorizontalCenter) == TextFormatFlags.HorizontalCenter)
+ sf.Alignment = StringAlignment.Center;
+ else if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right)
+ sf.Alignment = StringAlignment.Far;
+ else
+ sf.Alignment = StringAlignment.Near;
+
+ // Vertical Alignment
+ if ((flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
+ sf.LineAlignment = StringAlignment.Far;
+ else if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter)
+ sf.LineAlignment = StringAlignment.Center;
+ else
+ sf.LineAlignment = StringAlignment.Near;
+
+ // Ellipsis
+ if ((flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis)
+ sf.Trimming = StringTrimming.EllipsisCharacter;
+ else if ((flags & TextFormatFlags.PathEllipsis) == TextFormatFlags.PathEllipsis)
+ sf.Trimming = StringTrimming.EllipsisPath;
+ else if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis)
+ sf.Trimming = StringTrimming.EllipsisWord;
+ else
+ sf.Trimming = StringTrimming.Character;
+
+ // Hotkey Prefix
+ if ((flags & TextFormatFlags.NoPrefix) == TextFormatFlags.NoPrefix)
+ sf.HotkeyPrefix = HotkeyPrefix.None;
+ else if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix)
+ sf.HotkeyPrefix = HotkeyPrefix.Hide;
+ else
+ sf.HotkeyPrefix = HotkeyPrefix.Show;
+
+ // Text Padding
+ if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding)
+ sf.FormatFlags |= StringFormatFlags.FitBlackBox;
+
+ // Text Wrapping
+ if ((flags & TextFormatFlags.SingleLine) == TextFormatFlags.SingleLine)
+ sf.FormatFlags |= StringFormatFlags.NoWrap;
+ else if ((flags & TextFormatFlags.TextBoxControl) == TextFormatFlags.TextBoxControl)
+ sf.FormatFlags |= StringFormatFlags.LineLimit;
+
+ // Other Flags
+ //if ((flags & TextFormatFlags.RightToLeft) == TextFormatFlags.RightToLeft)
+ // sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
+ if ((flags & TextFormatFlags.NoClipping) == TextFormatFlags.NoClipping)
+ sf.FormatFlags |= StringFormatFlags.NoClip;
+
+ return sf;
+ }
+
+ private static Rectangle PadRectangle (Rectangle r, TextFormatFlags flags)
+ {
+ if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
+ r.X += 3;
+ r.Width -= 3;
+ }
+ if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
+ r.Width -= 4;
+ }
+ if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
+ r.X += 2;
+ r.Width -= 2;
+ }
+ if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
+ r.Width -= 4;
+ }
+ if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
+ r.Y += 1;
+ }
+
+ return r;
+ }
+
+ private static Rectangle PadDrawStringRectangle (Rectangle r, TextFormatFlags flags)
+ {
+ if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
+ r.X += 1;
+ r.Width -= 1;
+ }
+ if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
+ r.Width -= 4;
+ }
+ if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding) {
+ r.X -= 2;
+ }
+ if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) {
+ r.Y += 1;
+ }
+ if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
+ r.X += 2;
+ r.Width -= 2;
+ }
+ if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter && XplatUI.RunningOnUnix) {
+ r.Y -= 1;
+ }
+
+ return r;
+ }
+#endregion
+
+#region DllImports (Windows)
+ [DllImport ("user32", CharSet = CharSet.Unicode, EntryPoint = "DrawText")]
+ static extern int Win32DrawText (IntPtr hdc, string lpStr, int nCount, ref XplatUIWin32.RECT lpRect, int wFormat);
+
+ [DllImport ("gdi32")]
+ static extern int SetTextColor (IntPtr hdc, int crColor);
+
+ [DllImport ("gdi32")]
+ static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject);
+
+ [DllImport ("gdi32")]
+ static extern int SetBkColor (IntPtr hdc, int crColor);
+
+ [DllImport ("gdi32")]
+ static extern int SetBkMode (IntPtr hdc, int iBkMode);
+
+ [DllImport ("gdi32")]
+ static extern bool DeleteObject (IntPtr objectHandle);
+
+ [DllImport("gdi32")]
+ static extern bool SelectClipRgn(IntPtr hdc, IntPtr hrgn);
+#endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/Theme.cs b/source/ShiftUI/Internal/Theme.cs
new file mode 100644
index 0000000..4f1eac6
--- /dev/null
+++ b/source/ShiftUI/Internal/Theme.cs
@@ -0,0 +1,1063 @@
+// 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-2005 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+// Peter Dennis Bartok, [email protected]
+//
+
+using System.Collections;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Reflection;
+using System;
+
+namespace ShiftUI
+{
+ internal enum UIIcon {
+ PlacesRecentDocuments,
+ PlacesDesktop,
+ PlacesPersonal,
+ PlacesMyComputer,
+ PlacesMyNetwork,
+ MessageBoxError,
+ MessageBoxQuestion,
+ MessageBoxWarning,
+ MessageBoxInfo,
+
+ NormalFolder
+ }
+
+ internal struct CPColor {
+ internal Color Dark;
+ internal Color DarkDark;
+ internal Color Light;
+ internal Color LightLight;
+
+ internal static CPColor Empty;
+ }
+
+ // Implements a pool of system resources
+ internal class SystemResPool
+ {
+ private Hashtable pens = new Hashtable ();
+ private Hashtable dashpens = new Hashtable ();
+ private Hashtable sizedpens = new Hashtable ();
+ private Hashtable solidbrushes = new Hashtable ();
+ private Hashtable hatchbrushes = new Hashtable ();
+ private Hashtable uiImages = new Hashtable();
+ private Hashtable cpcolors = new Hashtable ();
+
+ public SystemResPool () {}
+
+ public Pen GetPen (Color color)
+ {
+ int hash = color.ToArgb ();
+
+ lock (pens) {
+ Pen res = pens [hash] as Pen;
+ if (res != null)
+ return res;
+
+ Pen pen = new Pen (color);
+ pens.Add (hash, pen);
+ return pen;
+ }
+ }
+
+ public Pen GetDashPen (Color color, DashStyle dashStyle)
+ {
+ string hash = color.ToString() + dashStyle;
+
+ lock (dashpens) {
+ Pen res = dashpens [hash] as Pen;
+ if (res != null)
+ return res;
+
+ Pen pen = new Pen (color);
+ pen.DashStyle = dashStyle;
+ dashpens [hash] = pen;
+ return pen;
+ }
+ }
+
+ public Pen GetSizedPen (Color color, int size)
+ {
+ string hash = color.ToString () + size;
+
+ lock (sizedpens) {
+ Pen res = sizedpens [hash] as Pen;
+ if (res != null)
+ return res;
+
+ Pen pen = new Pen (color, size);
+ sizedpens [hash] = pen;
+ return pen;
+ }
+ }
+
+ public SolidBrush GetSolidBrush (Color color)
+ {
+ int hash = color.ToArgb ();
+
+ lock (solidbrushes) {
+ SolidBrush res = solidbrushes [hash] as SolidBrush;
+ if (res != null)
+ return res;
+
+ SolidBrush brush = new SolidBrush (color);
+ solidbrushes.Add (hash, brush);
+ return brush;
+ }
+ }
+
+ public HatchBrush GetHatchBrush (HatchStyle hatchStyle, Color foreColor, Color backColor)
+ {
+ string hash = ((int)hatchStyle).ToString () + foreColor.ToString () + backColor.ToString ();
+
+ lock (hatchbrushes) {
+ HatchBrush brush = (HatchBrush) hatchbrushes[hash];
+ if (brush == null) {
+ brush = new HatchBrush (hatchStyle, foreColor, backColor);
+ hatchbrushes.Add (hash, brush);
+ }
+ return brush;
+ }
+ }
+
+ public void AddUIImage (Image image, string name, int size)
+ {
+ string hash = name + size.ToString();
+
+ lock (uiImages) {
+ if (uiImages.Contains (hash))
+ return;
+ uiImages.Add (hash, image);
+ }
+ }
+
+ public Image GetUIImage(string name, int size)
+ {
+ string hash = name + size.ToString();
+
+ Image image = uiImages [hash] as Image;
+
+ return image;
+ }
+
+ public CPColor GetCPColor (Color color)
+ {
+ lock (cpcolors) {
+ object tmp = cpcolors [color];
+
+ if (tmp == null) {
+ CPColor cpcolor = new CPColor ();
+ cpcolor.Dark = WidgetPaint.Dark (color);
+ cpcolor.DarkDark = WidgetPaint.DarkDark (color);
+ cpcolor.Light = WidgetPaint.Light (color);
+ cpcolor.LightLight = WidgetPaint.LightLight (color);
+
+ cpcolors.Add (color, cpcolor);
+
+ return cpcolor;
+ }
+
+ return (CPColor)tmp;
+ }
+ }
+ }
+
+ internal abstract class Theme
+ {
+ protected Array syscolors;
+ Font default_font;
+ protected Color defaultWindowBackColor;
+ protected Color defaultWindowForeColor;
+ internal SystemResPool ResPool = new SystemResPool ();
+ private MethodInfo update;
+
+ protected Theme ()
+ {
+ }
+
+ private void SetSystemColors (KnownColor kc, Color value)
+ {
+ if (update == null) {
+ Type known_colors = Type.GetType ("System.Drawing.KnownColors, " + Consts.AssemblySystem_Drawing);
+ if (known_colors != null)
+ update = known_colors.GetMethod ("Update", BindingFlags.Static | BindingFlags.Public);
+ }
+ if (update != null)
+ update.Invoke (null, new object [2] { (int)kc, value.ToArgb () });
+ }
+
+ /* OS Feature support */
+ public abstract Version Version {
+ get;
+ }
+
+ /* Default properties */
+ public virtual Color ColorScrollBar {
+ get { return SystemColors.ScrollBar; }
+ set { SetSystemColors (KnownColor.ScrollBar, value); }
+ }
+
+ public virtual Color ColorDesktop {
+ get { return SystemColors.Desktop;}
+ set { SetSystemColors (KnownColor.Desktop, value); }
+ }
+
+ public virtual Color ColorActiveCaption {
+ get { return SystemColors.ActiveCaption;}
+ set { SetSystemColors (KnownColor.ActiveCaption, value); }
+ }
+
+ public virtual Color ColorInactiveCaption {
+ get { return SystemColors.InactiveCaption;}
+ set { SetSystemColors (KnownColor.InactiveCaption, value); }
+ }
+
+ public virtual Color ColorMenu {
+ get { return SystemColors.Menu;}
+ set { SetSystemColors (KnownColor.Menu, value); }
+ }
+
+ public virtual Color ColorWindow {
+ get { return SystemColors.Window;}
+ set { SetSystemColors (KnownColor.Window, value); }
+ }
+
+ public virtual Color ColorWindowFrame {
+ get { return SystemColors.WindowFrame;}
+ set { SetSystemColors (KnownColor.WindowFrame, value); }
+ }
+
+ public virtual Color ColorMenuText {
+ get { return SystemColors.MenuText;}
+ set { SetSystemColors (KnownColor.MenuText, value); }
+ }
+
+ public virtual Color ColorWindowText {
+ get { return SystemColors.WindowText;}
+ set { SetSystemColors (KnownColor.WindowText, value); }
+ }
+
+ public virtual Color ColorActiveCaptionText {
+ get { return SystemColors.ActiveCaptionText;}
+ set { SetSystemColors (KnownColor.ActiveCaptionText, value); }
+ }
+
+ public virtual Color ColorActiveBorder {
+ get { return SystemColors.ActiveBorder;}
+ set { SetSystemColors (KnownColor.ActiveBorder, value); }
+ }
+
+ public virtual Color ColorInactiveBorder{
+ get { return SystemColors.InactiveBorder;}
+ set { SetSystemColors (KnownColor.InactiveBorder, value); }
+ }
+
+ public virtual Color ColorAppWorkspace {
+ get { return SystemColors.AppWorkspace;}
+ set { SetSystemColors (KnownColor.AppWorkspace, value); }
+ }
+
+ public virtual Color ColorHighlight {
+ get { return SystemColors.Highlight;}
+ set { SetSystemColors (KnownColor.Highlight, value); }
+ }
+
+ public virtual Color ColorHighlightText {
+ get { return SystemColors.HighlightText;}
+ set { SetSystemColors (KnownColor.HighlightText, value); }
+ }
+
+ public virtual Color ColorControl {
+ get { return SystemColors.Control; }
+ set { SetSystemColors (KnownColor.Control, value); }
+ }
+
+ public virtual Color ColorControlDark {
+ get { return SystemColors.ControlDark;}
+ set { SetSystemColors (KnownColor.ControlDark, value); }
+ }
+
+ public virtual Color ColorGrayText {
+ get { return SystemColors.GrayText;}
+ set { SetSystemColors (KnownColor.GrayText, value); }
+ }
+
+ public virtual Color ColorControlText {
+ get { return SystemColors.ControlText;}
+ set { SetSystemColors (KnownColor.ControlText, value); }
+ }
+
+ public virtual Color ColorInactiveCaptionText {
+ get { return SystemColors.InactiveCaptionText;}
+ set { SetSystemColors (KnownColor.InactiveCaptionText, value); }
+ }
+
+ public virtual Color ColorControlLight {
+ get { return SystemColors.ControlLight;}
+ set { SetSystemColors (KnownColor.ControlLight, value); }
+ }
+
+ public virtual Color ColorControlDarkDark {
+ get { return SystemColors.ControlDarkDark;}
+ set { SetSystemColors (KnownColor.ControlDarkDark, value); }
+ }
+
+ public virtual Color ColorControlLightLight {
+ get { return SystemColors.ControlLightLight;}
+ set { SetSystemColors (KnownColor.ControlLightLight, value); }
+ }
+
+ public virtual Color ColorInfoText {
+ get { return SystemColors.InfoText;}
+ set { SetSystemColors (KnownColor.InfoText, value); }
+ }
+
+ public virtual Color ColorInfo {
+ get { return SystemColors.Info;}
+ set { SetSystemColors (KnownColor.Info, value); }
+ }
+
+ public virtual Color ColorHotTrack {
+ get { return SystemColors.HotTrack;}
+ set { SetSystemColors (KnownColor.HotTrack, value);}
+ }
+
+ public virtual Color DefaultControlBackColor {
+ get { return ColorControl; }
+ set { ColorControl = value; }
+ }
+
+ public virtual Color DefaultControlForeColor {
+ get { return ColorControlText; }
+ set { ColorControlText = value; }
+ }
+
+ public virtual Font DefaultFont {
+ get { return default_font ?? (default_font = SystemFonts.DefaultFont); }
+ }
+
+ public virtual Color DefaultWindowBackColor {
+ get { return defaultWindowBackColor; }
+ }
+
+ public virtual Color DefaultWindowForeColor {
+ get { return defaultWindowForeColor; }
+ }
+
+ public virtual Color GetColor (XplatUIWin32.GetSysColorIndex idx)
+ {
+ return (Color) syscolors.GetValue ((int)idx);
+ }
+
+ public virtual void SetColor (XplatUIWin32.GetSysColorIndex idx, Color color)
+ {
+ syscolors.SetValue (color, (int) idx);
+ }
+
+ // Theme/UI specific defaults
+ public virtual ArrangeDirection ArrangeDirection {
+ get {
+ return ArrangeDirection.Down;
+ }
+ }
+
+ public virtual ArrangeStartingPosition ArrangeStartingPosition {
+ get {
+ return ArrangeStartingPosition.BottomLeft;
+ }
+ }
+
+ public virtual int BorderMultiplierFactor { get { return 1; } }
+
+ public virtual Size BorderSizableSize {
+ get {
+ return new Size (3, 3);
+ }
+ }
+
+ public virtual Size Border3DSize {
+ get {
+ return XplatUI.Border3DSize;
+ }
+ }
+
+ public virtual Size BorderStaticSize {
+ get {
+ return new Size(1, 1);
+ }
+ }
+
+ public virtual Size BorderSize {
+ get {
+ return XplatUI.BorderSize;
+ }
+ }
+
+ public virtual Size CaptionButtonSize {
+ get {
+ return XplatUI.CaptionButtonSize;
+ }
+ }
+
+ public virtual int CaptionHeight {
+ get {
+ return XplatUI.CaptionHeight;
+ }
+ }
+
+ public virtual Size DoubleClickSize {
+ get {
+ return new Size(4, 4);
+ }
+ }
+
+ public virtual int DoubleClickTime {
+ get {
+ return XplatUI.DoubleClickTime;
+ }
+ }
+
+ public virtual Size FixedFrameBorderSize {
+ get {
+ return XplatUI.FixedFrameBorderSize;
+ }
+ }
+
+ public virtual Size FrameBorderSize {
+ get {
+ return XplatUI.FrameBorderSize;
+ }
+ }
+
+ public virtual int HorizontalFocusThickness { get { return 1; } }
+
+ public virtual int HorizontalScrollBarArrowWidth {
+ get {
+ return 16;
+ }
+ }
+
+ public virtual int HorizontalScrollBarHeight {
+ get {
+ return 16;
+ }
+ }
+
+ public virtual int HorizontalScrollBarThumbWidth {
+ get {
+ return 16;
+ }
+ }
+
+ public virtual Size IconSpacingSize {
+ get {
+ return new Size(75, 75);
+ }
+ }
+
+ public virtual bool MenuAccessKeysUnderlined {
+ get {
+ try {
+ return XplatUI.MenuAccessKeysUnderlined;
+ }
+ catch(Exception ex) {
+ Console.WriteLine("[ShiftUI] XplatUI error: {0}\r\nInnerException: {1}", ex.Message, ex.InnerException.Message);
+ return false;
+ }
+ }
+ }
+
+ public virtual Size MenuBarButtonSize {
+ get { return XplatUI.MenuBarButtonSize; }
+ }
+
+ public virtual Size MenuButtonSize {
+ get {
+ return XplatUI.MenuButtonSize;
+ }
+ }
+
+ public virtual Size MenuCheckSize {
+ get {
+ return new Size(13, 13);
+ }
+ }
+
+ public virtual Font MenuFont {
+ get {
+ return default_font ?? (default_font = SystemFonts.DefaultFont);
+ }
+ }
+
+ public virtual int MenuHeight {
+ get {
+ return XplatUI.MenuHeight;
+ }
+ }
+
+ public virtual int MouseWheelScrollLines {
+ get {
+ return 3;
+ }
+ }
+
+ public virtual bool RightAlignedMenus {
+ get {
+ return false;
+ }
+ }
+
+ public virtual Size ToolWindowCaptionButtonSize {
+ get {
+ return XplatUI.ToolWindowCaptionButtonSize;
+ }
+ }
+
+ public virtual int ToolWindowCaptionHeight {
+ get {
+ return XplatUI.ToolWindowCaptionHeight;
+ }
+ }
+
+ public virtual int VerticalFocusThickness { get { return 1; } }
+
+ public virtual int VerticalScrollBarArrowHeight {
+ get {
+ return 16;
+ }
+ }
+
+ public virtual int VerticalScrollBarThumbHeight {
+ get {
+ return 16;
+ }
+ }
+
+ public virtual int VerticalScrollBarWidth {
+ get {
+ return 16;
+ }
+ }
+
+ public abstract Font WindowBorderFont {
+ get;
+ }
+
+ public int Clamp (int value, int lower, int upper)
+ {
+ if (value < lower) return lower;
+ else if (value > upper) return upper;
+ else return value;
+ }
+
+ [MonoInternalNote ("Figure out where to point for My Network Places")]
+ public virtual string Places(UIIcon index) {
+ switch (index) {
+ case UIIcon.PlacesRecentDocuments: {
+ // Default = "Recent Documents"
+ return Environment.GetFolderPath(Environment.SpecialFolder.Recent);
+ }
+
+ case UIIcon.PlacesDesktop: {
+ // Default = "Desktop"
+ return Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
+ }
+
+ case UIIcon.PlacesPersonal: {
+ // Default = "My Documents"
+ return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
+ }
+
+ case UIIcon.PlacesMyComputer: {
+ // Default = "My Computer"
+ return Environment.GetFolderPath(Environment.SpecialFolder.MyComputer);
+ }
+
+ case UIIcon.PlacesMyNetwork: {
+ // Default = "My Network Places"
+ return "/tmp";
+ }
+
+ default: {
+ throw new ArgumentOutOfRangeException("index", index, "Unsupported place");
+ }
+ }
+ }
+
+ //
+ // This routine fetches images embedded as assembly resources (not
+ // resgen resources). It optionally scales the image to fit the
+ // specified size x dimension (it adjusts y automatically to fit that).
+ //
+ private Image GetSizedResourceImage(string name, int width)
+ {
+ Image image = ResPool.GetUIImage (name, width);
+ if (image != null)
+ return image;
+
+ string fullname;
+
+ if (width > 0) {
+ // Try name_width
+ fullname = String.Format("{1}_{0}", name, width);
+ if (image != null){
+ ResPool.AddUIImage (image, name, width);
+ return image;
+ }
+ }
+
+ // Just try name
+ if (image == null)
+ return null;
+
+ ResPool.AddUIImage (image, name, 0);
+ if (image.Width != width && width != 0){
+ Console.Error.WriteLine ("warning: requesting icon that not been tuned {0}_{1} {2}", width, name, image.Width);
+ int height = (image.Height * width)/image.Width;
+ Bitmap b = new Bitmap (width, height);
+ using (Graphics g = Graphics.FromImage (b))
+ g.DrawImage (image, 0, 0, width, height);
+ ResPool.AddUIImage (b, name, width);
+
+ return b;
+ }
+ return image;
+ }
+
+ public virtual Image Images(UIIcon index) {
+ return Images(index, 0);
+ }
+
+ public virtual Image Images(UIIcon index, int size) {
+ switch (index) {
+ case UIIcon.PlacesRecentDocuments:
+ return GetSizedResourceImage ("document-open.png", size);
+ case UIIcon.PlacesDesktop:
+ return GetSizedResourceImage ("user-desktop.png", size);
+ case UIIcon.PlacesPersonal:
+ return GetSizedResourceImage ("user-home.png", size);
+ case UIIcon.PlacesMyComputer:
+ return GetSizedResourceImage ("computer.png", size);
+ case UIIcon.PlacesMyNetwork:
+ return GetSizedResourceImage ("folder-remote.png", size);
+
+ // Icons for message boxes
+ case UIIcon.MessageBoxError:
+ return GetSizedResourceImage ("dialog-error.png", size);
+ case UIIcon.MessageBoxInfo:
+ return GetSizedResourceImage ("dialog-information.png", size);
+ case UIIcon.MessageBoxQuestion:
+ return GetSizedResourceImage ("dialog-question.png", size);
+ case UIIcon.MessageBoxWarning:
+ return GetSizedResourceImage ("dialog-warning.png", size);
+
+ // misc Icons
+ case UIIcon.NormalFolder:
+ return GetSizedResourceImage ("folder.png", size);
+
+ default: {
+ throw new ArgumentException("Invalid Icon type requested", "index");
+ }
+ }
+ }
+
+ public virtual Image Images(string mimetype, string extension, int size) {
+ return null;
+ }
+
+ #region Principal Theme Methods
+ // To let the theme now that a change of defaults (colors, etc) was detected and force a re-read (and possible recreation of cached resources)
+ public abstract void ResetDefaults();
+
+ // If the theme writes directly to a window instead of a device context
+ public abstract bool DoubleBufferingSupported {get;}
+ #endregion // Principal Theme Methods
+
+ #region OwnerDraw Support
+ public abstract void DrawOwnerDrawBackground (DrawItemEventArgs e);
+ public abstract void DrawOwnerDrawFocusRectangle (DrawItemEventArgs e);
+ #endregion // OwnerDraw Support
+
+ #region Button
+ public abstract Size CalculateButtonAutoSize (Button button);
+ public abstract void CalculateButtonTextAndImageLayout (Graphics g, ButtonBase b, out Rectangle textRectangle, out Rectangle imageRectangle);
+ public abstract void DrawButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
+ public abstract void DrawFlatButton (Graphics g, ButtonBase b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
+ public abstract void DrawPopupButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
+ #endregion // Button
+
+ #region ButtonBase
+ // Drawing
+ public abstract void DrawButtonBase(Graphics dc, Rectangle clip_area, ButtonBase button);
+
+ // Sizing
+ public abstract Size ButtonBaseDefaultSize{get;}
+ #endregion // ButtonBase
+
+ #region CheckBox
+ public abstract Size CalculateCheckBoxAutoSize (CheckBox checkBox);
+ public abstract void CalculateCheckBoxTextAndImageLayout (ButtonBase b, Point offset, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle);
+ public abstract void DrawCheckBox (Graphics g, CheckBox cb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
+ public abstract void DrawCheckBox (Graphics dc, Rectangle clip_area, CheckBox checkbox);
+
+ #endregion // CheckBox
+
+ #region CheckedListBox
+ // Drawing
+ public abstract void DrawCheckedListBoxItem (CheckedListBox ctrl, DrawItemEventArgs e);
+ #endregion // CheckedListBox
+
+ #region ComboBox
+ // Drawing
+ public abstract void DrawComboBoxItem (ComboBox ctrl, DrawItemEventArgs e);
+ public abstract void DrawFlatStyleComboButton (Graphics graphics, Rectangle rectangle, ButtonState state);
+ public abstract void ComboBoxDrawNormalDropDownButton (ComboBox comboBox, Graphics g, Rectangle clippingArea, Rectangle area, ButtonState state);
+ public abstract bool ComboBoxNormalDropDownButtonHasTransparentBackground (ComboBox comboBox, ButtonState state);
+ public abstract bool ComboBoxDropDownButtonHasHotElementStyle (ComboBox comboBox);
+ public abstract void ComboBoxDrawBackground (ComboBox comboBox, Graphics g, Rectangle clippingArea, FlatStyle style);
+ public abstract bool CombBoxBackgroundHasHotElementStyle (ComboBox comboBox);
+ #endregion // ComboBox
+
+ #region Widget
+ public abstract Font GetLinkFont (Widget control);
+ #endregion // Widget
+
+
+ /* FIXME: I really don't feel like implementing DataGrids. Too much code.
+ #region Datagrid
+ public abstract int DataGridPreferredColumnWidth { get; }
+ public abstract int DataGridMinimumColumnCheckBoxHeight { get; }
+ public abstract int DataGridMinimumColumnCheckBoxWidth { get; }
+
+ // Default colours
+ public abstract Color DataGridAlternatingBackColor { get; }
+ public abstract Color DataGridBackColor { get; }
+ public abstract Color DataGridBackgroundColor { get; }
+ public abstract Color DataGridCaptionBackColor { get; }
+ public abstract Color DataGridCaptionForeColor { get; }
+ public abstract Color DataGridGridLineColor { get; }
+ public abstract Color DataGridHeaderBackColor { get; }
+ public abstract Color DataGridHeaderForeColor { get; }
+ public abstract Color DataGridLinkColor { get; }
+ public abstract Color DataGridLinkHoverColor { get; }
+ public abstract Color DataGridParentRowsBackColor { get; }
+ public abstract Color DataGridParentRowsForeColor { get; }
+ public abstract Color DataGridSelectionBackColor { get; }
+ public abstract Color DataGridSelectionForeColor { get; }
+ // Paint
+ public abstract void DataGridPaint (PaintEventArgs pe, DataGrid grid);
+ public abstract void DataGridPaintCaption (Graphics g, Rectangle clip, DataGrid grid);
+ public abstract void DataGridPaintColumnHeaders (Graphics g, Rectangle clip, DataGrid grid);
+ public abstract void DataGridPaintColumnHeader (Graphics g, Rectangle bounds, DataGrid grid, int col);
+ public abstract void DataGridPaintRowContents (Graphics g, int row, Rectangle row_rect, bool is_newrow, Rectangle clip, DataGrid grid);
+ public abstract void DataGridPaintRowHeader (Graphics g, Rectangle bounds, int row, DataGrid grid);
+ public abstract void DataGridPaintRowHeaderArrow (Graphics g, Rectangle bounds, DataGrid grid);
+ public abstract void DataGridPaintRowHeaderStar (Graphics g, Rectangle bounds, DataGrid grid);
+ public abstract void DataGridPaintParentRows (Graphics g, Rectangle bounds, DataGrid grid);
+ public abstract void DataGridPaintParentRow (Graphics g, Rectangle bounds, DataGridDataSource row, DataGrid grid);
+ public abstract void DataGridPaintRows (Graphics g, Rectangle cells, Rectangle clip, DataGrid grid);
+ public abstract void DataGridPaintRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, Rectangle clip, DataGrid grid);
+ public abstract void DataGridPaintRelationRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, Rectangle clip, DataGrid grid);
+
+ #endregion // Datagrid
+
+ #region DataGridView
+ #region DataGridViewHeaderCell
+ #region DataGridViewRowHeaderCell
+ public abstract bool DataGridViewRowHeaderCellDrawBackground (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds);
+ public abstract bool DataGridViewRowHeaderCellDrawSelectionBackground (DataGridViewRowHeaderCell cell);
+ public abstract bool DataGridViewRowHeaderCellDrawBorder (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds);
+ #endregion
+ #region DataGridViewColumnHeaderCell
+ public abstract bool DataGridViewColumnHeaderCellDrawBackground (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds);
+ public abstract bool DataGridViewColumnHeaderCellDrawBorder (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds);
+ #endregion
+ public abstract bool DataGridViewHeaderCellHasPressedStyle (DataGridView dataGridView);
+ public abstract bool DataGridViewHeaderCellHasHotStyle (DataGridView dataGridView);
+ #endregion
+ #endregion
+*/
+
+ #region DateTimePicker
+ public abstract void DrawDateTimePicker(Graphics dc, Rectangle clip_rectangle, DateTimePicker dtp);
+ public abstract bool DateTimePickerBorderHasHotElementStyle { get; }
+ public abstract Rectangle DateTimePickerGetDropDownButtonArea (DateTimePicker dateTimePicker);
+ public abstract Rectangle DateTimePickerGetDateArea (DateTimePicker dateTimePicker);
+ public abstract bool DateTimePickerDropDownButtonHasHotElementStyle { get; }
+ #endregion // DateTimePicker
+
+ #region GroupBox
+ // Drawing
+ public abstract void DrawGroupBox (Graphics dc, Rectangle clip_area, GroupBox box);
+
+ // Sizing
+ public abstract Size GroupBoxDefaultSize{get;}
+ #endregion // GroupBox
+
+ #region HScrollBar
+ public abstract Size HScrollBarDefaultSize{get;} // Default size of the scrollbar
+ #endregion // HScrollBar
+
+ #region ListBox
+ // Drawing
+ public abstract void DrawListBoxItem (ListBox ctrl, DrawItemEventArgs e);
+ #endregion // ListBox
+
+ #region ListView
+ // Drawing
+ public abstract void DrawListViewItems (Graphics dc, Rectangle clip_rectangle, ListView control);
+ public abstract void DrawListViewHeader (Graphics dc, Rectangle clip_rectangle, ListView control);
+ public abstract void DrawListViewHeaderDragDetails (Graphics dc, ListView control, ColumnHeader drag_column, int target_x);
+ public abstract bool ListViewHasHotHeaderStyle { get; }
+
+ // Sizing
+ public abstract int ListViewGetHeaderHeight (ListView listView, Font font);
+ public abstract Size ListViewCheckBoxSize { get; }
+ public abstract int ListViewColumnHeaderHeight { get; }
+ public abstract int ListViewDefaultColumnWidth { get; }
+ public abstract int ListViewVerticalSpacing { get; }
+ public abstract int ListViewEmptyColumnWidth { get; }
+ public abstract int ListViewHorizontalSpacing { get; }
+ public abstract Size ListViewDefaultSize { get; }
+ public abstract int ListViewGroupHeight { get; }
+ public abstract int ListViewItemPaddingWidth { get; }
+ public abstract int ListViewTileWidthFactor { get; }
+ public abstract int ListViewTileHeightFactor { get; }
+ #endregion // ListView
+
+ #region Menus
+ public abstract void CalcItemSize (Graphics dc, MenuItem item, int y, int x, bool menuBar);
+ public abstract void CalcPopupMenuSize (Graphics dc, Menu menu);
+ public abstract int CalcMenuBarSize (Graphics dc, Menu menu, int width);
+ public abstract void DrawMenuBar (Graphics dc, Menu menu, Rectangle rect);
+ public abstract void DrawMenuItem (MenuItem item, DrawItemEventArgs e);
+ public abstract void DrawPopupMenu (Graphics dc, Menu menu, Rectangle cliparea, Rectangle rect);
+ #endregion // Menus
+
+ #region MonthCalendar
+ public abstract void DrawMonthCalendar(Graphics dc, Rectangle clip_rectangle, MonthCalendar month_calendar);
+ #endregion // MonthCalendar
+
+ #region Panel
+ // Sizing
+ public abstract Size PanelDefaultSize{get;}
+ #endregion // Panel
+
+ #region PictureBox
+ // Drawing
+ public abstract void DrawPictureBox (Graphics dc, Rectangle clip, PictureBox pb);
+
+ // Sizing
+ public abstract Size PictureBoxDefaultSize{get;}
+ #endregion // PictureBox
+
+ /* FIXME: No printing.
+ #region PrintPreviewControl
+ public abstract int PrintPreviewControlPadding{get;}
+ public abstract Size PrintPreviewControlGetPageSize (PrintPreviewControl preview);
+ public abstract void PrintPreviewWidgetPaint (PaintEventArgs pe, PrintPreviewControl preview, Size page_image_size);
+ #endregion // PrintPreviewControl
+*/
+ #region ProgressBar
+ // Drawing
+ public abstract void DrawProgressBar (Graphics dc, Rectangle clip_rectangle, ProgressBar progress_bar);
+
+ // Sizing
+ public abstract Size ProgressBarDefaultSize{get;}
+ #endregion // ProgressBar
+
+ #region RadioButton
+ // Drawing
+ public abstract Size CalculateRadioButtonAutoSize (RadioButton rb);
+ public abstract void CalculateRadioButtonTextAndImageLayout (ButtonBase b, Point offset, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle);
+ public abstract void DrawRadioButton (Graphics g, RadioButton rb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
+ public abstract void DrawRadioButton (Graphics dc, Rectangle clip_rectangle, RadioButton radio_button);
+
+ // Sizing
+ public abstract Size RadioButtonDefaultSize{get;}
+ #endregion // RadioButton
+
+ #region ScrollBar
+ // Drawing
+ //public abstract void DrawScrollBar (Graphics dc, Rectangle area, ScrollBar bar, ref Rectangle thumb_pos, ref Rectangle first_arrow_area, ref Rectangle second_arrow_area, ButtonState first_arrow, ButtonState second_arrow, ref int scrollbutton_width, ref int scrollbutton_height, bool vert);
+ public abstract void DrawScrollBar (Graphics dc, Rectangle clip_rectangle, ScrollBar bar);
+
+ // Sizing
+ public abstract int ScrollBarButtonSize {get;} // Size of the scroll button
+
+ public abstract bool ScrollBarHasHotElementStyles { get; }
+
+ public abstract bool ScrollBarHasPressedThumbStyle { get; }
+
+ public abstract bool ScrollBarHasHoverArrowButtonStyle { get; }
+ #endregion // ScrollBar
+
+ #region StatusBar
+ // Drawing
+ public abstract void DrawStatusBar (Graphics dc, Rectangle clip_rectangle, StatusBar sb);
+
+ // Sizing
+ public abstract int StatusBarSizeGripWidth {get;} // Size of Resize area
+ public abstract int StatusBarHorzGapWidth {get;} // Gap between panels
+ public abstract Size StatusBarDefaultSize{get;}
+ #endregion // StatusBar
+
+ #region TabControl
+ public abstract Size TabControlDefaultItemSize {get; }
+ public abstract Point TabControlDefaultPadding {get; }
+ public abstract int TabControlMinimumTabWidth {get; }
+ public abstract Rectangle TabWidgetselectedDelta { get; }
+ public abstract int TabWidgetselectedSpacing { get; }
+ public abstract int TabPanelOffsetX { get; }
+ public abstract int TabPanelOffsetY { get; }
+ public abstract int TabControlColSpacing { get; }
+ public abstract Point TabControlImagePadding { get; }
+ public abstract int TabWidgetscrollerWidth { get; }
+
+ public abstract Rectangle TabControlGetDisplayRectangle (TabWidget tab);
+ public abstract Rectangle TabControlGetPanelRect (TabWidget tab);
+ public abstract Size TabControlGetSpacing (TabWidget tab);
+ public abstract void DrawTabControl (Graphics dc, Rectangle area, TabWidget tab);
+ #endregion
+
+ #region TextBoxBase
+ public abstract void TextBoxBaseFillBackground (TextBoxBase textBoxBase, Graphics g, Rectangle clippingArea);
+ public abstract bool TextBoxBaseHandleWmNcPaint (TextBoxBase textBoxBase, ref Message m);
+ public abstract bool TextBoxBaseShouldPaintBackground (TextBoxBase textBoxBase);
+ #endregion
+
+ /*#region ToolBar
+ // Drawing
+ public abstract void DrawToolBar (Graphics dc, Rectangle clip_rectangle, ToolBar control);
+
+ // Sizing
+ public abstract int ToolBarGripWidth {get;} // Grip width for the ToolBar
+ public abstract int ToolBarImageGripWidth {get;} // Grip width for the Image on the ToolBarButton
+ public abstract int ToolBarSeparatorWidth {get;} // width of the separator
+ public abstract int ToolBarDropDownWidth { get; } // width of the dropdown arrow rect
+ public abstract int ToolBarDropDownArrowWidth { get; } // width for the dropdown arrow on the ToolBarButton
+ public abstract int ToolBarDropDownArrowHeight { get; } // height for the dropdown arrow on the ToolBarButton
+ public abstract Size ToolBarDefaultSize{get;}
+
+ public abstract bool ToolBarHasHotElementStyles (ToolBar toolBar);
+ public abstract bool ToolBarHasHotCheckedElementStyles { get; }
+ #endregion // ToolBar
+*/
+
+ #region ToolTip
+ public abstract void DrawToolTip(Graphics dc, Rectangle clip_rectangle, ToolTip.ToolTipWindow control);
+ public abstract Size ToolTipSize(ToolTip.ToolTipWindow tt, string text);
+ public abstract bool ToolTipTransparentBackground { get; }
+ #endregion // ToolTip
+
+ #region BalloonWindow
+ public abstract void ShowBalloonWindow (IntPtr handle, int timeout, string title, string text, ToolTipIcon icon);
+ public abstract void HideBalloonWindow (IntPtr handle);
+ public abstract void DrawBalloonWindow (Graphics dc, Rectangle clip, NotifyIcon.BalloonWindow control);
+ public abstract Rectangle BalloonWindowRect (NotifyIcon.BalloonWindow control);
+ #endregion // BalloonWindow
+
+ #region TrackBar
+ // Drawing
+ public abstract void DrawTrackBar (Graphics dc, Rectangle clip_rectangle, TrackBar tb);
+
+ // Sizing
+ public abstract Size TrackBarDefaultSize{get; } // Default size for the TrackBar control
+
+ public abstract int TrackBarValueFromMousePosition (int x, int y, TrackBar tb);
+
+ public abstract bool TrackBarHasHotThumbStyle { get; }
+ #endregion // TrackBar
+
+ #region UpDownBase
+ public abstract void UpDownBaseDrawButton (Graphics g, Rectangle bounds, bool top, VisualStyles.PushButtonState state);
+ public abstract bool UpDownBaseHasHotButtonStyle { get; }
+ #endregion
+
+ #region VScrollBar
+ public abstract Size VScrollBarDefaultSize{get;} // Default size of the scrollbar
+ #endregion // VScrollBar
+
+ #region TreeView
+ public abstract Size TreeViewDefaultSize { get; }
+ public abstract void TreeViewDrawNodePlusMinus (TreeView treeView, TreeNode node, Graphics dc, int x, int middle);
+ #endregion
+
+ #region Managed window
+ public abstract void DrawManagedWindowDecorations (Graphics dc, Rectangle clip, InternalWindowManager wm);
+ public abstract int ManagedWindowTitleBarHeight (InternalWindowManager wm);
+ public abstract int ManagedWindowBorderWidth (InternalWindowManager wm);
+ public abstract int ManagedWindowIconWidth (InternalWindowManager wm);
+ public abstract Size ManagedWindowButtonSize (InternalWindowManager wm);
+ public abstract void ManagedWindowSetButtonLocations (InternalWindowManager wm);
+ public abstract Rectangle ManagedWindowGetTitleBarIconArea (InternalWindowManager wm);
+ public abstract Size ManagedWindowGetMenuButtonSize (InternalWindowManager wm);
+ public abstract bool ManagedWindowTitleButtonHasHotElementStyle (TitleButton button, Form form);
+ public abstract void ManagedWindowDrawMenuButton (Graphics dc, TitleButton button, Rectangle clip, InternalWindowManager wm);
+ public abstract void ManagedWindowOnSizeInitializedOrChanged (Form form);
+ public const int ManagedWindowSpacingAfterLastTitleButton = 2;
+ #endregion
+
+ #region WidgetPaint Methods
+ public abstract void CPDrawBorder (Graphics graphics, Rectangle bounds, Color leftColor, int leftWidth,
+ ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle,
+ Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor,
+ int bottomWidth, ButtonBorderStyle bottomStyle);
+
+ public abstract void CPDrawBorder (Graphics graphics, RectangleF bounds, Color leftColor, int leftWidth,
+ ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle,
+ Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor,
+ int bottomWidth, ButtonBorderStyle bottomStyle);
+
+ public abstract void CPDrawBorder3D (Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides);
+ public abstract void CPDrawBorder3D (Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides, Color control_color);
+ public abstract void CPDrawButton (Graphics graphics, Rectangle rectangle, ButtonState state);
+ public abstract void CPDrawCaptionButton (Graphics graphics, Rectangle rectangle, CaptionButton button, ButtonState state);
+ public abstract void CPDrawCheckBox (Graphics graphics, Rectangle rectangle, ButtonState state);
+ public abstract void CPDrawComboButton (Graphics graphics, Rectangle rectangle, ButtonState state);
+ public abstract void CPDrawContainerGrabHandle (Graphics graphics, Rectangle bounds);
+ public abstract void CPDrawFocusRectangle (Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor);
+ public abstract void CPDrawGrabHandle (Graphics graphics, Rectangle rectangle, bool primary, bool enabled);
+ public abstract void CPDrawGrid (Graphics graphics, Rectangle area, Size pixelsBetweenDots, Color backColor);
+ public abstract void CPDrawImageDisabled (Graphics graphics, Image image, int x, int y, Color background);
+ public abstract void CPDrawLockedFrame (Graphics graphics, Rectangle rectangle, bool primary);
+ public abstract void CPDrawMenuGlyph (Graphics graphics, Rectangle rectangle, MenuGlyph glyph, Color color, Color backColor);
+ public abstract void CPDrawMixedCheckBox (Graphics graphics, Rectangle rectangle, ButtonState state);
+ public abstract void CPDrawRadioButton (Graphics graphics, Rectangle rectangle, ButtonState state);
+ public abstract void CPDrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style);
+ public abstract void CPDrawReversibleLine (Point start, Point end, Color backColor);
+ public abstract void CPDrawScrollButton (Graphics graphics, Rectangle rectangle, ScrollButton button, ButtonState state);
+ public abstract void CPDrawSelectionFrame (Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect,
+ Color backColor);
+ public abstract void CPDrawSizeGrip (Graphics graphics, Color backColor, Rectangle bounds);
+ public abstract void CPDrawStringDisabled (Graphics graphics, string s, Font font, Color color, RectangleF layoutRectangle,
+ StringFormat format);
+ public abstract void CPDrawStringDisabled (IDeviceContext dc, string s, Font font, Color color, Rectangle layoutRectangle, TextFormatFlags format);
+ public abstract void CPDrawVisualStyleBorder (Graphics graphics, Rectangle bounds);
+ public abstract void CPDrawBorderStyle (Graphics dc, Rectangle area, BorderStyle border_style);
+ #endregion // WidgetPaint Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/Timer.cs b/source/ShiftUI/Internal/Timer.cs
new file mode 100644
index 0000000..e51c40d
--- /dev/null
+++ b/source/ShiftUI/Internal/Timer.cs
@@ -0,0 +1,170 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.Threading;
+using System.ComponentModel;
+
+namespace ShiftUI {
+ [DefaultProperty("Interval")]
+ [DefaultEvent("Tick")]
+ [ToolboxItemFilter("ShiftUI", ToolboxItemFilterType.Allow)]
+ public class Timer : Component {
+
+ private bool enabled;
+ private int interval = 100;
+ private DateTime expires;
+ internal Thread thread;
+ internal bool Busy;
+ internal IntPtr window;
+ object Widget_tag;
+
+ internal static readonly int Minimum = 15;
+
+ public Timer ()
+ {
+ enabled = false;
+ }
+
+ public Timer (IContainer container) : this ()
+ {
+ container.Add (this);
+ }
+
+ [DefaultValue (false)]
+ public virtual bool Enabled {
+ get {
+ return enabled;
+ }
+ set {
+ if (value != enabled) {
+ enabled = value;
+ if (value) {
+ // Use AddTicks so we get some rounding
+ expires = DateTime.UtcNow.AddMilliseconds (interval > Minimum ? interval : Minimum);
+
+ thread = Thread.CurrentThread;
+ XplatUI.SetTimer (this);
+ } else {
+ XplatUI.KillTimer (this);
+ thread = null;
+ }
+ }
+ }
+ }
+
+ [DefaultValue (100)]
+ public int Interval {
+ get {
+ return interval;
+ }
+ set {
+ if (value <= 0)
+ throw new ArgumentOutOfRangeException ("Interval", string.Format ("'{0}' is not a valid value for Interval. Interval must be greater than 0.", value));
+
+ if (interval == value) {
+ return;
+ }
+
+ interval = value;
+
+ // Use AddTicks so we get some rounding
+ expires = DateTime.UtcNow.AddMilliseconds (interval > Minimum ? interval : Minimum);
+
+ if (enabled == true) {
+ XplatUI.KillTimer (this);
+ XplatUI.SetTimer (this);
+ }
+ }
+ }
+
+ [Localizable(false)]
+ [Bindable(true)]
+ [TypeConverter(typeof(StringConverter))]
+ [DefaultValue(null)]
+ [MWFCategory("Data")]
+ public object Tag {
+ get {
+ return Widget_tag;
+ }
+
+ set {
+ Widget_tag = value;
+ }
+ }
+
+ public void Start ()
+ {
+ Enabled = true;
+ }
+
+ public void Stop ()
+ {
+ Enabled = false;
+ }
+
+ internal DateTime Expires {
+ get {
+ return expires;
+ }
+ }
+
+ public event EventHandler Tick;
+
+ public override string ToString ()
+ {
+ return base.ToString () + ", Interval: " + Interval;
+ }
+
+ internal void Update (DateTime update)
+ {
+ expires = update.AddMilliseconds (interval > Minimum ? interval : Minimum);
+ }
+
+ internal void FireTick ()
+ {
+ OnTick (EventArgs.Empty);
+ }
+
+
+ protected virtual void OnTick (EventArgs e)
+ {
+ if (Tick != null)
+ Tick (this, e);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ base.Dispose (disposing);
+ Enabled = false;
+ }
+
+ internal void TickHandler (object sender, EventArgs e)
+ {
+ OnTick (e);
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/ToolBarAppearance.cs b/source/ShiftUI/Internal/ToolBarAppearance.cs
new file mode 100644
index 0000000..ef3e110
--- /dev/null
+++ b/source/ShiftUI/Internal/ToolBarAppearance.cs
@@ -0,0 +1,40 @@
+//
+// ShiftUI.ToolBarAppearance.cs
+//
+// 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 Novell, Inc.
+//
+// Authors:
+// Ravindra ([email protected])
+//
+//
+
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public enum ToolBarAppearance
+ {
+ Normal = 0,
+ Flat = 1
+ }
+}
diff --git a/source/ShiftUI/Internal/ToolBarButtonStyle.cs b/source/ShiftUI/Internal/ToolBarButtonStyle.cs
new file mode 100644
index 0000000..fffcd99
--- /dev/null
+++ b/source/ShiftUI/Internal/ToolBarButtonStyle.cs
@@ -0,0 +1,41 @@
+//
+// ShiftUI.ToolBarButtonStyle.cs
+//
+// 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 Novell, Inc.
+//
+// Authors:
+// Ravindra ([email protected])
+//
+
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public enum ToolBarButtonStyle
+ {
+ PushButton = 1,
+ ToggleButton = 2,
+ Separator = 3,
+ DropDownButton =4
+ }
+}
diff --git a/source/ShiftUI/Internal/ToolBarTextAlign.cs b/source/ShiftUI/Internal/ToolBarTextAlign.cs
new file mode 100644
index 0000000..9850ca6
--- /dev/null
+++ b/source/ShiftUI/Internal/ToolBarTextAlign.cs
@@ -0,0 +1,39 @@
+//
+// ShiftUI.ToolBarTextAlign.cs
+//
+// 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 Novell, Inc.
+//
+// Authors:
+// Ravindra ([email protected])
+//
+
+
+// COMPLETE
+
+namespace ShiftUI
+{
+ public enum ToolBarTextAlign
+ {
+ Underneath = 0,
+ Right = 1
+ }
+}
diff --git a/source/ShiftUI/Internal/ToolTip.cs b/source/ShiftUI/Internal/ToolTip.cs
new file mode 100644
index 0000000..24895fb
--- /dev/null
+++ b/source/ShiftUI/Internal/ToolTip.cs
@@ -0,0 +1,1004 @@
+// 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 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+using System.Collections;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Text;
+using ShiftUI;
+using System;
+
+namespace ShiftUI {
+ [DefaultEvent ("Popup")]
+ [ProvideProperty ("ToolTip", typeof(Widget))]
+ [ToolboxItemFilter("ShiftUI", ToolboxItemFilterType.Allow)]
+ public class ToolTip : System.ComponentModel.Component, System.ComponentModel.IExtenderProvider {
+ #region Local variables
+ internal bool is_active;
+ internal int automatic_delay;
+ internal int autopop_delay;
+ internal int initial_delay;
+ internal int re_show_delay;
+ internal bool show_always;
+
+ internal Color back_color;
+ internal Color fore_color;
+
+ internal ToolTipWindow tooltip_window; // The actual tooltip window
+ internal Hashtable tooltip_strings; // List of strings for each Widget, indexed by Widget
+ internal ArrayList Widgets;
+ internal Widget active_Widget; // Widget for which the tooltip is currently displayed
+ internal Widget last_Widget; // last Widget the mouse was in
+ internal Timer timer; // Used for the various intervals
+ private Form hooked_form;
+
+ private bool isBalloon;
+ private bool owner_draw;
+ private bool stripAmpersands;
+ private ToolTipIcon tool_tip_icon;
+ private bool useAnimation;
+ private bool useFading;
+ private object tag;
+
+ #endregion // Local variables
+
+ #region ToolTipWindow Class
+ internal class ToolTipWindow : Widget {
+ #region ToolTipWindow Class Local Variables
+ private Widget associated_Widget;
+ internal Icon icon;
+ internal string title = String.Empty;
+ internal Rectangle icon_rect;
+ internal Rectangle title_rect;
+ internal Rectangle text_rect;
+ #endregion // ToolTipWindow Class Local Variables
+
+ #region ToolTipWindow Class Constructor
+ internal ToolTipWindow() {
+ Visible = false;
+ Size = new Size(100, 20);
+ ForeColor = ThemeEngine.Current.ColorInfoText;
+ BackColor = ThemeEngine.Current.ColorInfo;
+
+ VisibleChanged += new EventHandler(ToolTipWindow_VisibleChanged);
+
+ // UIA Framework: Used to generate UnPopup
+ VisibleChanged += new EventHandler (OnUIAToolTip_VisibleChanged);
+
+ SetStyle (Widgetstyles.UserPaint | Widgetstyles.AllPaintingInWmPaint, true);
+ SetStyle (Widgetstyles.ResizeRedraw, true);
+ if (ThemeEngine.Current.ToolTipTransparentBackground) {
+ SetStyle (Widgetstyles.SupportsTransparentBackColor, true);
+ BackColor = Color.Transparent;
+ } else
+ SetStyle (Widgetstyles.Opaque, true);
+ }
+
+ #endregion // ToolTipWindow Class Constructor
+
+ #region ToolTipWindow Class Protected Instance Methods
+ protected override void OnCreateWidget() {
+ base.OnCreateWidget ();
+ XplatUI.SetTopmost(this.window.Handle, true);
+ }
+
+ protected override CreateParams CreateParams {
+ get {
+ CreateParams cp;
+
+ cp = base.CreateParams;
+
+ cp.Style = (int)WindowStyles.WS_POPUP;
+ cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;
+
+ cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST);
+
+ return cp;
+ }
+ }
+
+ protected override void OnPaint(PaintEventArgs pevent) {
+ // We don't do double-buffering on purpose:
+ // 1) we'd have to meddle with is_visible, it destroys the buffers if !visible
+ // 2) We don't draw much, no need to double buffer
+ base.OnPaint(pevent);
+
+ OnDraw (new DrawToolTipEventArgs (pevent.Graphics, associated_Widget, associated_Widget, ClientRectangle, this.Text, this.BackColor, this.ForeColor, this.Font));
+ }
+
+ protected override void OnTextChanged (EventArgs args)
+ {
+ Invalidate ();
+ base.OnTextChanged (args);
+ }
+
+ protected override void WndProc(ref Message m) {
+ if (m.Msg == (int)Msg.WM_SETFOCUS) {
+ if (m.WParam != IntPtr.Zero) {
+ XplatUI.SetFocus(m.WParam);
+ }
+ }
+ base.WndProc (ref m);
+ }
+
+
+ #endregion // ToolTipWindow Class Protected Instance Methods
+
+ #region ToolTipWindow Class Private Methods
+ internal virtual void OnDraw (DrawToolTipEventArgs e)
+ {
+ DrawToolTipEventHandler eh = (DrawToolTipEventHandler)(Events[DrawEvent]);
+ if (eh != null)
+ eh (this, e);
+ else
+ ThemeEngine.Current.DrawToolTip (e.Graphics, e.Bounds, this);
+ }
+
+ internal virtual void OnPopup (PopupEventArgs e)
+ {
+ PopupEventHandler eh = (PopupEventHandler)(Events[PopupEvent]);
+ if (eh != null)
+ eh (this, e);
+ else
+ e.ToolTipSize = ThemeEngine.Current.ToolTipSize (this, Text);
+ }
+
+ private void ToolTipWindow_VisibleChanged(object sender, EventArgs e) {
+ Widget Widget = (Widget)sender;
+
+ if (Widget.is_visible) {
+ XplatUI.SetTopmost(Widget.window.Handle, true);
+ } else {
+ XplatUI.SetTopmost(Widget.window.Handle, false);
+ }
+ }
+
+ // UIA Framework
+ private void OnUIAToolTip_VisibleChanged (object sender, EventArgs e)
+ {
+ if (Visible == false)
+ OnUnPopup (new PopupEventArgs (associated_Widget, associated_Widget, false, Size.Empty));
+ }
+
+ private void OnUnPopup (PopupEventArgs e)
+ {
+ PopupEventHandler eh = (PopupEventHandler) (Events [UnPopupEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+
+ #endregion // ToolTipWindow Class Protected Instance Methods
+
+ #region Internal Properties
+ internal override bool ActivateOnShow { get { return false; } }
+ #endregion
+
+ // This Present is used when we are using the expicit Show methods for 2.0.
+ // It will not reposition the window.
+ public void PresentModal (Widget Widget, string text)
+ {
+ if (IsDisposed)
+ return;
+
+ Size display_size;
+ XplatUI.GetDisplaySize (out display_size);
+
+ associated_Widget = Widget;
+
+ Text = text;
+
+ PopupEventArgs pea = new PopupEventArgs (Widget, Widget, false, Size.Empty);
+ OnPopup (pea);
+
+ if (pea.Cancel)
+ return;
+
+ Size = pea.ToolTipSize;
+
+ Visible = true;
+ }
+
+ public void Present (Widget Widget, string text)
+ {
+ if (IsDisposed)
+ return;
+
+ Size display_size;
+ XplatUI.GetDisplaySize (out display_size);
+
+ associated_Widget = Widget;
+
+ Text = text;
+
+ PopupEventArgs pea = new PopupEventArgs (Widget, Widget, false, Size.Empty);
+ OnPopup (pea);
+
+ if (pea.Cancel)
+ return;
+
+ Size size = pea.ToolTipSize;
+
+ Width = size.Width;
+ Height = size.Height;
+
+ int cursor_w, cursor_h, hot_x, hot_y;
+ XplatUI.GetCursorInfo (Widget.Cursor.Handle, out cursor_w, out cursor_h, out hot_x, out hot_y);
+ Point loc = Widget.MousePosition;
+ loc.Y += (cursor_h - hot_y);
+
+ if ((loc.X + Width) > display_size.Width)
+ loc.X = display_size.Width - Width;
+
+ if ((loc.Y + Height) > display_size.Height)
+ loc.Y = Widget.MousePosition.Y - Height - hot_y;
+
+ Location = loc;
+ Visible = true;
+ BringToFront ();
+ }
+
+
+ #region Internal Events
+ static object DrawEvent = new object ();
+ static object PopupEvent = new object ();
+
+ // UIA Framework
+ static object UnPopupEvent = new object ();
+
+ public event DrawToolTipEventHandler Draw {
+ add { Events.AddHandler (DrawEvent, value); }
+ remove { Events.RemoveHandler (DrawEvent, value); }
+ }
+
+ public event PopupEventHandler Popup {
+ add { Events.AddHandler (PopupEvent, value); }
+ remove { Events.RemoveHandler (PopupEvent, value); }
+ }
+
+ internal event PopupEventHandler UnPopup {
+ add { Events.AddHandler (UnPopupEvent, value); }
+ remove { Events.RemoveHandler (UnPopupEvent, value); }
+ }
+ #endregion
+ }
+ #endregion // ToolTipWindow Class
+
+ #region Public Constructors & Destructors
+ public ToolTip() {
+
+ // Defaults from MS
+ is_active = true;
+ automatic_delay = 500;
+ autopop_delay = 5000;
+ initial_delay = 500;
+ re_show_delay = 100;
+ show_always = false;
+ back_color = SystemColors.Info;
+ fore_color = SystemColors.InfoText;
+
+ isBalloon = false;
+ stripAmpersands = false;
+ useAnimation = true;
+ useFading = true;
+ tooltip_strings = new Hashtable(5);
+ Widgets = new ArrayList(5);
+
+ tooltip_window = new ToolTipWindow();
+ tooltip_window.MouseLeave += new EventHandler(Widget_MouseLeave);
+ tooltip_window.Draw += new DrawToolTipEventHandler (tooltip_window_Draw);
+ tooltip_window.Popup += new PopupEventHandler (tooltip_window_Popup);
+
+ // UIA Framework: Static event handlers
+ tooltip_window.UnPopup += delegate (object sender, PopupEventArgs args) {
+ OnUnPopup (args);
+ };
+ UnPopup += new PopupEventHandler (OnUIAUnPopup);
+
+ timer = new Timer();
+ timer.Enabled = false;
+ timer.Tick +=new EventHandler(timer_Tick);
+
+ }
+
+
+ #region UIA Framework: Events, Delegates and Methods
+ // NOTE:
+ // We are using Reflection to add/remove internal events.
+ // Class ToolTipListener uses the events.
+ //
+ // - UIAUnPopup. Event used to generate ChildRemoved in ToolTip
+ // - UIAToolTipHookUp. Event used to keep track of associated Widgets
+ // - UIAToolTipUnhookUp. Event used to remove track of associated Widgets
+ static object UnPopupEvent = new object ();
+
+ internal event PopupEventHandler UnPopup {
+ add { Events.AddHandler (UnPopupEvent, value); }
+ remove { Events.RemoveHandler (UnPopupEvent, value); }
+ }
+
+ internal static event PopupEventHandler UIAUnPopup;
+ internal static event WidgetEventHandler UIAToolTipHookUp;
+ internal static event WidgetEventHandler UIAToolTipUnhookUp;
+
+ internal Rectangle UIAToolTipRectangle {
+ get { return tooltip_window.Bounds; }
+ }
+
+ internal static void OnUIAUnPopup (object sender, PopupEventArgs args)
+ {
+ if (UIAUnPopup != null)
+ UIAUnPopup (sender, args);
+ }
+
+ internal static void OnUIAToolTipHookUp (object sender, WidgetEventArgs args)
+ {
+ if (UIAToolTipHookUp != null)
+ UIAToolTipHookUp (sender, args);
+ }
+
+ internal static void OnUIAToolTipUnhookUp (object sender, WidgetEventArgs args)
+ {
+ if (UIAToolTipUnhookUp != null)
+ UIAToolTipUnhookUp (sender, args);
+ }
+
+ #endregion
+
+ public ToolTip(System.ComponentModel.IContainer cont) : this() {
+ cont.Add (this);
+ }
+
+ ~ToolTip() {
+ }
+ #endregion // Public Constructors & Destructors
+
+ #region Public Instance Properties
+ [DefaultValue (true)]
+ public bool Active {
+ get {
+ return is_active;
+ }
+
+ set {
+ if (is_active != value) {
+ is_active = value;
+
+ if (tooltip_window.Visible) {
+ tooltip_window.Visible = false;
+ active_Widget = null;
+ }
+ }
+ }
+ }
+
+ [DefaultValue (500)]
+ [RefreshProperties (RefreshProperties.All)]
+ public int AutomaticDelay {
+ get {
+ return automatic_delay;
+ }
+
+ set {
+ if (automatic_delay != value) {
+ automatic_delay = value;
+ autopop_delay = automatic_delay * 10;
+ initial_delay = automatic_delay;
+ re_show_delay = automatic_delay / 5;
+ }
+ }
+ }
+
+ [RefreshProperties (RefreshProperties.All)]
+ public int AutoPopDelay {
+ get {
+ return autopop_delay;
+ }
+
+ set {
+ if (autopop_delay != value) {
+ autopop_delay = value;
+ }
+ }
+ }
+
+ [DefaultValue ("Color [Info]")]
+ public Color BackColor {
+ get { return this.back_color; }
+ set { this.back_color = value; tooltip_window.BackColor = value; }
+ }
+
+ [DefaultValue ("Color [InfoText]")]
+ public Color ForeColor
+ {
+ get { return this.fore_color; }
+ set { this.fore_color = value; tooltip_window.ForeColor = value; }
+ }
+
+ [RefreshProperties (RefreshProperties.All)]
+ public int InitialDelay {
+ get {
+ return initial_delay;
+ }
+
+ set {
+ if (initial_delay != value) {
+ initial_delay = value;
+ }
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool OwnerDraw {
+ get { return this.owner_draw; }
+ set { this.owner_draw = value; }
+ }
+
+ [RefreshProperties (RefreshProperties.All)]
+ public int ReshowDelay {
+ get {
+ return re_show_delay;
+ }
+
+ set {
+ if (re_show_delay != value) {
+ re_show_delay = value;
+ }
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool ShowAlways {
+ get {
+ return show_always;
+ }
+
+ set {
+ if (show_always != value) {
+ show_always = value;
+ }
+ }
+ }
+
+
+ [DefaultValue (false)]
+ public bool IsBalloon {
+ get { return isBalloon; }
+ set { isBalloon = value; }
+ }
+
+ [Browsable (true)]
+ [DefaultValue (false)]
+ public bool StripAmpersands {
+ get { return stripAmpersands; }
+ set { stripAmpersands = value; }
+ }
+
+ [Localizable (false)]
+ [Bindable (true)]
+ [TypeConverter (typeof (StringConverter))]
+ [DefaultValue (null)]
+ public object Tag {
+ get { return tag; }
+ set { tag = value; }
+ }
+
+ [DefaultValue (ToolTipIcon.None)]
+ public ToolTipIcon ToolTipIcon {
+ get { return this.tool_tip_icon; }
+ set {
+ switch (value) {
+ case ToolTipIcon.None:
+ tooltip_window.icon = null;
+ break;
+ case ToolTipIcon.Error:
+ tooltip_window.icon = SystemIcons.Error;
+ break;
+ case ToolTipIcon.Warning:
+ tooltip_window.icon = SystemIcons.Warning;
+ break;
+ case ToolTipIcon.Info:
+ tooltip_window.icon = SystemIcons.Information;
+ break;
+ }
+
+ tool_tip_icon = value;
+ }
+ }
+
+ [DefaultValue ("")]
+ public string ToolTipTitle {
+ get { return tooltip_window.title; }
+ set {
+ if (value == null)
+ value = String.Empty;
+
+ tooltip_window.title = value;
+ }
+ }
+
+ [Browsable (true)]
+ [DefaultValue (true)]
+ public bool UseAnimation {
+ get { return useAnimation; }
+ set { useAnimation = value; }
+ }
+
+ [Browsable (true)]
+ [DefaultValue (true)]
+ public bool UseFading {
+ get { return useFading; }
+ set { useFading = value; }
+ }
+
+ #endregion // Public Instance Properties
+
+ #region Protected Properties
+ protected virtual CreateParams CreateParams
+ {
+ get
+ {
+ CreateParams cp = new CreateParams ();
+
+ cp.Style = 2;
+
+ return cp;
+ }
+ }
+ #endregion
+
+ #region Public Instance Methods
+ public bool CanExtend(object target) {
+ return false;
+ }
+
+ [Localizable (true)]
+ [DefaultValue ("")]
+ public string GetToolTip (Widget Widget)
+ {
+ string tooltip = (string)tooltip_strings[Widget];
+ if (tooltip == null)
+ return "";
+ return tooltip;
+ }
+
+ public void RemoveAll() {
+ tooltip_strings.Clear();
+ //UIA Framework: ToolTip isn't associated anymore
+ foreach (Widget Widget in Widgets)
+ OnUIAToolTipUnhookUp (this, new WidgetEventArgs (Widget));
+
+ Widgets.Clear();
+ }
+
+ public void SetToolTip(Widget Widget, string caption) {
+ // UIA Framework
+ OnUIAToolTipHookUp (this, new WidgetEventArgs (Widget));
+ tooltip_strings[Widget] = caption;
+
+ // no need for duplicates
+ if (!Widgets.Contains(Widget)) {
+ Widget.MouseEnter += new EventHandler(Widget_MouseEnter);
+ Widget.MouseMove += new MouseEventHandler(Widget_MouseMove);
+ Widget.MouseLeave += new EventHandler(Widget_MouseLeave);
+ Widget.MouseDown += new MouseEventHandler (Widget_MouseDown);
+ Widgets.Add(Widget);
+ }
+
+ // if SetToolTip is called from a Widget and the mouse is currently over that Widget,
+ // make sure that tooltip_window.Text gets updated if it's being shown,
+ // or show the tooltip for it if is not
+ if (active_Widget == Widget && caption != null && state == TipState.Show) {
+ Size size = ThemeEngine.Current.ToolTipSize(tooltip_window, caption);
+ tooltip_window.Width = size.Width;
+ tooltip_window.Height = size.Height;
+ tooltip_window.Text = caption;
+ timer.Stop ();
+ timer.Start ();
+ } else if (Widget.IsHandleCreated && MouseInWidget (Widget, false))
+ ShowTooltip (Widget);
+ }
+
+ public override string ToString() {
+ return base.ToString() + " InitialDelay: " + initial_delay + ", ShowAlways: " + show_always;
+ }
+
+ public void Show (string text, IWin32Window window)
+ {
+ Show (text, window, 0);
+ }
+
+ public void Show (string text, IWin32Window window, int duration)
+ {
+ if (window == null)
+ throw new ArgumentNullException ("window");
+ if (duration < 0)
+ throw new ArgumentOutOfRangeException ("duration", "duration cannot be less than zero");
+
+ if (!Active)
+ return;
+
+ timer.Stop ();
+
+ Widget c = (Widget)window;
+
+ XplatUI.SetOwner (tooltip_window.Handle, c.TopLevelWidget.Handle);
+
+ // If the mouse is in the requested window, use that position
+ // Else, center in the requested window
+ if (c.ClientRectangle.Contains (c.PointToClient (Widget.MousePosition))) {
+ tooltip_window.Location = Widget.MousePosition;
+ tooltip_strings[c] = text;
+ HookupWidgetEvents (c);
+ }
+ else
+ tooltip_window.Location = c.PointToScreen (new Point (c.Width / 2, c.Height / 2));
+
+ // We need to hide our tooltip if the form loses focus, is closed, or is minimized
+ HookupFormEvents ((Form)c.TopLevelWidget);
+
+ tooltip_window.PresentModal ((Widget)window, text);
+
+ state = TipState.Show;
+
+ if (duration > 0) {
+ timer.Interval = duration;
+ timer.Start ();
+ }
+ }
+
+ public void Show (string text, IWin32Window window, Point point)
+ {
+ Show (text, window, point, 0);
+ }
+
+ public void Show (string text, IWin32Window window, int x, int y)
+ {
+ Show (text, window, new Point (x, y), 0);
+ }
+
+ public void Show (string text, IWin32Window window, Point point, int duration)
+ {
+ if (window == null)
+ throw new ArgumentNullException ("window");
+ if (duration < 0)
+ throw new ArgumentOutOfRangeException ("duration", "duration cannot be less than zero");
+
+ if (!Active)
+ return;
+
+ timer.Stop ();
+
+ Widget c = (Widget)window;
+
+ Point display_point = c.PointToScreen (Point.Empty);
+ display_point.X += point.X;
+ display_point.Y += point.Y;
+
+ XplatUI.SetOwner (tooltip_window.Handle, c.TopLevelWidget.Handle);
+
+ // We need to hide our tooltip if the form loses focus, is closed, or is minimized
+ HookupFormEvents ((Form)c.TopLevelWidget);
+
+ tooltip_window.Location = display_point;
+ tooltip_window.PresentModal ((Widget)window, text);
+
+ state = TipState.Show;
+
+ if (duration > 0) {
+ timer.Interval = duration;
+ timer.Start ();
+ }
+ }
+
+ public void Show (string text, IWin32Window window, int x, int y, int duration)
+ {
+ Show (text, window, new Point (x, y), duration);
+ }
+
+ public void Hide (IWin32Window win)
+ {
+ timer.Stop ();
+ state = TipState.Initial;
+
+ UnhookFormEvents ();
+ tooltip_window.Visible = false;
+ }
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+ protected override void Dispose(bool disposing) {
+ // call the base impl first to avoid conflicts with any parent's events
+ base.Dispose (disposing);
+
+ if (disposing) {
+ // Mop up the mess; or should we wait for the GC to kick in?
+ timer.Stop();
+ timer.Dispose();
+
+ // Not sure if we should clean up tooltip_window
+ tooltip_window.Dispose();
+
+ tooltip_strings.Clear();
+
+ //UIA Framework: ToolTip isn't associated anymore
+ foreach (Widget Widget in Widgets)
+ OnUIAToolTipUnhookUp (this, new WidgetEventArgs (Widget));
+ Widgets.Clear();
+ }
+ }
+
+ protected void StopTimer ()
+ {
+ timer.Stop ();
+ }
+ #endregion // Protected Instance Methods
+
+ internal enum TipState {
+ Initial,
+ Show,
+ Down
+ }
+
+ TipState state = TipState.Initial;
+
+ #region Private Methods
+
+ private void HookupFormEvents (Form form)
+ {
+ hooked_form = form;
+
+ form.Deactivate += new EventHandler (Form_Deactivate);
+ form.Closed += new EventHandler (Form_Closed);
+ form.Resize += new EventHandler (Form_Resize);
+ }
+
+ private void HookupWidgetEvents (Widget widget)
+ {
+ if (!Widgets.Contains (widget)) {
+ widget.MouseEnter += new EventHandler (Widget_MouseEnter);
+ widget.MouseMove += new MouseEventHandler (Widget_MouseMove);
+ widget.MouseLeave += new EventHandler (Widget_MouseLeave);
+ widget.MouseDown += new MouseEventHandler (Widget_MouseDown);
+ Widgets.Add (widget);
+ }
+ }
+
+ private void UnhookWidgetEvents (Widget widget)
+ {
+ widget.MouseEnter -= new EventHandler (Widget_MouseEnter);
+ widget.MouseMove -= new MouseEventHandler (Widget_MouseMove);
+ widget.MouseLeave -= new EventHandler (Widget_MouseLeave);
+ widget.MouseDown -= new MouseEventHandler (Widget_MouseDown);
+ }
+ private void UnhookFormEvents ()
+ {
+ if (hooked_form == null)
+ return;
+
+ hooked_form.Deactivate -= new EventHandler (Form_Deactivate);
+ hooked_form.Closed -= new EventHandler (Form_Closed);
+ hooked_form.Resize -= new EventHandler (Form_Resize);
+
+ hooked_form = null;
+ }
+
+
+ private void Form_Resize (object sender, EventArgs e)
+ {
+ Form f = (Form)sender;
+
+ if (f.WindowState == FormWindowState.Minimized)
+ tooltip_window.Visible = false;
+ }
+
+ private void Form_Closed (object sender, EventArgs e)
+ {
+ tooltip_window.Visible = false;
+ }
+
+ private void Form_Deactivate (object sender, EventArgs e)
+ {
+ tooltip_window.Visible = false;
+ }
+
+ internal void Present (Widget Widget, string text)
+ {
+ tooltip_window.Present (Widget, text);
+ }
+
+ private void Widget_MouseEnter (object sender, EventArgs e)
+ {
+ ShowTooltip (sender as Widget);
+ }
+
+ private void ShowTooltip (Widget Widget)
+ {
+ last_Widget = Widget;
+
+ // Whatever we're displaying right now, we don't want it anymore
+ tooltip_window.Visible = false;
+ timer.Stop();
+ state = TipState.Initial;
+
+ if (!is_active)
+ return;
+
+ // ShowAlways Widgets whether the Widgets in non-active forms
+ // can display its tooltips, even if they are not current active Widget.
+ if (!show_always && Widget.FindForm () != Form.ActiveForm)
+ return;
+
+ string text = (string)tooltip_strings[Widget];
+ if (text != null && text.Length > 0) {
+ if (active_Widget == null) {
+ timer.Interval = Math.Max (initial_delay, 1);
+ } else {
+ timer.Interval = Math.Max (re_show_delay, 1);
+ }
+
+ active_Widget = Widget;
+ timer.Start ();
+ }
+ }
+
+ private void timer_Tick(object sender, EventArgs e) {
+ timer.Stop();
+
+ switch (state) {
+ case TipState.Initial:
+ if (active_Widget == null)
+ return;
+ tooltip_window.Present (active_Widget, (string)tooltip_strings[active_Widget]);
+ state = TipState.Show;
+ timer.Interval = autopop_delay;
+ timer.Start();
+ break;
+
+ case TipState.Show:
+ tooltip_window.Visible = false;
+ state = TipState.Down;
+ break;
+
+ default:
+ throw new Exception ("Timer shouldn't be running in state: " + state);
+ }
+ }
+
+ private void tooltip_window_Popup (object sender, PopupEventArgs e)
+ {
+ e.ToolTipSize = ThemeEngine.Current.ToolTipSize (tooltip_window, tooltip_window.Text);
+ OnPopup (e);
+ }
+
+ private void tooltip_window_Draw (object sender, DrawToolTipEventArgs e)
+ {
+ if (OwnerDraw)
+ OnDraw (e);
+ else
+ ThemeEngine.Current.DrawToolTip (e.Graphics, e.Bounds, tooltip_window);
+ }
+
+ private bool MouseInWidget (Widget Widget, bool fuzzy) {
+ Point m;
+ Point c;
+ Size cw;
+
+ if (Widget == null) {
+ return false;
+ }
+
+ m = Widget.MousePosition;
+ c = new Point(Widget.Bounds.X, Widget.Bounds.Y);
+ if (Widget.Parent != null) {
+ c = Widget.Parent.PointToScreen(c);
+ }
+ cw = Widget.ClientSize;
+
+
+ Rectangle rect = new Rectangle (c, cw);
+
+ //
+ // We won't get mouse move events on all platforms with the exact same
+ // frequency, so cheat a bit.
+ if (fuzzy)
+ rect.Inflate (2, 2);
+
+ return rect.Contains (m);
+ }
+
+ private void Widget_MouseLeave(object sender, EventArgs e)
+ {
+ timer.Stop ();
+
+ active_Widget = null;
+ tooltip_window.Visible = false;
+
+ if (last_Widget == sender)
+ last_Widget = null;
+ }
+
+
+ void Widget_MouseDown (object sender, MouseEventArgs e)
+ {
+ timer.Stop();
+
+ active_Widget = null;
+ tooltip_window.Visible = false;
+
+ if (last_Widget == sender)
+ last_Widget = null;
+ }
+
+ private void Widget_MouseMove(object sender, MouseEventArgs e) {
+ if (state != TipState.Down) {
+ timer.Stop();
+ timer.Start();
+ }
+ }
+
+ internal void OnDraw (DrawToolTipEventArgs e)
+ {
+ DrawToolTipEventHandler eh = (DrawToolTipEventHandler)(Events[DrawEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ internal void OnPopup (PopupEventArgs e)
+ {
+ PopupEventHandler eh = (PopupEventHandler) (Events [PopupEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ internal void OnUnPopup (PopupEventArgs e)
+ {
+ PopupEventHandler eh = (PopupEventHandler) (Events [UnPopupEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ internal bool Visible {
+ get { return tooltip_window.Visible; }
+ }
+ #endregion // Private Methods
+
+ #region Events
+ static object PopupEvent = new object ();
+ static object DrawEvent = new object ();
+
+ public event PopupEventHandler Popup {
+ add { Events.AddHandler (PopupEvent, value); }
+ remove { Events.RemoveHandler (PopupEvent, value); }
+ }
+
+ public event DrawToolTipEventHandler Draw {
+ add { Events.AddHandler (DrawEvent, value); }
+ remove { Events.RemoveHandler (DrawEvent, value); }
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/ToolTipIcon.cs b/source/ShiftUI/Internal/ToolTipIcon.cs
new file mode 100644
index 0000000..2adcca8
--- /dev/null
+++ b/source/ShiftUI/Internal/ToolTipIcon.cs
@@ -0,0 +1,39 @@
+//
+// ToolTipIcon.cs
+//
+// 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) 2006 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+
+namespace ShiftUI
+{
+ public enum ToolTipIcon
+ {
+ None = 0,
+ Info = 1,
+ Warning = 2,
+ Error = 3
+ }
+}
diff --git a/source/ShiftUI/Internal/ToolWindowManager.cs b/source/ShiftUI/Internal/ToolWindowManager.cs
new file mode 100644
index 0000000..ba080d7
--- /dev/null
+++ b/source/ShiftUI/Internal/ToolWindowManager.cs
@@ -0,0 +1,47 @@
+// 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) 2007 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Rolf Bjarne Kvinge ([email protected])
+//
+//
+
+
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI
+{
+ internal class ToolWindowManager : InternalWindowManager
+ {
+ public ToolWindowManager (Form form)
+ : base (form)
+ {
+
+ }
+
+ public override void SetWindowState (FormWindowState old_state, FormWindowState window_state)
+ {
+ // Do nothing here.
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/TreeNodeCollection.cs b/source/ShiftUI/Internal/TreeNodeCollection.cs
new file mode 100644
index 0000000..5323579
--- /dev/null
+++ b/source/ShiftUI/Internal/TreeNodeCollection.cs
@@ -0,0 +1,611 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Globalization;
+using System.Collections.Generic;
+
+namespace ShiftUI {
+ //[Editor("ShiftUI.Design.TreeNodeCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
+ public class TreeNodeCollection : IList, ICollection, IEnumerable {
+
+ private static readonly int OrigSize = 50;
+
+ private TreeNode owner;
+ private int count;
+ private TreeNode [] nodes;
+
+ private TreeNodeCollection ()
+ {
+ }
+
+ internal TreeNodeCollection (TreeNode owner)
+ {
+ this.owner = owner;
+ nodes = new TreeNode [OrigSize];
+ }
+
+ [Browsable(false)]
+ public int Count {
+ get { return count; }
+ }
+
+ public bool IsReadOnly {
+ get { return false; }
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false; }
+ }
+
+ object ICollection.SyncRoot {
+ get { return this; }
+ }
+
+ bool IList.IsFixedSize {
+ get { return false; }
+ }
+
+ object IList.this [int index] {
+ get {
+ return this [index];
+ }
+ set {
+ if (!(value is TreeNode))
+ throw new ArgumentException ("Parameter must be of type TreeNode.", "value");
+ this [index] = (TreeNode) value;
+ }
+ }
+
+ public virtual TreeNode this [int index] {
+ get {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException ("index");
+ return nodes [index];
+ }
+ set {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException ("index");
+ SetupNode (value);
+ nodes [index] = value;
+ }
+ }
+
+ public virtual TreeNode this [string key] {
+ get {
+ for (int i = 0; i < count; i++)
+ if (string.Compare (key, nodes[i].Name, true) == 0)
+ return nodes[i];
+
+ return null;
+ }
+ }
+
+ bool UsingSorting {
+ get {
+ TreeView tv = owner == null ? null : owner.TreeView;
+ return tv != null && (tv.Sorted || tv.TreeViewNodeSorter != null);
+ }
+ }
+
+ public virtual TreeNode Add (string text)
+ {
+ TreeNode res = new TreeNode (text);
+ Add (res);
+ return res;
+ }
+
+ public virtual int Add (TreeNode node)
+ {
+ if (node == null)
+ throw new ArgumentNullException("node");
+
+ int index;
+ TreeView tree_view = null;
+
+ if (owner != null)
+ tree_view = owner.TreeView;
+
+ if (tree_view != null && UsingSorting) {
+ index = AddSorted (node);
+ } else {
+ if (count >= nodes.Length)
+ Grow ();
+ index = count;
+ count++;
+ nodes[index] = node;
+ }
+
+ SetupNode (node);
+
+ // UIA Framework Event: Collection Changed
+ if (tree_view != null)
+ tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Add, node));
+ return index;
+ }
+
+ public virtual TreeNode Add (string key, string text)
+ {
+ TreeNode node = new TreeNode (text);
+ node.Name = key;
+ Add (node);
+ return node;
+ }
+
+ public virtual TreeNode Add (string key, string text, int imageIndex)
+ {
+ TreeNode node = Add (key, text);
+ node.ImageIndex = imageIndex;
+ return node;
+ }
+
+ public virtual TreeNode Add (string key, string text, string imageKey)
+ {
+ TreeNode node = Add (key, text);
+ node.ImageKey = imageKey;
+ return node;
+
+ }
+
+ public virtual TreeNode Add (string key, string text, int imageIndex, int selectedImageIndex)
+ {
+ TreeNode node = Add (key, text);
+ node.ImageIndex = imageIndex;
+ node.SelectedImageIndex = selectedImageIndex;
+ return node;
+ }
+
+ public virtual TreeNode Add (string key, string text, string imageKey, string selectedImageKey)
+ {
+ TreeNode node = Add (key, text);
+ node.ImageKey = imageKey;
+ node.SelectedImageKey = selectedImageKey;
+ return node;
+ }
+
+ public virtual void AddRange (TreeNode [] nodes)
+ {
+ if (nodes == null)
+ throw new ArgumentNullException("nodes");
+
+ // We can't just use Array.Copy because the nodes also
+ // need to have some properties set when they are added.
+ for (int i = 0; i < nodes.Length; i++)
+ Add (nodes [i]);
+ }
+
+ public virtual void Clear ()
+ {
+ while (count > 0)
+ RemoveAt (0, false);
+
+ Array.Clear (nodes, 0, count);
+ count = 0;
+
+ TreeView tree_view = null;
+ if (owner != null) {
+ tree_view = owner.TreeView;
+ if (tree_view != null) {
+ tree_view.UpdateBelow (owner);
+ tree_view.RecalculateVisibleOrder (owner);
+ tree_view.UpdateScrollBars (false);
+ }
+ }
+ }
+
+ public bool Contains (TreeNode node)
+ {
+ return Array.IndexOf (nodes, node, 0, count) != -1;
+ }
+
+ public virtual bool ContainsKey (string key)
+ {
+ for (int i = 0; i < count; i++) {
+ if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0)
+ return true;
+ }
+ return false;
+ }
+
+ public void CopyTo (Array dest, int index)
+ {
+ Array.Copy (nodes, index, dest, index, count);
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return new TreeNodeEnumerator (this);
+ }
+
+ public int IndexOf (TreeNode node)
+ {
+ return Array.IndexOf (nodes, node);
+ }
+
+ public virtual int IndexOfKey (string key)
+ {
+ for (int i = 0; i < count; i++) {
+ if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0)
+ return i;
+ }
+ return -1;
+ }
+
+ public virtual TreeNode Insert (int index, string text)
+ {
+ TreeNode node = new TreeNode (text);
+ Insert (index, node);
+ return node;
+ }
+
+ public virtual void Insert (int index, TreeNode node)
+ {
+ if (count >= nodes.Length)
+ Grow ();
+
+ Array.Copy (nodes, index, nodes, index + 1, count - index);
+ nodes [index] = node;
+ count++;
+
+ // If we can use sorting, it means we have an owner *and* a TreeView
+ if (UsingSorting)
+ Sort (owner.TreeView.TreeViewNodeSorter);
+
+ SetupNode (node);
+ }
+
+ public virtual TreeNode Insert (int index, string key, string text)
+ {
+ TreeNode node = new TreeNode (text);
+ node.Name = key;
+ Insert (index, node);
+ return node;
+ }
+
+ public virtual TreeNode Insert (int index, string key, string text, int imageIndex)
+ {
+ TreeNode node = new TreeNode (text);
+ node.Name = key;
+ node.ImageIndex = imageIndex;
+ Insert (index, node);
+ return node;
+ }
+
+ public virtual TreeNode Insert (int index, string key, string text, string imageKey)
+ {
+ TreeNode node = new TreeNode (text);
+ node.Name = key;
+ node.ImageKey = imageKey;
+ Insert (index, node);
+ return node;
+ }
+
+ public virtual TreeNode Insert (int index, string key, string text, int imageIndex, int selectedImageIndex)
+ {
+ TreeNode node = new TreeNode (text, imageIndex, selectedImageIndex);
+ node.Name = key;
+ Insert (index, node);
+ return node;
+ }
+
+ public virtual TreeNode Insert (int index, string key, string text, string imageKey, string selectedImageKey)
+ {
+ TreeNode node = new TreeNode (text);
+ node.Name = key;
+ node.ImageKey = imageKey;
+ node.SelectedImageKey = selectedImageKey;
+ Insert (index, node);
+ return node;
+ }
+
+ public void Remove (TreeNode node)
+ {
+ if (node == null)
+ throw new NullReferenceException ();
+
+ int index = IndexOf (node);
+ if (index != -1)
+ RemoveAt (index);
+ }
+
+ public virtual void RemoveAt (int index)
+ {
+ RemoveAt (index, true);
+ }
+
+ private void RemoveAt (int index, bool update)
+ {
+ TreeNode removed = nodes [index];
+ TreeNode prev = GetPrevNode (removed);
+ TreeNode new_selected = null;
+ bool re_set_selected = false;
+ bool visible = removed.IsVisible;
+
+ TreeView tree_view = null;
+ if (owner != null)
+ tree_view = owner.TreeView;
+
+ if (tree_view != null) {
+ tree_view.RecalculateVisibleOrder (prev);
+
+ if (removed == tree_view.SelectedNode) {
+ if (removed.IsExpanded)
+ removed.Collapse(); // Fix Xamarin Bugzilla 5010.
+ re_set_selected = true;
+ OpenTreeNodeEnumerator oe = new OpenTreeNodeEnumerator (removed);
+ if (oe.MoveNext () && oe.MoveNext ()) {
+ new_selected = oe.CurrentNode;
+ } else {
+ oe = new OpenTreeNodeEnumerator (removed);
+ oe.MovePrevious ();
+ new_selected = oe.CurrentNode == removed ? null : oe.CurrentNode;
+ }
+ }
+ }
+
+ Array.Copy (nodes, index + 1, nodes, index, count - index - 1);
+ count--;
+
+ nodes[count] = null;
+
+ if (nodes.Length > OrigSize && nodes.Length > (count * 2))
+ Shrink ();
+
+ if (tree_view != null && re_set_selected) {
+ tree_view.SelectedNode = new_selected;
+ }
+
+ TreeNode parent = removed.parent;
+ removed.parent = null;
+
+ if (update && tree_view != null && visible) {
+ tree_view.RecalculateVisibleOrder (prev);
+ tree_view.UpdateScrollBars (false);
+ tree_view.UpdateBelow (parent);
+ }
+
+ // UIA Framework Event: Collection Changed
+ if (tree_view != null)
+ tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed));
+ }
+
+ public virtual void RemoveByKey (string key)
+ {
+ TreeNode node = this[key];
+
+ if (node != null)
+ Remove (node);
+ }
+
+ private TreeNode GetPrevNode (TreeNode node)
+ {
+ OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (node);
+
+ if (one.MovePrevious () && one.MovePrevious ())
+ return one.CurrentNode;
+ return null;
+ }
+
+ private void SetupNode (TreeNode node)
+ {
+ // We used to remove this from the previous parent, but .Net
+ // skips this step (even if setting the owner field).
+ //node.Remove ();
+
+ node.parent = owner;
+
+ TreeView tree_view = null;
+ if (owner != null)
+ tree_view = owner.TreeView;
+
+ if (tree_view != null) {
+ // We may need to invalidate this entire node collection if sorted.
+ TreeNode prev = UsingSorting ? owner : GetPrevNode (node);
+
+ if (tree_view.IsHandleCreated && node.ArePreviousNodesExpanded)
+ tree_view.RecalculateVisibleOrder (prev);
+ if (owner == tree_view.root_node || node.Parent.IsVisible && node.Parent.IsExpanded)
+ tree_view.UpdateScrollBars (false);
+
+ tree_view.UpdateBelow (owner);
+ }
+ }
+
+ int IList.Add (object node)
+ {
+ return Add ((TreeNode) node);
+ }
+
+ bool IList.Contains (object node)
+ {
+ return Contains ((TreeNode) node);
+ }
+
+ int IList.IndexOf (object node)
+ {
+ return IndexOf ((TreeNode) node);
+ }
+
+ void IList.Insert (int index, object node)
+ {
+ Insert (index, (TreeNode) node);
+ }
+
+ void IList.Remove (object node)
+ {
+ Remove ((TreeNode) node);
+ }
+
+ private int AddSorted (TreeNode node)
+ {
+ if (count >= nodes.Length)
+ Grow ();
+
+ TreeView tree_view = owner.TreeView;
+ if (tree_view.TreeViewNodeSorter != null) { // Custom sorting
+ nodes [count++] = node;
+ Sort (tree_view.TreeViewNodeSorter);
+ return count - 1;
+ }
+
+ CompareInfo compare = Application.CurrentCulture.CompareInfo;
+ int index = 0;
+ bool found = false;
+ for (int i = 0; i < count; i++) {
+ index = i;
+ int comp = compare.Compare (node.Text, nodes [i].Text);
+ if (comp < 0) {
+ found = true;
+ break;
+ }
+ }
+
+ // Stick it at the end
+ if (!found)
+ index = count;
+
+ // Move the nodes up and adjust their indices
+ for (int i = count - 1; i >= index; i--) {
+ nodes [i + 1] = nodes [i];
+ }
+ count++;
+ nodes [index] = node;
+
+ return index;
+ }
+
+ // Would be nice to do this without running through the collection twice
+ internal void Sort (IComparer sorter) {
+ Array.Sort (nodes, 0, count, sorter == null ? new TreeNodeComparer (Application.CurrentCulture.CompareInfo) : sorter);
+
+ for (int i = 0; i < count; i++) {
+ nodes [i].Nodes.Sort (sorter);
+ }
+
+ // Sorted may have been set to false even if TreeViewNodeSorter is being used.
+ TreeView tv = owner == null ? null : owner.TreeView;
+ if (tv != null)
+ tv.sorted = true;
+ }
+
+ private void Grow ()
+ {
+ TreeNode [] nn = new TreeNode [nodes.Length + 50];
+ Array.Copy (nodes, nn, nodes.Length);
+ nodes = nn;
+ }
+
+ private void Shrink ()
+ {
+ int len = (count + 1 > OrigSize ? count + 1 : OrigSize);
+ TreeNode [] nn = new TreeNode [len];
+ Array.Copy (nodes, nn, count);
+ nodes = nn;
+ }
+
+ public TreeNode[] Find (string key, bool searchAllChildren)
+ {
+ List<TreeNode> results = new List<TreeNode> (0);
+ Find (key, searchAllChildren, this, results);
+
+ return results.ToArray ();
+ }
+
+ private static void Find (string key, bool searchAllChildren, TreeNodeCollection nodes, List<TreeNode> results)
+ {
+ for (int i = 0; i < nodes.Count; i++) {
+ TreeNode thisNode = nodes [i];
+
+ if (string.Compare (thisNode.Name, key, true, CultureInfo.InvariantCulture) == 0)
+ results.Add (thisNode);
+
+ }
+ // Need to match the Microsoft order.
+
+ if (searchAllChildren){
+ for (int i = 0; i < nodes.Count; i++){
+ TreeNodeCollection childNodes = nodes [i].Nodes;
+ if (childNodes.Count > 0) {
+ Find (key, searchAllChildren, childNodes, results);
+ }
+ }
+ }
+ }
+
+ internal class TreeNodeEnumerator : IEnumerator {
+
+ private TreeNodeCollection collection;
+ private int index = -1;
+
+ public TreeNodeEnumerator (TreeNodeCollection collection)
+ {
+ this.collection = collection;
+ }
+
+ public object Current {
+ get {
+ if (index == -1)
+ return null;
+ return collection [index];
+ }
+ }
+
+ public bool MoveNext ()
+ {
+ if (index + 1 >= collection.Count)
+ return false;
+ index++;
+ return true;
+ }
+
+ public void Reset ()
+ {
+ index = -1;
+ }
+ }
+
+ private class TreeNodeComparer : IComparer {
+
+ private CompareInfo compare;
+
+ public TreeNodeComparer (CompareInfo compare)
+ {
+ this.compare = compare;
+ }
+
+ public int Compare (object x, object y)
+ {
+ TreeNode l = (TreeNode) x;
+ TreeNode r = (TreeNode) y;
+ int res = compare.Compare (l.Text, r.Text);
+
+ return (res == 0 ? l.Index - r.Index : res);
+ }
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/TreeNodeConverter.cs b/source/ShiftUI/Internal/TreeNodeConverter.cs
new file mode 100644
index 0000000..d9682b4
--- /dev/null
+++ b/source/ShiftUI/Internal/TreeNodeConverter.cs
@@ -0,0 +1,55 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+//
+//
+
+// NOT COMPLETE
+
+using System.ComponentModel;
+using System.Globalization;
+using System;
+
+namespace ShiftUI {
+ public class TreeNodeConverter : TypeConverter {
+
+ #region Public Instance Methods
+ public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof (string))
+ return true;
+ return base.CanConvertTo (context, destinationType);
+ }
+
+ public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture,
+ object value, Type destinationType)
+ {
+ // Regardless of the type of object passed in this does a ToString
+ if (destinationType == typeof (string) && value != null)
+ return value.ToString ();
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ #endregion // Public Instance Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/TreeViewHitTestInfo.cs b/source/ShiftUI/Internal/TreeViewHitTestInfo.cs
new file mode 100644
index 0000000..7e5c19a
--- /dev/null
+++ b/source/ShiftUI/Internal/TreeViewHitTestInfo.cs
@@ -0,0 +1,51 @@
+//
+// TreeViewHitTestLocations.cs
+//
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+//
+
+
+namespace ShiftUI {
+
+ public class TreeViewHitTestInfo {
+
+ private TreeNode node;
+ private TreeViewHitTestLocations location;
+
+ public TreeViewHitTestInfo (TreeNode hitNode, TreeViewHitTestLocations hitLocation)
+ {
+ this.node = hitNode;
+ this.location = hitLocation;
+ }
+
+ public TreeNode Node {
+ get { return node; }
+ }
+
+ public TreeViewHitTestLocations Location {
+ get { return location; }
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/TreeViewImageIndexConverter.cs b/source/ShiftUI/Internal/TreeViewImageIndexConverter.cs
new file mode 100644
index 0000000..f66b205
--- /dev/null
+++ b/source/ShiftUI/Internal/TreeViewImageIndexConverter.cs
@@ -0,0 +1,89 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+
+
+using System;
+using System.Drawing;
+using System.Collections;
+using System.ComponentModel;
+
+
+namespace ShiftUI {
+
+ public class TreeViewImageIndexConverter : ImageIndexConverter {
+
+ public TreeViewImageIndexConverter ()
+ {
+ }
+
+ #region Protected Properties
+ protected override bool IncludeNoneAsStandardValue {
+ get { return false; }
+ }
+ #endregion
+
+ #region Public Methods
+ public override object ConvertFrom (System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
+ {
+ string indexStr;
+
+ if (value != null && value is string) {
+ indexStr = (string)value;
+
+ if (indexStr.Equals ("(default)", StringComparison.InvariantCultureIgnoreCase))
+ return -1;
+ else if (indexStr.Equals ("(none)", StringComparison.InvariantCultureIgnoreCase))
+ return -2;
+
+ return Int32.Parse (indexStr);
+ } else
+ return base.ConvertFrom (context, culture, value);
+ }
+
+ public override object ConvertTo (System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+ {
+ if (destinationType == typeof (string)) {
+ if (value == null)
+ return string.Empty;
+ else if (value is int && (int)value == -1)
+ return "(default)";
+ else if (value is int && (int)value == -2)
+ return "(none)";
+ else if (value is string && ((string)value).Length == 0)
+ return string.Empty;
+ else
+ return value.ToString ();
+ } else
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+
+ public override StandardValuesCollection GetStandardValues (System.ComponentModel.ITypeDescriptorContext context)
+ {
+ int[] stdVal = new int[] { -1, -2 };
+ return new TypeConverter.StandardValuesCollection (stdVal);
+ }
+ #endregion
+ }
+}
+
diff --git a/source/ShiftUI/Internal/TreeViewImageKeyConverter.cs b/source/ShiftUI/Internal/TreeViewImageKeyConverter.cs
new file mode 100644
index 0000000..78ff1d5
--- /dev/null
+++ b/source/ShiftUI/Internal/TreeViewImageKeyConverter.cs
@@ -0,0 +1,51 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Jonathan Pobst [email protected]
+//
+
+using System.Drawing;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI
+{
+ public class TreeViewImageKeyConverter : ImageKeyConverter
+ {
+ #region Constructors
+ public TreeViewImageKeyConverter () { }
+ #endregion Constructors
+
+ #region Public Methods
+ // XXX - Can't find the difference from the base method
+ public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture,
+ object value, Type destinationType)
+ {
+ return base.ConvertTo (context, culture, value, destinationType);
+ }
+ #endregion Public Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/VScrollProperties.cs b/source/ShiftUI/Internal/VScrollProperties.cs
new file mode 100644
index 0000000..e790787
--- /dev/null
+++ b/source/ShiftUI/Internal/VScrollProperties.cs
@@ -0,0 +1,33 @@
+// 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.
+//
+// Authors:
+// Olivier Dufour [email protected]
+//
+
+namespace ShiftUI
+{
+ public class VScrollProperties : ScrollProperties
+ {
+ public VScrollProperties (ScrollableWidget container) : base (container)
+ {
+ scroll_bar = container.vscrollbar;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/Win32DnD.cs b/source/ShiftUI/Internal/Win32DnD.cs
new file mode 100644
index 0000000..24cf2da
--- /dev/null
+++ b/source/ShiftUI/Internal/Win32DnD.cs
@@ -0,0 +1,1081 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok ([email protected])
+// Srikanth Madikeri ([email protected]) - Win32 Drop files.
+//
+
+// NOT COMPLETE
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace ShiftUI {
+ internal class Win32DnD {
+ #region Local Variables
+ private const uint DATADIR_GET = 1;
+ private const uint S_OK = 0x00000000;
+ private const uint S_FALSE = 0x00000001;
+ private const uint DRAGDROP_S_DROP = 0x00040100;
+ private const uint DRAGDROP_S_CANCEL = 0x00040101;
+ private const uint DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102;
+ private const uint E_NOTIMPL = unchecked((uint)0x80004001);
+ private const uint E_NOINTERFACE = unchecked((uint)0x80004002);
+ private const uint E_FAIL = unchecked((uint)0x80004005);
+ private const uint OLE_E_ADVISENOTSUPPORTED = unchecked((uint)0x80040003);
+ private const uint DV_E_FORMATETC = unchecked((uint)0x80040064);
+
+ // To call function pointers
+ //private static object[] GetDataArgs;
+
+ // IDataObject Delegates
+ private static QueryInterfaceDelegate DOQueryInterface;
+ private static AddRefDelegate DOAddRef;
+ private static ReleaseDelegate DORelease;
+ private static GetDataDelegate GetData;
+ private static GetDataHereDelegate GetDataHere;
+ private static QueryGetDataDelegate QueryGetData;
+ private static GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc;
+ private static SetDataDelegate SetData;
+ private static EnumFormatEtcDelegate EnumFormatEtc;
+ private static DAdviseDelegate DAdvise;
+ private static DUnadviseDelegate DUnadvise;
+ private static EnumDAdviseDelegate EnumDAdvise;
+
+ // IDropSource Delegates
+ private static QueryInterfaceDelegate DSQueryInterface;
+ private static AddRefDelegate DSAddRef;
+ private static ReleaseDelegate DSRelease;
+ private static QueryContinueDragDelegate QueryContinueDrag;
+ private static GiveFeedbackDelegate GiveFeedback;
+
+ // IDropTarget Delegates
+ private static QueryInterfaceDelegate DTQueryInterface;
+ private static AddRefDelegate DTAddRef;
+ private static ReleaseDelegate DTRelease;
+ private static DragEnterDelegate DragEnter;
+ private static DragOverDelegate DragOver;
+ private static DragLeaveDelegate DragLeave;
+ private static DropDelegate Drop;
+
+ private static DragEventArgs DragDropEventArgs;
+ private static GiveFeedbackEventArgs DragFeedbackEventArgs;
+ private static QueryContinueDragEventArgs DragContinueEventArgs;
+ private static ArrayList DragFormats;
+ private static FORMATETC[] DragFormatArray;
+ private static ArrayList DragMediums;
+ #endregion // Local Variables
+
+ #region Delegate Definitions
+ // IUnknown
+ internal delegate uint QueryInterfaceDelegate(IntPtr @this, ref Guid riid, IntPtr ppvObject);
+ internal delegate uint AddRefDelegate(IntPtr @this);
+ internal delegate uint ReleaseDelegate(IntPtr @this);
+
+ // IDataObject
+ internal delegate uint GetDataDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pmedium);
+ internal delegate uint GetDataHereDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium);
+ internal delegate uint QueryGetDataDelegate(IntPtr @this, ref FORMATETC pformatetc);
+ internal delegate uint GetCanonicalFormatEtcDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut);
+ internal delegate uint SetDataDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release);
+ internal delegate uint EnumFormatEtcDelegate(IntPtr @this, uint direction, IntPtr ppenumFormatEtc);
+ internal delegate uint DAdviseDelegate(IntPtr @this, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection);
+ internal delegate uint DUnadviseDelegate(IntPtr @this, uint pdwConnection);
+ internal delegate uint EnumDAdviseDelegate(IntPtr @this, IntPtr ppenumAdvise);
+
+ // IDropSource
+ internal delegate uint QueryContinueDragDelegate(IntPtr @this, bool fEscapePressed, uint grfkeyState);
+ internal delegate uint GiveFeedbackDelegate(IntPtr @this, uint pdwEffect);
+
+ // IDropTarget
+ internal delegate uint DragEnterDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
+ internal delegate uint DragOverDelegate(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
+ internal delegate uint DragLeaveDelegate(IntPtr @this);
+ internal delegate uint DropDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
+ #endregion // Delegate Definitions
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct FORMATETC {
+ [MarshalAs(UnmanagedType.U2)]
+ internal ClipboardFormats cfFormat;
+ internal IntPtr ptd;
+ internal DVASPECT dwAspect;
+ internal int lindex;
+ internal TYMED tymed;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct STGMEDIUM {
+ internal TYMED tymed;
+ internal IntPtr hHandle;
+ internal IntPtr pUnkForRelease;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+ internal struct DROPFILES {
+ internal uint pFiles;
+ internal uint pt_x;
+ internal uint pt_y;
+ internal bool fNC;
+ internal bool fWide;
+ internal string pText;
+ }
+
+ internal enum DVASPECT {
+ DVASPECT_CONTENT = 1,
+ DVASPECT_THUMBNAIL = 2,
+ DVASPECT_ICON = 4,
+ DVASPECT_DOCPRINT = 8
+ }
+
+ internal enum TYMED {
+ TYMED_HGLOBAL = 1,
+ TYMED_FILE = 2,
+ TYMED_ISTREAM = 4,
+ TYMED_ISTORAGE = 8,
+ TYMED_GDI = 16,
+ TYMED_MFPICT = 32,
+ TYMED_ENHMF = 64,
+ TYMED_NULL = 0
+ }
+
+ private static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
+ private static readonly Guid IID_IDataObject = new Guid("0000010e-0000-0000-C000-000000000046");
+ private static readonly Guid IID_IDropSource = new Guid("00000121-0000-0000-C000-000000000046");
+ private static readonly Guid IID_IDropTarget = new Guid("00000122-0000-0000-C000-000000000046");
+
+ static Win32DnD()
+ {
+ // Required for all other OLE functions to work
+ Win32OleInitialize(IntPtr.Zero);
+
+ // We reuse those
+ DragDropEventArgs = new DragEventArgs(new DataObject(DataFormats.FileDrop, new string[0]), 0, 0, 0, DragDropEffects.None, DragDropEffects.None);
+ DragFeedbackEventArgs = new GiveFeedbackEventArgs(DragDropEffects.None, true);
+ DragContinueEventArgs = new QueryContinueDragEventArgs(0, false, DragAction.Continue);
+ DragFormats = new ArrayList();
+ DragFormatArray = new FORMATETC[0];
+ DragMediums = new ArrayList();
+
+ // Set up delegates
+ // IDataObject
+ DOQueryInterface = new QueryInterfaceDelegate(ComIDataObject.QueryInterface);
+ DOAddRef = new AddRefDelegate(ComIDataObject.AddRef);
+ DORelease = new ReleaseDelegate(ComIDataObject.Release);
+ GetData = new GetDataDelegate(ComIDataObject.GetData);
+ GetDataHere = new GetDataHereDelegate(ComIDataObject.GetDataHere);
+ QueryGetData = new QueryGetDataDelegate(ComIDataObject.QueryGetData);
+ GetCanonicalFormatEtc = new GetCanonicalFormatEtcDelegate(ComIDataObject.GetCanonicalFormatEtc);
+ SetData = new SetDataDelegate(ComIDataObject.SetData);
+ EnumFormatEtc = new EnumFormatEtcDelegate(ComIDataObject.EnumFormatEtc);
+ DAdvise = new DAdviseDelegate(ComIDataObject.DAdvise);
+ DUnadvise = new DUnadviseDelegate(ComIDataObject.DUnadvise);
+ EnumDAdvise = new EnumDAdviseDelegate(ComIDataObject.EnumDAdvise);
+
+ // IDropSource
+ DSQueryInterface = new QueryInterfaceDelegate(ComIDropSource.QueryInterface);
+ DSAddRef = new AddRefDelegate(ComIDropSource.AddRef);
+ DSRelease = new ReleaseDelegate(ComIDropSource.Release);
+ QueryContinueDrag = new QueryContinueDragDelegate(ComIDropSource.QueryContinueDrag);
+ GiveFeedback = new GiveFeedbackDelegate(ComIDropSource.GiveFeedback);
+
+ // IDropTarget
+ DTQueryInterface = new QueryInterfaceDelegate(ComIDropTarget.QueryInterface);
+ DTAddRef = new AddRefDelegate(ComIDropTarget.AddRef);
+ DTRelease = new ReleaseDelegate(ComIDropTarget.Release);
+ DragEnter = new DragEnterDelegate(ComIDropTarget.DragEnter);
+ DragOver = new DragOverDelegate(ComIDropTarget.DragOver);
+ DragLeave = new DragLeaveDelegate(ComIDropTarget.DragLeave);
+ Drop = new DropDelegate(ComIDropTarget.Drop);
+ }
+
+ internal class ComIDataObject {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct DataObjectStruct {
+ internal IntPtr vtbl;
+ internal QueryInterfaceDelegate QueryInterface;
+ internal AddRefDelegate AddRef;
+ internal ReleaseDelegate Release;
+ internal GetDataDelegate GetData;
+ internal GetDataHereDelegate GetDataHere;
+ internal QueryGetDataDelegate QueryGetData;
+ internal GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc;
+ internal SetDataDelegate SetData;
+ internal EnumFormatEtcDelegate EnumFormatEtc;
+ internal DAdviseDelegate DAdvise;
+ internal DUnadviseDelegate DUnadvise;
+ internal EnumDAdviseDelegate EnumDAdvise;
+ }
+
+ internal static IntPtr GetUnmanaged() {
+ DataObjectStruct data_object;
+ IntPtr data_object_ptr;
+ long offset;
+
+ data_object = new DataObjectStruct();
+
+ data_object.QueryInterface = Win32DnD.DOQueryInterface;
+ data_object.AddRef = Win32DnD.DOAddRef;
+ data_object.Release = Win32DnD.DORelease;
+ data_object.GetData = Win32DnD.GetData;
+ data_object.GetDataHere = Win32DnD.GetDataHere;
+ data_object.QueryGetData = Win32DnD.QueryGetData;
+ data_object.GetCanonicalFormatEtc = Win32DnD.GetCanonicalFormatEtc;
+ data_object.SetData = Win32DnD.SetData;
+ data_object.EnumFormatEtc = Win32DnD.EnumFormatEtc;
+ data_object.DAdvise = Win32DnD.DAdvise;
+ data_object.DUnadvise = Win32DnD.DUnadvise;
+ data_object.EnumDAdvise = Win32DnD.EnumDAdvise;
+
+ data_object_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DataObjectStruct)));
+ Marshal.StructureToPtr(data_object, data_object_ptr, false);
+
+ // Update vtbl pointer
+ offset = data_object_ptr.ToInt64();
+ offset += Marshal.SizeOf(typeof(IntPtr));
+ Marshal.WriteIntPtr(data_object_ptr, new IntPtr(offset));
+
+ return data_object_ptr;
+ }
+
+ internal static void ReleaseUnmanaged(IntPtr data_object_ptr) {
+ Marshal.FreeHGlobal(data_object_ptr);
+ }
+
+ internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
+ try {
+ if (IID_IUnknown.Equals(riid) || IID_IDataObject.Equals(riid)) {
+ Marshal.WriteIntPtr(ppvObject, @this);
+ return S_OK;
+ }
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Got exception {0}", e.Message);
+ }
+
+ Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
+ return E_NOINTERFACE;
+ }
+
+ internal static uint AddRef(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal static uint Release(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal static STGMEDIUM medium = new STGMEDIUM();
+ internal static uint GetData(IntPtr this_, ref FORMATETC pformatetcIn, IntPtr pmedium) {
+ int index;
+
+ index = FindFormat(pformatetcIn);
+ if (index != -1) {
+ medium.tymed = TYMED.TYMED_HGLOBAL;
+ medium.hHandle = XplatUIWin32.DupGlobalMem(((STGMEDIUM)DragMediums[index]).hHandle);
+ medium.pUnkForRelease = IntPtr.Zero;
+ try {
+ Marshal.StructureToPtr(medium, pmedium, false);
+ }
+ catch (Exception e) {
+ Console.WriteLine("Error: {0}", e.Message);
+ }
+ return S_OK;
+ }
+
+ return DV_E_FORMATETC;
+ }
+
+ internal static uint GetDataHere(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium) {
+ return DV_E_FORMATETC;
+ }
+
+ internal static uint QueryGetData(IntPtr @this, ref FORMATETC pformatetc) {
+ if (FindFormat(pformatetc) != -1) {
+ return S_OK;
+ }
+ return DV_E_FORMATETC;
+ }
+
+ internal static uint GetCanonicalFormatEtc(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut) {
+ Marshal.WriteIntPtr(pformatetcOut, Marshal.SizeOf(typeof(IntPtr)), IntPtr.Zero);
+ return E_NOTIMPL;
+ }
+
+ internal static uint SetData(IntPtr this_, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release) {
+ return E_NOTIMPL;
+ }
+
+ internal static uint EnumFormatEtc(IntPtr this_, uint direction, IntPtr ppenumFormatEtc) {
+ if (direction == DATADIR_GET) {
+ IntPtr ppenum_ptr;
+
+ ppenum_ptr = IntPtr.Zero;
+ DragFormatArray = new FORMATETC[DragFormats.Count];
+
+ for (int i = 0; i < DragFormats.Count; i++) {
+ DragFormatArray[i] = (FORMATETC)DragFormats[i];
+ }
+ Win32SHCreateStdEnumFmtEtc((uint)DragFormatArray.Length, DragFormatArray, ref ppenum_ptr);
+ Marshal.WriteIntPtr(ppenumFormatEtc, ppenum_ptr);
+ return S_OK;
+ }
+ return E_NOTIMPL;
+ }
+
+ internal static uint DAdvise(IntPtr this_, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal static uint DUnadvise(IntPtr this_, uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal static uint EnumDAdvise(IntPtr this_, IntPtr ppenumAdvise) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+ }
+
+ internal class ComIDataObjectUnmanaged {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IDataObjectUnmanaged {
+ internal IntPtr QueryInterface;
+ internal IntPtr AddRef;
+ internal IntPtr Release;
+ internal IntPtr GetData;
+ internal IntPtr GetDataHere;
+ internal IntPtr QueryGetData;
+ internal IntPtr GetCanonicalFormatEtc;
+ internal IntPtr SetData;
+ internal IntPtr EnumFormatEtc;
+ internal IntPtr DAdvise;
+ internal IntPtr DUnadvise;
+ internal IntPtr EnumDAdvise;
+ }
+
+ private static bool Initialized;
+ private static MethodInfo GetDataMethod;
+ //private static MethodInfo GetDataHereMethod;
+ private static MethodInfo QueryGetDataMethod;
+ //private static MethodInfo GetCanonicalFormatEtcMethod;
+ //private static MethodInfo SetDataMethod;
+ //private static MethodInfo EnumFormatEtcMethod;
+ //private static MethodInfo DAdviseMethod;
+ //private static MethodInfo DUnadviseMethod;
+ //private static MethodInfo EnumDAdviseMethod;
+ private static object[] MethodArguments;
+
+ private IDataObjectUnmanaged vtbl;
+ private IntPtr @this;
+
+ internal ComIDataObjectUnmanaged(IntPtr data_object_ptr) {
+ if (!Initialized) {
+ Initialize();
+ }
+
+ vtbl = new IDataObjectUnmanaged();
+ @this = data_object_ptr;
+ try {
+ vtbl = (IDataObjectUnmanaged)Marshal.PtrToStructure(Marshal.ReadIntPtr(data_object_ptr), typeof(IDataObjectUnmanaged));
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Exception {0}", e.Message);
+ }
+ }
+
+ private static void Initialize() {
+ AssemblyName assembly;
+ AssemblyBuilder assembly_builder;
+
+ if (Initialized) {
+ return;
+ }
+
+ assembly = new AssemblyName();
+ assembly.Name = "XplatUIWin32.FuncPtrInterface";
+ assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
+
+ MethodArguments = new object[6];
+ GetDataMethod = CreateFuncPtrInterface(assembly_builder, "GetData", typeof(uint), 3);
+ //GetDataHereMethod = CreateFuncPtrInterface(assembly_builder, "GetDataHere", typeof(uint), 3);
+ QueryGetDataMethod = CreateFuncPtrInterface(assembly_builder, "QueryGetData", typeof(uint), 2);
+ //GetCanonicalFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "GetCanonicalFormatEtc", typeof(uint), 3);
+ //SetDataMethod = CreateFuncPtrInterface(assembly_builder, "SetData", typeof(uint), 4);
+ //EnumFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "EnumFormatEtc", typeof(uint), 3);
+ //DAdviseMethod = CreateFuncPtrInterface(assembly_builder, "DAdvise", typeof(uint), 5);
+ //DUnadviseMethod = CreateFuncPtrInterface(assembly_builder, "DUnadvise", typeof(uint), 2);
+ //EnumDAdviseMethod = CreateFuncPtrInterface(assembly_builder, "EnumDAdvise", typeof(uint), 2);
+
+ Initialized = true;
+ }
+
+ internal uint QueryInterface(Guid riid, IntPtr ppvObject) {
+ uint ret;
+ IntPtr riid_ptr;
+
+ riid_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
+ Marshal.StructureToPtr(riid, riid_ptr, false);
+
+ MethodArguments[0] = vtbl.QueryInterface;
+ MethodArguments[1] = this.@this;
+ MethodArguments[2] = riid_ptr;
+ MethodArguments[3] = ppvObject;
+
+ try {
+ ret = (uint)GetDataMethod.Invoke(null, MethodArguments);
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Caught exception {0}", e.Message);
+ ret = E_FAIL;
+ }
+
+ Marshal.FreeHGlobal(riid_ptr);
+
+ return ret;
+ }
+
+ internal uint AddRef() {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal uint Release() {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal uint GetData(FORMATETC pformatetcIn, ref STGMEDIUM pmedium) {
+ uint ret;
+ IntPtr pformatetcIn_ptr;
+ IntPtr pmedium_ptr;
+
+ pformatetcIn_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC)));
+ Marshal.StructureToPtr(pformatetcIn, pformatetcIn_ptr, false);
+
+ pmedium_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(STGMEDIUM)));
+
+ MethodArguments[0] = vtbl.GetData;
+ MethodArguments[1] = this.@this;
+ MethodArguments[2] = pformatetcIn_ptr;
+ MethodArguments[3] = pmedium_ptr;
+
+ try {
+ ret = (uint)GetDataMethod.Invoke(null, MethodArguments);
+ Marshal.PtrToStructure(pmedium_ptr, pmedium);
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Caught exception {0}", e.Message);
+ ret = E_FAIL;
+ }
+
+ Marshal.FreeHGlobal(pformatetcIn_ptr);
+ Marshal.FreeHGlobal(pmedium_ptr);
+
+ return ret;
+ }
+
+ internal uint GetDataHere(FORMATETC pformatetc, ref STGMEDIUM pmedium) {
+ return E_NOTIMPL;
+ }
+
+ internal uint QueryGetData(FORMATETC pformatetc) {
+ uint ret;
+ IntPtr pformatetc_ptr;
+
+ pformatetc_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC)));
+ Marshal.StructureToPtr(pformatetc, pformatetc_ptr, false);
+
+ MethodArguments[0] = vtbl.GetData;
+ MethodArguments[1] = this.@this;
+ MethodArguments[2] = pformatetc_ptr;
+
+ try {
+ ret = (uint)QueryGetDataMethod.Invoke(null, MethodArguments);
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Caught exception {0}", e.Message);
+ ret = E_FAIL;
+ }
+
+ Marshal.FreeHGlobal(pformatetc_ptr);
+
+ return ret;
+ }
+
+ internal uint GetCanonicalFormatEtc(FORMATETC pformatetcIn, ref FORMATETC pformatetcOut) {
+ return E_NOTIMPL;
+ }
+
+ internal uint SetData(FORMATETC pformatetc, STGMEDIUM pmedium, bool release) {
+ return E_NOTIMPL;
+ }
+
+ internal uint EnumFormatEtc(uint direction, IntPtr ppenumFormatEtc) {
+ return E_NOTIMPL;
+ }
+
+ internal uint DAdvise(FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal uint DUnadvise(uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal uint EnumDAdvise(IntPtr ppenumAdvise) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+ }
+
+
+ internal class ComIDropSource {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IDropSource {
+ internal IntPtr vtbl;
+ internal IntPtr Window;
+ internal QueryInterfaceDelegate QueryInterface;
+ internal AddRefDelegate AddRef;
+ internal ReleaseDelegate Release;
+ internal QueryContinueDragDelegate QueryContinueDrag;
+ internal GiveFeedbackDelegate GiveFeedback;
+ }
+
+ internal static IntPtr GetUnmanaged(IntPtr Window) {
+ IDropSource drop_source;
+ IntPtr drop_source_ptr;
+ long offset;
+
+ drop_source = new IDropSource();
+ drop_source.QueryInterface = Win32DnD.DSQueryInterface;
+ drop_source.AddRef = Win32DnD.DSAddRef;
+ drop_source.Release = Win32DnD.DSRelease;
+ drop_source.QueryContinueDrag = Win32DnD.QueryContinueDrag;
+ drop_source.GiveFeedback = Win32DnD.GiveFeedback;
+ drop_source.Window = Window;
+
+ drop_source_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_source));
+ Marshal.StructureToPtr(drop_source, drop_source_ptr, false);
+
+ // Update vtbl pointer
+ offset = drop_source_ptr.ToInt64();
+ offset += 2 * Marshal.SizeOf(typeof(IntPtr));
+ Marshal.WriteIntPtr(drop_source_ptr, new IntPtr(offset));
+
+ return drop_source_ptr;
+ }
+
+ internal static void ReleaseUnmanaged(IntPtr drop_source_ptr) {
+ Marshal.FreeHGlobal(drop_source_ptr);
+ }
+
+ internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
+ try {
+ if (IID_IUnknown.Equals(riid) || IID_IDropSource.Equals(riid)) {
+ Marshal.WriteIntPtr(ppvObject, @this);
+ return S_OK;
+ }
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Got exception {0}", e.Message);
+ }
+
+ Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
+ return E_NOINTERFACE;
+ }
+
+ internal static uint AddRef(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal static uint Release(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal static uint QueryContinueDrag(IntPtr @this, bool fEscapePressed, uint grfkeyState) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ // LAMESPEC? - according to MSDN, when the any mousebutton is *pressed* it defaults to Drop.
+ // According to COM customary behaviour it's the other way round; which is what we do here
+ if (fEscapePressed) {
+ DragContinueEventArgs.drag_action = DragAction.Cancel;
+ } else if ((grfkeyState & (1+2+16)) == 0) { // Left, middle and right mouse button not pressed
+ DragContinueEventArgs.drag_action = DragAction.Drop;
+ } else {
+ DragContinueEventArgs.drag_action = DragAction.Continue;
+ }
+
+ DragContinueEventArgs.escape_pressed = fEscapePressed;
+ DragContinueEventArgs.key_state = (int)grfkeyState;
+
+ Widget.FromHandle(window).DndContinueDrag(DragContinueEventArgs);
+
+ if (DragContinueEventArgs.drag_action == DragAction.Cancel) {
+ return DRAGDROP_S_CANCEL;
+ } else if (DragContinueEventArgs.drag_action == DragAction.Drop) {
+ return DRAGDROP_S_DROP;
+ }
+ return S_OK;
+ }
+
+ internal static uint GiveFeedback(IntPtr @this, uint pdwEffect) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ DragFeedbackEventArgs.effect = (DragDropEffects)pdwEffect;
+ DragFeedbackEventArgs.use_default_cursors = true;
+
+ Widget.FromHandle(window).DndFeedback(DragFeedbackEventArgs);
+
+ if (DragFeedbackEventArgs.use_default_cursors) {
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+ }
+ return S_OK;
+ }
+ }
+
+ internal class ComIDropTarget {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IDropTarget {
+ internal IntPtr vtbl;
+ internal IntPtr Window;
+ internal QueryInterfaceDelegate QueryInterface;
+ internal AddRefDelegate AddRef;
+ internal ReleaseDelegate Release;
+
+ internal DragEnterDelegate DragEnter;
+ internal DragOverDelegate DragOver;
+ internal DragLeaveDelegate DragLeave;
+ internal DropDelegate Drop;
+ }
+
+ internal static IntPtr GetUnmanaged(IntPtr Window) {
+ IDropTarget drop_target;
+ IntPtr drop_target_ptr;
+ long offset;
+
+ drop_target = new IDropTarget();
+ drop_target.QueryInterface = Win32DnD.DTQueryInterface;
+ drop_target.AddRef = Win32DnD.DTAddRef;
+ drop_target.Release = Win32DnD.DTRelease;
+ drop_target.DragEnter = Win32DnD.DragEnter;
+ drop_target.DragOver = Win32DnD.DragOver;
+ drop_target.DragLeave = Win32DnD.DragLeave;
+ drop_target.Drop = Win32DnD.Drop;
+ drop_target.Window = Window;
+
+ drop_target_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_target));
+ Marshal.StructureToPtr(drop_target, drop_target_ptr, false);
+
+ // Update vtbl pointer
+ offset = drop_target_ptr.ToInt64();
+ offset += 2 * Marshal.SizeOf(typeof(IntPtr));
+ Marshal.WriteIntPtr(drop_target_ptr, new IntPtr(offset));
+
+ return drop_target_ptr;
+ }
+
+ internal static void ReleaseUnmanaged(IntPtr drop_target_ptr) {
+ Marshal.FreeHGlobal(drop_target_ptr);
+ }
+
+ internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
+ try {
+ if (IID_IUnknown.Equals(riid) || IID_IDropTarget.Equals(riid)) {
+ Marshal.WriteIntPtr(ppvObject, @this);
+ return S_OK;
+ }
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Got exception {0}", e.Message);
+ }
+
+ Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
+ return E_NOINTERFACE;
+ }
+
+ internal static uint AddRef(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal static uint Release(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal static uint DragEnter(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ DragDropEventArgs.x = pt_x.ToInt32();
+ DragDropEventArgs.y = pt_y.ToInt32();
+ DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32();
+ DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
+ DragDropEventArgs.keystate = (int)grfkeyState;
+
+ Widget.FromHandle(window).DndEnter(DragDropEventArgs);
+
+ Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect);
+
+ return S_OK;
+ }
+
+ internal static uint DragOver(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ DragDropEventArgs.x = pt_x.ToInt32();
+ DragDropEventArgs.y = pt_y.ToInt32();
+ DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32();
+ DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
+ DragDropEventArgs.keystate = (int)grfkeyState;
+
+ Widget.FromHandle(window).DndOver(DragDropEventArgs);
+
+ Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect);
+
+ return S_OK;
+ }
+
+ internal static uint DragLeave(IntPtr @this) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ Widget.FromHandle(window).DndLeave(EventArgs.Empty);
+
+ return S_OK;
+ }
+
+ internal static uint Drop(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect)
+ {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr (@this, Marshal.SizeOf (typeof (IntPtr)));
+
+ DragDropEventArgs.x = pt_x.ToInt32 ();
+ DragDropEventArgs.y = pt_y.ToInt32 ();
+ DragDropEventArgs.allowed_effect = (DragDropEffects) Marshal.ReadIntPtr (pdwEffect).ToInt32();
+ DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
+ DragDropEventArgs.keystate = (int) grfkeyState;
+
+ Widget control = Widget.FromHandle (window);
+ if (control != null) {
+ control.DndDrop (DragDropEventArgs);
+ return S_FALSE;
+ }
+
+ Marshal.WriteInt32 (pdwEffect, (int) DragDropEventArgs.Effect);
+
+ return S_OK;
+ }
+ }
+
+ internal static bool HandleWMDropFiles(ref MSG msg) {
+ IntPtr hDrop;
+ int count;
+ StringBuilder sb;
+ string[] dropfiles;
+
+ hDrop = msg.wParam;
+ count = Win32DragQueryFile(hDrop, -1, IntPtr.Zero, 0);
+
+ dropfiles = new string[count];
+
+ sb = new StringBuilder(256);
+ for (int i = 0; i < count; i++) {
+ Win32DragQueryFile(hDrop, i, sb, sb.Capacity);
+ dropfiles[i] = sb.ToString();
+ }
+
+ DragDropEventArgs.Data.SetData(DataFormats.FileDrop, dropfiles);
+
+ Widget.FromHandle(msg.hwnd).DndDrop(DragDropEventArgs);
+
+ return true;
+ }
+
+ private static bool AddFormatAndMedium(ClipboardFormats cfFormat, object data) {
+ STGMEDIUM medium;
+ FORMATETC format;
+ IntPtr hmem;
+ IntPtr hmem_ptr;
+ byte[] b;
+
+ switch(cfFormat) {
+ case ClipboardFormats.CF_TEXT: {
+ b = XplatUIWin32.StringToAnsi ((string)data);
+ hmem = XplatUIWin32.CopyToMoveableMemory (b);
+ break;
+ }
+
+ case ClipboardFormats.CF_UNICODETEXT: {
+ b = XplatUIWin32.StringToUnicode ((string)data);
+ hmem = XplatUIWin32.CopyToMoveableMemory (b);
+ break;
+ }
+
+ case ClipboardFormats.CF_HDROP: {
+ IEnumerator e;
+ StringBuilder sb;
+ long hmem_string_ptr;
+ IntPtr string_buffer;
+ int string_buffer_size;
+
+ sb = new StringBuilder();
+
+ // Make sure object is enumerable; otherwise
+ if ((data is string) || !(data is IEnumerable)) {
+ sb.Append(data.ToString());
+ sb.Append('\0');
+ sb.Append('\0');
+ } else {
+ e = ((IEnumerable)data).GetEnumerator();
+ while (e.MoveNext()) {
+ sb.Append(e.Current.ToString());
+ sb.Append('\0');
+ }
+ sb.Append('\0');
+ }
+
+ string_buffer = Marshal.StringToHGlobalUni(sb.ToString());
+ string_buffer_size = (int)XplatUIWin32.Win32GlobalSize(string_buffer);
+
+ // Write DROPFILES structure
+ hmem = XplatUIWin32.Win32GlobalAlloc(XplatUIWin32.GAllocFlags.GMEM_MOVEABLE | XplatUIWin32.GAllocFlags.GMEM_DDESHARE, 0x14 + string_buffer_size);
+ hmem_ptr = XplatUIWin32.Win32GlobalLock(hmem);
+ Marshal.WriteInt32(hmem_ptr, 0x14); // pFiles
+ Marshal.WriteInt32(hmem_ptr, 1 * Marshal.SizeOf(typeof(uint)), 0); // point.x
+ Marshal.WriteInt32(hmem_ptr, 2 * Marshal.SizeOf(typeof(uint)), 0); // point.y
+ Marshal.WriteInt32(hmem_ptr, 3 * Marshal.SizeOf(typeof(uint)), 0); // fNc
+ Marshal.WriteInt32(hmem_ptr, 4 * Marshal.SizeOf(typeof(uint)), 1); // fWide
+
+ hmem_string_ptr = (long)hmem_ptr;
+ hmem_string_ptr += 0x14;
+
+ XplatUIWin32.Win32CopyMemory(new IntPtr(hmem_string_ptr), string_buffer, string_buffer_size);
+ Marshal.FreeHGlobal(string_buffer);
+ XplatUIWin32.Win32GlobalUnlock(hmem_ptr);
+
+ break;
+ }
+
+ case ClipboardFormats.CF_DIB: {
+ b = XplatUIWin32.ImageToDIB((Image)data);
+ hmem = XplatUIWin32.CopyToMoveableMemory (b);
+ break;
+ }
+
+ default: {
+ hmem = IntPtr.Zero;
+ break;
+ }
+ }
+
+ if (hmem != IntPtr.Zero) {
+ medium = new STGMEDIUM();
+ medium.tymed = TYMED.TYMED_HGLOBAL;
+ medium.hHandle = hmem;
+ medium.pUnkForRelease = IntPtr.Zero;
+ DragMediums.Add(medium);
+
+ format = new FORMATETC();
+ format.ptd = IntPtr.Zero;
+ format.dwAspect = DVASPECT.DVASPECT_CONTENT;
+ format.lindex = -1;
+ format.tymed = TYMED.TYMED_HGLOBAL;
+ format.cfFormat = cfFormat;
+ DragFormats.Add(format);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private static int FindFormat(FORMATETC pformatetc) {
+ for (int i = 0; i < DragFormats.Count; i++) {
+ if ((((FORMATETC)DragFormats[i]).cfFormat == pformatetc.cfFormat) &&
+ (((FORMATETC)DragFormats[i]).dwAspect == pformatetc.dwAspect) &&
+ ((((FORMATETC)DragFormats[i]).tymed & pformatetc.tymed)) != 0) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static void BuildFormats(object data) {
+
+ DragFormats.Clear();
+ DragMediums.Clear();
+
+ // Build our formats based on object data
+ if (data is String) {
+ AddFormatAndMedium(ClipboardFormats.CF_TEXT, data);
+ AddFormatAndMedium(ClipboardFormats.CF_UNICODETEXT, data);
+ AddFormatAndMedium(ClipboardFormats.CF_HDROP, data);
+ } else if (data is Bitmap) {
+ AddFormatAndMedium(ClipboardFormats.CF_DIB, data);
+ } else if (data is ICollection) {
+ // FIXME - test with .Net and found how this is handled
+ AddFormatAndMedium(ClipboardFormats.CF_HDROP, data);
+ } else if (data is ISerializable) {
+ // FIXME - test with .Net and found how this is handled
+ }
+ }
+
+ internal static DragDropEffects StartDrag(IntPtr Window, object data, DragDropEffects allowed) {
+ IntPtr result;
+ IntPtr data_object;
+ IntPtr drop_source;
+
+ BuildFormats(data);
+
+ data_object = ComIDataObject.GetUnmanaged();
+ drop_source = ComIDropSource.GetUnmanaged(Window);
+
+ result = (IntPtr)DragDropEffects.None;
+
+ Win32DoDragDrop(data_object, drop_source, (IntPtr)allowed, ref result);
+
+ // Cleanup again
+ ComIDataObject.ReleaseUnmanaged(data_object);
+ ComIDropSource.ReleaseUnmanaged(drop_source);
+ DragFormats.Clear();
+ DragFormatArray = null;
+ DragMediums.Clear();
+
+ return (DragDropEffects)result.ToInt32();
+ }
+
+ internal static bool UnregisterDropTarget(IntPtr Window) {
+ Win32RevokeDragDrop(Window);
+ return true;
+ }
+
+ internal static bool RegisterDropTarget(IntPtr Window) {
+ Hwnd hwnd;
+ IntPtr drop_target;
+ uint result;
+
+ hwnd = Hwnd.ObjectFromWindow(Window);
+ if (hwnd == null) {
+ return false;
+ }
+
+ drop_target = ComIDropTarget.GetUnmanaged(Window);
+ hwnd.marshal_free_list.Add(drop_target);
+ result = Win32RegisterDragDrop(Window, drop_target);
+
+ if (result != S_OK) {
+ return false;
+ }
+ return true;
+ }
+
+ // Thanks, Martin
+ static MethodInfo CreateFuncPtrInterface(AssemblyBuilder assembly, string MethodName, Type ret_type, int param_count) {
+ ModuleBuilder mb;
+ TypeBuilder tb;
+ Type[] il_param_types;
+ Type[] param_types;
+
+ mb = assembly.DefineDynamicModule("XplatUIWin32.FuncInterface" + MethodName);
+ tb = mb.DefineType ("XplatUIWin32.FuncInterface" + MethodName, TypeAttributes.Public);
+
+ param_types = new Type[param_count];
+ il_param_types = new Type[param_count + 1];
+
+ il_param_types[param_count] = typeof(IntPtr);
+ for (int i = 0; i < param_count; i++) {
+ param_types[i] = typeof(IntPtr);
+ il_param_types[i] = typeof(IntPtr);
+ }
+
+ MethodBuilder method = tb.DefineMethod (
+ MethodName, MethodAttributes.Static | MethodAttributes.Public,
+ ret_type, il_param_types);
+
+ ILGenerator ig = method.GetILGenerator ();
+ if (param_count > 5) ig.Emit (OpCodes.Ldarg_S, 6);
+ if (param_count > 4) ig.Emit (OpCodes.Ldarg_S, 5);
+ if (param_count > 3) ig.Emit (OpCodes.Ldarg_S, 4);
+ if (param_count > 2) ig.Emit (OpCodes.Ldarg_3);
+ if (param_count > 1) ig.Emit (OpCodes.Ldarg_2);
+ if (param_count > 0) ig.Emit (OpCodes.Ldarg_1);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, ret_type, param_types);
+ ig.Emit (OpCodes.Ret);
+
+ Type t = tb.CreateType ();
+ MethodInfo m = t.GetMethod (MethodName);
+
+ return m;
+ }
+
+ [DllImport ("ole32.dll", EntryPoint="RegisterDragDrop", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32RegisterDragDrop(IntPtr Window, IntPtr pDropTarget);
+
+ [DllImport ("ole32.dll", EntryPoint="RevokeDragDrop", CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32RevokeDragDrop(IntPtr Window);
+
+ [DllImport ("ole32.dll", EntryPoint="DoDragDrop", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32DoDragDrop(IntPtr pDataObject, IntPtr pDropSource, IntPtr dwOKEffect, ref IntPtr pdwEffect);
+
+ //[DllImport ("shell32.dll", EntryPoint="DragAcceptFiles", CallingConvention=CallingConvention.StdCall)]
+ //private extern static int Win32DragAcceptFiles(IntPtr Window, bool fAccept);
+
+ [DllImport ("ole32.dll", EntryPoint="OleInitialize", CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32OleInitialize(IntPtr pvReserved);
+
+ [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, IntPtr lpszFile, int cch);
+
+ [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
+
+ [DllImport ("shell32.dll", EntryPoint="SHCreateStdEnumFmtEtc", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32SHCreateStdEnumFmtEtc(uint cfmt, FORMATETC[] afmt, ref IntPtr ppenumFormatEtc);
+ }
+}
diff --git a/source/ShiftUI/Internal/WindowHandler.cs b/source/ShiftUI/Internal/WindowHandler.cs
new file mode 100644
index 0000000..cb59ca4
--- /dev/null
+++ b/source/ShiftUI/Internal/WindowHandler.cs
@@ -0,0 +1,235 @@
+// 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) 2007 Novell, Inc.
+//
+// Authors:
+// Geoff Norton <[email protected]>
+//
+//
+
+using System;
+using System.Drawing;
+using ShiftUI;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.CarbonInternal {
+ internal class WindowHandler : EventHandlerBase, IEventHandler {
+ internal const uint kEventWindowUpdate = 1;
+ internal const uint kEventWindowDrawContent = 2;
+ internal const uint kEventWindowActivated = 5;
+ internal const uint kEventWindowDeactivated = 6;
+ internal const uint kEventWindowGetClickActivation = 7;
+ internal const uint kEventWindowShowing = 22;
+ internal const uint kEventWindowHiding = 23;
+ internal const uint kEventWindowShown = 24;
+ internal const uint kEventWindowHidden = 25;
+ internal const uint kEventWindowCollapsing = 86;
+ internal const uint kEventWindowExpanding = 87;
+ internal const uint kEventWindowZoomed = 76;
+ internal const uint kEventWindowBoundsChanging = 26;
+ internal const uint kEventWindowBoundsChanged = 27;
+ internal const uint kEventWindowResizeStarted = 28;
+ internal const uint kEventWindowResizeCompleted = 29;
+ internal const uint kEventWindowDragStarted = 30;
+ internal const uint kEventWindowDragCompleted = 31;
+ internal const uint kEventWindowTransitionStarted = 88;
+ internal const uint kEventWindowTransitionCompleted = 89;
+ internal const uint kEventWindowClickDragRgn = 32;
+ internal const uint kEventWindowClickResizeRgn = 33;
+ internal const uint kEventWindowClickCollapseRgn = 34;
+ internal const uint kEventWindowClickCloseRgn = 35;
+ internal const uint kEventWindowClickZoomRgn = 36;
+ internal const uint kEventWindowClickContentRgn = 37;
+ internal const uint kEventWindowClickProxyIconRgn = 38;
+ internal const uint kEventWindowClickToolbarButtonRgn = 41;
+ internal const uint kEventWindowClickStructureRgn = 42;
+ internal const uint kEventWindowCursorChange = 40;
+ internal const uint kEventWindowCollapse = 66;
+ internal const uint kEventWindowCollapsed = 67;
+ internal const uint kEventWindowCollapseAll = 68;
+ internal const uint kEventWindowExpand = 69;
+ internal const uint kEventWindowExpanded = 70;
+ internal const uint kEventWindowExpandAll = 71;
+ internal const uint kEventWindowClose = 72;
+ internal const uint kEventWindowClosed = 73;
+ internal const uint kEventWindowCloseAll = 74;
+ internal const uint kEventWindowZoom = 75;
+ internal const uint kEventWindowZoomAll = 77;
+ internal const uint kEventWindowContextualMenuSelect = 78;
+ internal const uint kEventWindowPathSelect = 79;
+ internal const uint kEventWindowGetIdealSize = 80;
+ internal const uint kEventWindowGetMinimumSize = 81;
+ internal const uint kEventWindowGetMaximumSize = 82;
+ internal const uint kEventWindowConstrain = 83;
+ internal const uint kEventWindowHandleContentClick = 85;
+ internal const uint kEventWindowGetDockTileMenu = 90;
+ internal const uint kEventWindowHandleActivate = 91;
+ internal const uint kEventWindowHandleDeactivate = 92;
+ internal const uint kEventWindowProxyBeginDrag = 128;
+ internal const uint kEventWindowProxyEndDrag = 129;
+ internal const uint kEventWindowToolbarSwitchMode = 150;
+ internal const uint kEventWindowFocusAcquired = 200;
+ internal const uint kEventWindowFocusRelinquish = 201;
+ internal const uint kEventWindowFocusContent = 202;
+ internal const uint kEventWindowFocusToolbar = 203;
+ internal const uint kEventWindowDrawerOpening = 220;
+ internal const uint kEventWindowDrawerOpened = 221;
+ internal const uint kEventWindowDrawerClosing = 222;
+ internal const uint kEventWindowDrawerClosed = 223;
+ internal const uint kEventWindowDrawFrame = 1000;
+ internal const uint kEventWindowDrawPart = 1001;
+ internal const uint kEventWindowGetRegion = 1002;
+ internal const uint kEventWindowHitTest = 1003;
+ internal const uint kEventWindowInit = 1004;
+ internal const uint kEventWindowDispose = 1005;
+ internal const uint kEventWindowDragHilite = 1006;
+ internal const uint kEventWindowModified = 1007;
+ internal const uint kEventWindowSetupProxyDragImage = 1008;
+ internal const uint kEventWindowStateChanged = 1009;
+ internal const uint kEventWindowMeasureTitle = 1010;
+ internal const uint kEventWindowDrawGrowBox = 1011;
+ internal const uint kEventWindowGetGrowImageRegion = 1012;
+ internal const uint kEventWindowPaint = 1013;
+
+ internal WindowHandler (XplatUICarbon driver) : base (driver) {}
+
+ public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
+ IntPtr window = Driver.HandleToWindow (handle);
+ Hwnd hwnd = Hwnd.ObjectFromHandle (window);
+ if (window != IntPtr.Zero) {
+ switch (kind) {
+ case kEventWindowActivated: {
+ Widget c = Widget.FromHandle (hwnd.client_window);
+ if (c != null) {
+ Form form = c.FindForm ();
+ if (form != null && !form.IsDisposed) {
+ Driver.SendMessage (form.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
+ XplatUICarbon.ActiveWindow = hwnd.client_window;
+ }
+ }
+
+ foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) {
+ if (utility_window != handle && !XplatUICarbon.IsWindowVisible (utility_window))
+ XplatUICarbon.ShowWindow (utility_window);
+ }
+ break;
+ }
+ case kEventWindowExpanding:
+ foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) {
+ if (utility_window != handle && !XplatUICarbon.IsWindowVisible (utility_window))
+ XplatUICarbon.ShowWindow (utility_window);
+ }
+ msg.hwnd = hwnd.Handle;
+ msg.message = Msg.WM_ENTERSIZEMOVE;
+ return true;
+ case kEventWindowExpanded:
+ NativeWindow.WndProc (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ msg.hwnd = hwnd.Handle;
+ msg.message = Msg.WM_EXITSIZEMOVE;
+ return true;
+ case kEventWindowDeactivated: {
+ Widget c = Widget.FromHandle (hwnd.client_window);
+ if (c != null) {
+ Form form = c.FindForm ();
+ if (form != null && XplatUICarbon.UnactiveWindow != form.Handle) {
+ Driver.SendMessage (form.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
+ XplatUICarbon.ActiveWindow = IntPtr.Zero;
+ }
+ }
+ foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) {
+ if (utility_window != handle && XplatUICarbon.IsWindowVisible (utility_window))
+ XplatUICarbon.HideWindow (utility_window);
+ }
+ break;
+ }
+ case kEventWindowCollapsing:
+ foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) {
+ if (utility_window != handle && XplatUICarbon.IsWindowVisible (utility_window))
+ XplatUICarbon.HideWindow (utility_window);
+ }
+ msg.hwnd = hwnd.Handle;
+ msg.message = Msg.WM_ENTERSIZEMOVE;
+ return true;
+ case kEventWindowCollapsed:
+ NativeWindow.WndProc (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ msg.hwnd = hwnd.Handle;
+ msg.message = Msg.WM_EXITSIZEMOVE;
+ return true;
+ case kEventWindowClose:
+ NativeWindow.WndProc (hwnd.Handle, Msg.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
+ return false;
+ case kEventWindowShown: {
+ msg.message = Msg.WM_SHOWWINDOW;
+ msg.lParam = (IntPtr) 1;
+ msg.wParam = (IntPtr) 0;
+ msg.hwnd = hwnd.Handle;
+
+ return true;
+ }
+ case kEventWindowResizeStarted: {
+ msg.message = Msg.WM_ENTERSIZEMOVE;
+ msg.hwnd = hwnd.Handle;
+ return true;
+ }
+ case kEventWindowResizeCompleted: {
+ msg.message = Msg.WM_EXITSIZEMOVE;
+ msg.hwnd = hwnd.Handle;
+
+ return true;
+ }
+ case kEventWindowBoundsChanged: {
+ Rect window_bounds = new Rect ();
+ HIRect view_bounds = new HIRect ();
+ Size size;
+
+ GetWindowBounds (handle, 33, ref window_bounds);
+
+ view_bounds.size.width = window_bounds.right - window_bounds.left;
+ view_bounds.size.height = window_bounds.bottom - window_bounds.top;
+
+ HIViewSetFrame (hwnd.WholeWindow, ref view_bounds);
+
+ size = XplatUICarbon.TranslateQuartzWindowSizeToWindowSize (Widget.FromHandle (hwnd.Handle).GetCreateParams (), (int)view_bounds.size.width, (int)view_bounds.size.height);
+
+ hwnd.X = (int) window_bounds.left;
+ hwnd.Y = (int) window_bounds.top;
+ hwnd.Width = (int) size.Width;
+ hwnd.Height = (int) size.Height;
+
+ Driver.PerformNCCalc (hwnd);
+
+ msg.hwnd = hwnd.Handle;
+ msg.message = Msg.WM_WINDOWPOSCHANGED;
+ Driver.SetCaretPos (XplatUICarbon.Caret.Hwnd, XplatUICarbon.Caret.X, XplatUICarbon.Caret.Y);
+
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int GetWindowBounds (IntPtr handle, uint region, ref Rect bounds);
+
+ [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int HIViewSetFrame (IntPtr handle, ref HIRect bounds);
+ }
+}
diff --git a/source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs b/source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs
new file mode 100644
index 0000000..ec8ab1c
--- /dev/null
+++ b/source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs
@@ -0,0 +1,94 @@
+// 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) 2007 Novell, Inc.
+//
+
+using System;
+using System.Threading;
+using System.ComponentModel;
+
+
+// Some implementation details:
+// http://msdn.microsoft.com/msdnmag/issues/06/06/NETMatters/default.aspx
+namespace ShiftUI
+{
+ public sealed class WindowsFormsSynchronizationContext : SynchronizationContext, IDisposable
+ {
+ private static bool auto_installed;
+ private static Widget invoke_control;
+ private static SynchronizationContext previous_context;
+
+ #region Public Constructor
+ public WindowsFormsSynchronizationContext ()
+ {
+ }
+
+ static WindowsFormsSynchronizationContext ()
+ {
+ try {
+ invoke_control = new Widget ();
+ invoke_control.CreateWidget ();
+ auto_installed = true;
+ previous_context = SynchronizationContext.Current;
+ }
+ catch (Exception ex) {
+ Console.WriteLine (ex.Message);
+ }
+ }
+ #endregion
+
+ #region Public Properties
+ //[EditorBrowsable (EditorBrowsableState.Advanced)]
+ public static bool AutoInstall {
+ get { return auto_installed; }
+ set { auto_installed = value; }
+ }
+ #endregion
+
+ #region Public Methods
+ public override SynchronizationContext CreateCopy ()
+ {
+ return base.CreateCopy ();
+ }
+
+ public void Dispose ()
+ {
+ }
+
+ public override void Post (SendOrPostCallback d, object state)
+ {
+ invoke_control.BeginInvoke (d, new object[] { state });
+ }
+
+ public override void Send (SendOrPostCallback d, object state)
+ {
+ invoke_control.Invoke (d, new object[] { state });
+ }
+
+ public static void Uninstall ()
+ {
+ if (previous_context == null)
+ previous_context = new SynchronizationContext ();
+
+ SynchronizationContext.SetSynchronizationContext (previous_context);
+ }
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/X11Atoms.cs b/source/ShiftUI/Internal/X11Atoms.cs
new file mode 100644
index 0000000..ec0232c
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Atoms.cs
@@ -0,0 +1,329 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+//
+
+using System;
+using ShiftUI;
+
+namespace ShiftUI.X11Internal {
+
+ internal class X11Atoms {
+
+ // Our atoms
+ public readonly IntPtr AnyPropertyType = (IntPtr)0;
+ public readonly IntPtr XA_PRIMARY = (IntPtr)1;
+ public readonly IntPtr XA_SECONDARY = (IntPtr)2;
+ public readonly IntPtr XA_ARC = (IntPtr)3;
+ public readonly IntPtr XA_ATOM = (IntPtr)4;
+ public readonly IntPtr XA_BITMAP = (IntPtr)5;
+ public readonly IntPtr XA_CARDINAL = (IntPtr)6;
+ public readonly IntPtr XA_COLORMAP = (IntPtr)7;
+ public readonly IntPtr XA_CURSOR = (IntPtr)8;
+ public readonly IntPtr XA_CUT_BUFFER0 = (IntPtr)9;
+ public readonly IntPtr XA_CUT_BUFFER1 = (IntPtr)10;
+ public readonly IntPtr XA_CUT_BUFFER2 = (IntPtr)11;
+ public readonly IntPtr XA_CUT_BUFFER3 = (IntPtr)12;
+ public readonly IntPtr XA_CUT_BUFFER4 = (IntPtr)13;
+ public readonly IntPtr XA_CUT_BUFFER5 = (IntPtr)14;
+ public readonly IntPtr XA_CUT_BUFFER6 = (IntPtr)15;
+ public readonly IntPtr XA_CUT_BUFFER7 = (IntPtr)16;
+ public readonly IntPtr XA_DRAWABLE = (IntPtr)17;
+ public readonly IntPtr XA_FONT = (IntPtr)18;
+ public readonly IntPtr XA_INTEGER = (IntPtr)19;
+ public readonly IntPtr XA_PIXMAP = (IntPtr)20;
+ public readonly IntPtr XA_POINT = (IntPtr)21;
+ public readonly IntPtr XA_RECTANGLE = (IntPtr)22;
+ public readonly IntPtr XA_RESOURCE_MANAGER = (IntPtr)23;
+ public readonly IntPtr XA_RGB_COLOR_MAP = (IntPtr)24;
+ public readonly IntPtr XA_RGB_BEST_MAP = (IntPtr)25;
+ public readonly IntPtr XA_RGB_BLUE_MAP = (IntPtr)26;
+ public readonly IntPtr XA_RGB_DEFAULT_MAP = (IntPtr)27;
+ public readonly IntPtr XA_RGB_GRAY_MAP = (IntPtr)28;
+ public readonly IntPtr XA_RGB_GREEN_MAP = (IntPtr)29;
+ public readonly IntPtr XA_RGB_RED_MAP = (IntPtr)30;
+ public readonly IntPtr XA_STRING = (IntPtr)31;
+ public readonly IntPtr XA_VISUALID = (IntPtr)32;
+ public readonly IntPtr XA_WINDOW = (IntPtr)33;
+ public readonly IntPtr XA_WM_COMMAND = (IntPtr)34;
+ public readonly IntPtr XA_WM_HINTS = (IntPtr)35;
+ public readonly IntPtr XA_WM_CLIENT_MACHINE = (IntPtr)36;
+ public readonly IntPtr XA_WM_ICON_NAME = (IntPtr)37;
+ public readonly IntPtr XA_WM_ICON_SIZE = (IntPtr)38;
+ public readonly IntPtr XA_WM_NAME = (IntPtr)39;
+ public readonly IntPtr XA_WM_NORMAL_HINTS = (IntPtr)40;
+ public readonly IntPtr XA_WM_SIZE_HINTS = (IntPtr)41;
+ public readonly IntPtr XA_WM_ZOOM_HINTS = (IntPtr)42;
+ public readonly IntPtr XA_MIN_SPACE = (IntPtr)43;
+ public readonly IntPtr XA_NORM_SPACE = (IntPtr)44;
+ public readonly IntPtr XA_MAX_SPACE = (IntPtr)45;
+ public readonly IntPtr XA_END_SPACE = (IntPtr)46;
+ public readonly IntPtr XA_SUPERSCRIPT_X = (IntPtr)47;
+ public readonly IntPtr XA_SUPERSCRIPT_Y = (IntPtr)48;
+ public readonly IntPtr XA_SUBSCRIPT_X = (IntPtr)49;
+ public readonly IntPtr XA_SUBSCRIPT_Y = (IntPtr)50;
+ public readonly IntPtr XA_UNDERLINE_POSITION = (IntPtr)51;
+ public readonly IntPtr XA_UNDERLINE_THICKNESS = (IntPtr)52;
+ public readonly IntPtr XA_STRIKEOUT_ASCENT = (IntPtr)53;
+ public readonly IntPtr XA_STRIKEOUT_DESCENT = (IntPtr)54;
+ public readonly IntPtr XA_ITALIC_ANGLE = (IntPtr)55;
+ public readonly IntPtr XA_X_HEIGHT = (IntPtr)56;
+ public readonly IntPtr XA_QUAD_WIDTH = (IntPtr)57;
+ public readonly IntPtr XA_WEIGHT = (IntPtr)58;
+ public readonly IntPtr XA_POINT_SIZE = (IntPtr)59;
+ public readonly IntPtr XA_RESOLUTION = (IntPtr)60;
+ public readonly IntPtr XA_COPYRIGHT = (IntPtr)61;
+ public readonly IntPtr XA_NOTICE = (IntPtr)62;
+ public readonly IntPtr XA_FONT_NAME = (IntPtr)63;
+ public readonly IntPtr XA_FAMILY_NAME = (IntPtr)64;
+ public readonly IntPtr XA_FULL_NAME = (IntPtr)65;
+ public readonly IntPtr XA_CAP_HEIGHT = (IntPtr)66;
+ public readonly IntPtr XA_WM_CLASS = (IntPtr)67;
+ public readonly IntPtr XA_WM_TRANSIENT_FOR = (IntPtr)68;
+
+ public readonly IntPtr WM_PROTOCOLS;
+ public readonly IntPtr WM_DELETE_WINDOW;
+ public readonly IntPtr WM_TAKE_FOCUS;
+ public readonly IntPtr _NET_SUPPORTED;
+ public readonly IntPtr _NET_CLIENT_LIST;
+ public readonly IntPtr _NET_NUMBER_OF_DESKTOPS;
+ public readonly IntPtr _NET_DESKTOP_GEOMETRY;
+ public readonly IntPtr _NET_DESKTOP_VIEWPORT;
+ public readonly IntPtr _NET_CURRENT_DESKTOP;
+ public readonly IntPtr _NET_DESKTOP_NAMES;
+ public readonly IntPtr _NET_ACTIVE_WINDOW;
+ public readonly IntPtr _NET_WORKAREA;
+ public readonly IntPtr _NET_SUPPORTING_WM_CHECK;
+ public readonly IntPtr _NET_VIRTUAL_ROOTS;
+ public readonly IntPtr _NET_DESKTOP_LAYOUT;
+ public readonly IntPtr _NET_SHOWING_DESKTOP;
+ public readonly IntPtr _NET_CLOSE_WINDOW;
+ public readonly IntPtr _NET_MOVERESIZE_WINDOW;
+ public readonly IntPtr _NET_WM_MOVERESIZE;
+ public readonly IntPtr _NET_RESTACK_WINDOW;
+ public readonly IntPtr _NET_REQUEST_FRAME_EXTENTS;
+ public readonly IntPtr _NET_WM_NAME;
+ public readonly IntPtr _NET_WM_VISIBLE_NAME;
+ public readonly IntPtr _NET_WM_ICON_NAME;
+ public readonly IntPtr _NET_WM_VISIBLE_ICON_NAME;
+ public readonly IntPtr _NET_WM_DESKTOP;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE;
+ public readonly IntPtr _NET_WM_STATE;
+ public readonly IntPtr _NET_WM_ALLOWED_ACTIONS;
+ public readonly IntPtr _NET_WM_STRUT;
+ public readonly IntPtr _NET_WM_STRUT_PARTIAL;
+ public readonly IntPtr _NET_WM_ICON_GEOMETRY;
+ public readonly IntPtr _NET_WM_ICON;
+ public readonly IntPtr _NET_WM_PID;
+ public readonly IntPtr _NET_WM_HANDLED_ICONS;
+ public readonly IntPtr _NET_WM_USER_TIME;
+ public readonly IntPtr _NET_FRAME_EXTENTS;
+ public readonly IntPtr _NET_WM_PING;
+ public readonly IntPtr _NET_WM_SYNC_REQUEST;
+ public readonly IntPtr _NET_SYSTEM_TRAY_S;
+ public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
+ public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE;
+ public readonly IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
+ public readonly IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
+ public readonly IntPtr _XEMBED;
+ public readonly IntPtr _XEMBED_INFO;
+ public readonly IntPtr _MOTIF_WM_HINTS;
+ public readonly IntPtr _NET_WM_STATE_SKIP_TASKBAR;
+ public readonly IntPtr _NET_WM_STATE_ABOVE;
+ public readonly IntPtr _NET_WM_STATE_MODAL;
+ public readonly IntPtr _NET_WM_STATE_HIDDEN;
+ public readonly IntPtr _NET_WM_CONTEXT_HELP;
+ public readonly IntPtr _NET_WM_WINDOW_OPACITY;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_DOCK;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_MENU;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
+ public readonly IntPtr CLIPBOARD;
+ public readonly IntPtr PRIMARY;
+ public readonly IntPtr DIB;
+ public readonly IntPtr OEMTEXT;
+ public readonly IntPtr UNICODETEXT;
+ public readonly IntPtr TARGETS;
+ public readonly IntPtr PostAtom;
+ public readonly IntPtr AsyncAtom;
+
+
+ public X11Atoms (X11Display display) {
+
+ // make sure this array stays in sync with the statements below
+ string [] atom_names = new string[] {
+ "WM_PROTOCOLS",
+ "WM_DELETE_WINDOW",
+ "WM_TAKE_FOCUS",
+ "_NET_SUPPORTED",
+ "_NET_CLIENT_LIST",
+ "_NET_NUMBER_OF_DESKTOPS",
+ "_NET_DESKTOP_GEOMETRY",
+ "_NET_DESKTOP_VIEWPORT",
+ "_NET_CURRENT_DESKTOP",
+ "_NET_DESKTOP_NAMES",
+ "_NET_ACTIVE_WINDOW",
+ "_NET_WORKAREA",
+ "_NET_SUPPORTING_WM_CHECK",
+ "_NET_VIRTUAL_ROOTS",
+ "_NET_DESKTOP_LAYOUT",
+ "_NET_SHOWING_DESKTOP",
+ "_NET_CLOSE_WINDOW",
+ "_NET_MOVERESIZE_WINDOW",
+ "_NET_WM_MOVERESIZE",
+ "_NET_RESTACK_WINDOW",
+ "_NET_REQUEST_FRAME_EXTENTS",
+ "_NET_WM_NAME",
+ "_NET_WM_VISIBLE_NAME",
+ "_NET_WM_ICON_NAME",
+ "_NET_WM_VISIBLE_ICON_NAME",
+ "_NET_WM_DESKTOP",
+ "_NET_WM_WINDOW_TYPE",
+ "_NET_WM_STATE",
+ "_NET_WM_ALLOWED_ACTIONS",
+ "_NET_WM_STRUT",
+ "_NET_WM_STRUT_PARTIAL",
+ "_NET_WM_ICON_GEOMETRY",
+ "_NET_WM_ICON",
+ "_NET_WM_PID",
+ "_NET_WM_HANDLED_ICONS",
+ "_NET_WM_USER_TIME",
+ "_NET_FRAME_EXTENTS",
+ "_NET_WM_PING",
+ "_NET_WM_SYNC_REQUEST",
+ "_NET_SYSTEM_TRAY_OPCODE",
+ "_NET_SYSTEM_TRAY_ORIENTATION",
+ "_NET_WM_STATE_MAXIMIZED_HORZ",
+ "_NET_WM_STATE_MAXIMIZED_VERT",
+ "_NET_WM_STATE_HIDDEN",
+ "_XEMBED",
+ "_XEMBED_INFO",
+ "_MOTIF_WM_HINTS",
+ "_NET_WM_STATE_SKIP_TASKBAR",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_MODAL",
+ "_NET_WM_CONTEXT_HELP",
+ "_NET_WM_WINDOW_OPACITY",
+ "_NET_WM_WINDOW_TYPE_DESKTOP",
+ "_NET_WM_WINDOW_TYPE_DOCK",
+ "_NET_WM_WINDOW_TYPE_TOOLBAR",
+ "_NET_WM_WINDOW_TYPE_MENU",
+ "_NET_WM_WINDOW_TYPE_UTILITY",
+ "_NET_WM_WINDOW_TYPE_DIALOG",
+ "_NET_WM_WINDOW_TYPE_SPLASH",
+ "_NET_WM_WINDOW_TYPE_NORMAL",
+ "CLIPBOARD",
+ "PRIMARY",
+ "COMPOUND_TEXT",
+ "UTF8_STRING",
+ "TARGETS",
+ "_SWF_AsyncAtom",
+ "_SWF_PostMessageAtom",
+ "_SWF_HoverAtom" };
+
+ IntPtr[] atoms = new IntPtr [atom_names.Length];;
+
+ Xlib.XInternAtoms (display.Handle, atom_names, atom_names.Length, false, atoms);
+
+ int off = 0;
+ WM_PROTOCOLS = atoms [off++];
+ WM_DELETE_WINDOW = atoms [off++];
+ WM_TAKE_FOCUS = atoms [off++];
+ _NET_SUPPORTED = atoms [off++];
+ _NET_CLIENT_LIST = atoms [off++];
+ _NET_NUMBER_OF_DESKTOPS = atoms [off++];
+ _NET_DESKTOP_GEOMETRY = atoms [off++];
+ _NET_DESKTOP_VIEWPORT = atoms [off++];
+ _NET_CURRENT_DESKTOP = atoms [off++];
+ _NET_DESKTOP_NAMES = atoms [off++];
+ _NET_ACTIVE_WINDOW = atoms [off++];
+ _NET_WORKAREA = atoms [off++];
+ _NET_SUPPORTING_WM_CHECK = atoms [off++];
+ _NET_VIRTUAL_ROOTS = atoms [off++];
+ _NET_DESKTOP_LAYOUT = atoms [off++];
+ _NET_SHOWING_DESKTOP = atoms [off++];
+ _NET_CLOSE_WINDOW = atoms [off++];
+ _NET_MOVERESIZE_WINDOW = atoms [off++];
+ _NET_WM_MOVERESIZE = atoms [off++];
+ _NET_RESTACK_WINDOW = atoms [off++];
+ _NET_REQUEST_FRAME_EXTENTS = atoms [off++];
+ _NET_WM_NAME = atoms [off++];
+ _NET_WM_VISIBLE_NAME = atoms [off++];
+ _NET_WM_ICON_NAME = atoms [off++];
+ _NET_WM_VISIBLE_ICON_NAME = atoms [off++];
+ _NET_WM_DESKTOP = atoms [off++];
+ _NET_WM_WINDOW_TYPE = atoms [off++];
+ _NET_WM_STATE = atoms [off++];
+ _NET_WM_ALLOWED_ACTIONS = atoms [off++];
+ _NET_WM_STRUT = atoms [off++];
+ _NET_WM_STRUT_PARTIAL = atoms [off++];
+ _NET_WM_ICON_GEOMETRY = atoms [off++];
+ _NET_WM_ICON = atoms [off++];
+ _NET_WM_PID = atoms [off++];
+ _NET_WM_HANDLED_ICONS = atoms [off++];
+ _NET_WM_USER_TIME = atoms [off++];
+ _NET_FRAME_EXTENTS = atoms [off++];
+ _NET_WM_PING = atoms [off++];
+ _NET_WM_SYNC_REQUEST = atoms [off++];
+ _NET_SYSTEM_TRAY_OPCODE = atoms [off++];
+ _NET_SYSTEM_TRAY_ORIENTATION = atoms [off++];
+ _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++];
+ _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++];
+ _NET_WM_STATE_HIDDEN = atoms [off++];
+ _XEMBED = atoms [off++];
+ _XEMBED_INFO = atoms [off++];
+ _MOTIF_WM_HINTS = atoms [off++];
+ _NET_WM_STATE_SKIP_TASKBAR = atoms [off++];
+ _NET_WM_STATE_ABOVE = atoms [off++];
+ _NET_WM_STATE_MODAL = atoms [off++];
+ _NET_WM_CONTEXT_HELP = atoms [off++];
+ _NET_WM_WINDOW_OPACITY = atoms [off++];
+ _NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++];
+ _NET_WM_WINDOW_TYPE_DOCK = atoms [off++];
+ _NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++];
+ _NET_WM_WINDOW_TYPE_MENU = atoms [off++];
+ _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++];
+ _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++];
+ _NET_WM_WINDOW_TYPE_SPLASH = atoms [off++];
+ _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++];
+ CLIPBOARD = atoms [off++];
+ PRIMARY = atoms [off++];
+ OEMTEXT = atoms [off++];
+ UNICODETEXT = atoms [off++];
+ TARGETS = atoms [off++];
+ AsyncAtom = atoms [off++];
+ PostAtom = atoms [off++];
+ display.HoverState.Atom = atoms [off++];
+
+ DIB = XA_PIXMAP;
+
+ // XXX multi screen stuff here
+ _NET_SYSTEM_TRAY_S = Xlib.XInternAtom (display.Handle, "_NET_SYSTEM_TRAY_S" + display.DefaultScreen.ToString(), false);
+ }
+
+ }
+
+}
+
diff --git a/source/ShiftUI/Internal/X11Clipboard.cs b/source/ShiftUI/Internal/X11Clipboard.cs
new file mode 100644
index 0000000..b951cc3
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Clipboard.cs
@@ -0,0 +1,105 @@
+// 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) 2009 Novell, Inc.
+//
+// Authors:
+// Carlos Alberto Cortez ([email protected])
+//
+
+using System;
+using System.Drawing;
+using System.Collections;
+using System.Collections.Specialized;
+
+namespace ShiftUI {
+
+ internal class ClipboardData {
+ ListDictionary source_data; // Source in its different formats, if any
+ string plain_text_source; // Cached source as plain-text string
+ Image image_source; // Cached source as image
+
+ internal object Item; // Object on the clipboard
+ internal ArrayList Formats; // list of formats available in the clipboard
+ internal bool Retrieving; // true if we are requesting an item
+ internal bool Enumerating; // true if we are enumerating through all known types
+ internal XplatUI.ObjectToClipboard Converter;
+
+ public ClipboardData ()
+ {
+ source_data = new ListDictionary ();
+ }
+
+ public void ClearSources ()
+ {
+ source_data.Clear ();
+ plain_text_source = null;
+ image_source = null;
+ }
+
+ public void AddSource (int type, object source)
+ {
+ // Try to detect plain text, based on the old behaviour of XplatUIX11, which usually assigns
+ // -1 as the type when a string is stored in the Clipboard
+ if (source is string && (type == DataFormats.GetFormat (DataFormats.Text).Id || type == -1))
+ plain_text_source = source as string;
+ else if (source is Image)
+ image_source = source as Image;
+
+ source_data [type] = source;
+ }
+
+ public object GetSource (int type)
+ {
+ return source_data [type];
+ }
+
+ public string GetPlainText ()
+ {
+ return plain_text_source;
+ }
+
+ public string GetRtfText ()
+ {
+ DataFormats.Format format = DataFormats.GetFormat (DataFormats.Rtf);
+ if (format == null)
+ return null; // FIXME - is RTF not supported on any system?
+
+ return (string)GetSource (format.Id);
+ }
+
+ public Image GetImage ()
+ {
+ return image_source;
+ }
+
+ public bool IsSourceText {
+ get {
+ return plain_text_source != null;
+ }
+ }
+
+ public bool IsSourceImage {
+ get {
+ return image_source != null;
+ }
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/X11DesktopColors.cs b/source/ShiftUI/Internal/X11DesktopColors.cs
new file mode 100644
index 0000000..d3cdd26
--- /dev/null
+++ b/source/ShiftUI/Internal/X11DesktopColors.cs
@@ -0,0 +1,298 @@
+// 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) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Dennis Bartok ([email protected])
+// Alexander Olk ([email protected])
+//
+//
+
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.IO;
+using System;
+
+namespace ShiftUI {
+ internal class X11DesktopColors {
+ #region Structs & Enums
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GdkColorStruct {
+ internal int pixel;
+ internal short red;
+ internal short green;
+ internal short blue;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GObjectStruct {
+ public IntPtr Instance;
+ public IntPtr ref_count;
+ public IntPtr data;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GtkStyleStruct {
+ internal GObjectStruct obj;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] fg;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] bg;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] light;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] dark;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] mid;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] text;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] baseclr;
+ [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
+ internal GdkColorStruct[] text_aa; /* Halfway between text/base */
+
+ internal GdkColorStruct black;
+ internal GdkColorStruct white;
+
+ /* TODO: There is more stuff that we will add when we need it*/
+ }
+
+ private enum Desktop {
+ Gtk,
+ KDE,
+ Unknown
+ }
+ #endregion // Structs & Enums
+
+ #region Local Variables
+ static private Desktop desktop;
+ #endregion // Local Variables
+
+ #region Constructors
+ static X11DesktopColors() {
+ FindDesktopEnvironment();
+
+ switch(desktop) {
+ case Desktop.Gtk: {
+ //IntPtr dispmgr;
+ //IntPtr gdkdisplay;
+ IntPtr widget;
+ IntPtr style_ptr;
+ GtkStyleStruct style;
+
+ try {
+ GtkInit();
+ //dispmgr = gdk_display_manager_get ();
+ //gdkdisplay = gdk_display_manager_get_default_display (dispmgr);
+
+ widget = gtk_invisible_new ();
+ gtk_widget_ensure_style (widget);
+ style_ptr = gtk_widget_get_style (widget);
+
+ style = (GtkStyleStruct) Marshal.PtrToStructure (style_ptr, typeof (GtkStyleStruct));
+
+ ThemeEngine.Current.ColorControl = ColorFromGdkColor (style.bg[0]);
+ ThemeEngine.Current.ColorControlText = ColorFromGdkColor (style.fg[0]);
+ ThemeEngine.Current.ColorControlDark = ColorFromGdkColor (style.dark[0]);
+ ThemeEngine.Current.ColorControlLight = ColorFromGdkColor (style.light[0]);
+ ThemeEngine.Current.ColorControlLightLight = WidgetPaint.Light (ThemeEngine.Current.ColorControlLight);
+ ThemeEngine.Current.ColorControlDarkDark = WidgetPaint.Dark (ThemeEngine.Current.ColorControlDark);
+
+ // We don't want WidgetLight to disappear on a white background!
+ if (ThemeEngine.Current.ColorControlLight.ToArgb () == Color.White.ToArgb ()) {
+ ThemeEngine.Current.ColorControlLight = Color.FromArgb (255, 227, 227, 227);
+ }
+ widget = gtk_menu_new ();
+ gtk_widget_ensure_style (widget);
+ style_ptr = gtk_widget_get_style (widget);
+
+ style = (GtkStyleStruct) Marshal.PtrToStructure (style_ptr, typeof (GtkStyleStruct));
+
+ ThemeEngine.Current.ColorMenu = ColorFromGdkColor (style.bg [0]);
+ ThemeEngine.Current.ColorMenuText = ColorFromGdkColor (style.text [0]);
+ }
+
+ catch (DllNotFoundException) {
+ Console.Error.WriteLine("Gtk not found (missing LD_LIBRARY_PATH to libgtk-x11-2.0.so.0?), using built-in colorscheme");
+ }
+
+ catch {
+ Console.Error.WriteLine("Gtk colorscheme read failure, using built-in colorscheme");
+ }
+ break;
+ }
+
+ case Desktop.KDE: {
+ if (! ReadKDEColorsheme() )
+ Console.Error.WriteLine("KDE colorscheme read failure, using built-in colorscheme");
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+ }
+
+ static void GtkInit ()
+ {
+ gtk_init_check (IntPtr.Zero, IntPtr.Zero);
+ }
+ #endregion // Constructors
+
+ #region Properties
+ static void FindDesktopEnvironment() {
+ desktop = Desktop.Gtk;
+ string session = Environment.GetEnvironmentVariable("DESKTOP_SESSION");
+
+ if ( session != null ) {
+ session = session.ToUpper( );
+
+ if ( session == "DEFAULT" ) {
+ string helper = Environment.GetEnvironmentVariable("KDE_FULL_SESSION");
+
+ if ( helper != null )
+ desktop = Desktop.KDE;
+ } else
+ if ( session.StartsWith("KDE") )
+ desktop = Desktop.KDE;
+ }
+ }
+ #endregion // Properties
+
+ #region Methods
+ static internal void Initialize() {
+ // Do nothing; all is done in our static ctor
+ }
+
+ private static Color ColorFromGdkColor (GdkColorStruct gtkcolor) {
+ return Color.FromArgb (255,
+ (gtkcolor.red >> 8) & 0xff,
+ (gtkcolor.green >> 8) & 0xff,
+ (gtkcolor.blue >> 8) & 0xff );
+ }
+
+ private static bool ReadKDEColorsheme() {
+ string full_kdegloabals_filename = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ + "/"
+ + ".kde/share/config/kdeglobals";
+
+ if (!File.Exists(full_kdegloabals_filename))
+ return false;
+
+ StreamReader sr = new StreamReader(full_kdegloabals_filename);
+
+ string line = sr.ReadLine();
+
+ Color tmp_color;
+
+ while (line != null) {
+ line = line.Trim();
+
+ if (line.StartsWith( "background=")) {
+ tmp_color = GetColorFromKDEString(line);
+
+ if (tmp_color != Color.Empty) {
+ ThemeEngine.Current.ColorControl = tmp_color;
+ ThemeEngine.Current.ColorMenu = tmp_color;
+ }
+ } else
+ if (line.StartsWith( "foreground=")) {
+ tmp_color = GetColorFromKDEString(line);
+
+ if (tmp_color != Color.Empty) {
+ ThemeEngine.Current.ColorControlText = tmp_color;
+ ThemeEngine.Current.ColorMenuText = tmp_color;
+ }
+ } else
+ if (line.StartsWith("selectBackground")) {
+ tmp_color = GetColorFromKDEString(line);
+
+ if (tmp_color != Color.Empty) {
+ ThemeEngine.Current.ColorHighlight = tmp_color;
+ }
+ } else
+ if (line.StartsWith("selectForeground")) {
+ tmp_color = GetColorFromKDEString(line);
+
+ if (tmp_color != Color.Empty) {
+ ThemeEngine.Current.ColorHighlightText = tmp_color;
+ }
+ }
+
+ line = sr.ReadLine();
+ }
+
+ sr.Close();
+
+ return true;
+ }
+
+ private static Color GetColorFromKDEString(string line) {
+ string[] split = line.Split(new char[] {'='});
+
+ if (split.Length > 0) {
+ line = split[1];
+
+ split = line.Split(new char[] {','});
+
+ if (split.Length == 3) {
+ int r = System.Convert.ToInt32(split[0]);
+ int g = System.Convert.ToInt32(split[1]);
+ int b = System.Convert.ToInt32(split[2]);
+
+ return Color.FromArgb(r, g, b);
+ }
+ }
+
+ return Color.Empty;
+ }
+ #endregion // Methods
+
+ #region DllImports
+ const string libgdk = "libgdk-x11-2.0.so.0";
+ const string libgtk = "libgtk-x11-2.0.so.0";
+
+ [DllImport(libgtk)]
+ static extern bool gtk_init_check (IntPtr argc, IntPtr argv);
+
+ [DllImport(libgdk)]
+ internal static extern IntPtr gdk_display_manager_get ();
+
+ [DllImport(libgdk)]
+ internal static extern IntPtr gdk_display_manager_get_default_display (IntPtr display_manager);
+
+ [DllImport(libgtk)]
+ static extern IntPtr gtk_invisible_new ();
+
+ [DllImport(libgtk)]
+ static extern IntPtr gtk_menu_new ();
+
+ //[DllImport(libgtk)]
+ //static extern IntPtr gtk_menu_item_new_with_label (string label);
+
+ [DllImport(libgtk)]
+ static extern void gtk_widget_ensure_style (IntPtr raw);
+
+ [DllImport(libgtk)]
+ static extern IntPtr gtk_widget_get_style (IntPtr raw);
+ #endregion // DllImports
+ }
+}
diff --git a/source/ShiftUI/Internal/X11Display.cs b/source/ShiftUI/Internal/X11Display.cs
new file mode 100644
index 0000000..221e5f1
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Display.cs
@@ -0,0 +1,2693 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+//
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using ShiftUI;
+// Only do the poll when building with mono for now
+#if __MonoCS__
+//using Mono.Unix.Native;
+#endif
+
+namespace ShiftUI.X11Internal {
+
+ internal class X11Display {
+
+ IntPtr display; /* our X handle */
+
+ // XXX internal because X11Hwnd needs them
+ internal IntPtr CustomVisual; // Visual for window creation
+ internal IntPtr CustomColormap; // Colormap for window creation
+
+ X11Keyboard Keyboard;
+ internal X11Dnd Dnd; // XXX X11Hwnd needs it to enable Dnd
+ bool detectable_key_auto_repeat;
+
+ X11Atoms atoms;
+ X11RootHwnd root_hwnd;
+ X11Hwnd foster_hwnd;
+
+ // Clipboard
+ IntPtr ClipMagic;
+
+ // Focus tracking
+ internal X11Hwnd ActiveWindow;
+ X11Hwnd FocusWindow;
+
+ // Modality support
+ Stack ModalWindows; // Stack of our modal windows
+
+ // Caret
+ CaretStruct Caret;
+
+ // mouse hover message generation
+ // XXX internal because X11Atoms needs to access it..
+ internal HoverStruct HoverState;
+
+ // double click message generation
+ ClickStruct ClickPending;
+ int DoubleClickInterval; // msec; max interval between clicks to count as double click
+
+ // Support for mouse grab
+ GrabStruct Grab;
+
+ // Cursors
+ IntPtr LastCursorWindow; // The last window we set the cursor on
+ IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
+ IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
+
+ // State
+ Point MousePosition; // Last position of mouse, in screen coords
+ MouseButtons MouseState; // Last state of mouse buttons
+
+ XErrorHandler ErrorHandler; // Error handler delegate
+ bool ErrorExceptions; // Throw exceptions on X errors
+
+ Thread event_thread; // the background thread that just watches our X socket
+
+#if __MonoCS__
+ Pollfd[] pollfds;
+#endif
+
+ public X11Display (IntPtr display)
+ {
+ if (display == IntPtr.Zero) {
+ throw new ArgumentNullException("Display",
+ "Could not open display (X-Server required. Check your DISPLAY environment variable)");
+ }
+
+ this.display = display;
+
+ // Debugging support
+ if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
+ Xlib.XSynchronize (display, true);
+ }
+
+ if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
+ ErrorExceptions = true;
+ }
+
+ atoms = new X11Atoms (this);
+
+ DoubleClickInterval = 500;
+
+ HoverState.Interval = 500;
+ HoverState.Timer = new Timer();
+ HoverState.Timer.Enabled = false;
+ HoverState.Timer.Interval = HoverState.Interval;
+ HoverState.Timer.Tick += new EventHandler(MouseHover);
+ HoverState.Size = new Size(4, 4);
+ HoverState.X = -1;
+ HoverState.Y = -1;
+
+ ActiveWindow = null;
+ FocusWindow = null;
+ ModalWindows = new Stack(3);
+
+ MouseState = MouseButtons.None;
+ MousePosition = new Point(0, 0);
+
+ Caret.Timer = new Timer();
+ Caret.Timer.Interval = 500; // FIXME - where should this number come from?
+ Caret.Timer.Tick += new EventHandler(CaretCallback);
+
+ // XXX multiscreen work here
+ root_hwnd = new X11RootHwnd (this, Xlib.XRootWindow (display, DefaultScreen));
+
+ // XXX do we need a per-screen foster parent?
+ // Create the foster parent
+ foster_hwnd = new X11Hwnd (this,
+ Xlib.XCreateSimpleWindow (display, root_hwnd.WholeWindow,
+ 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero));
+
+#if __MonoCS__
+ pollfds = new Pollfd [1];
+ pollfds [0] = new Pollfd ();
+ pollfds [0].fd = Xlib.XConnectionNumber (display);
+ pollfds [0].events = PollEvents.POLLIN;
+#endif
+
+ Keyboard = new X11Keyboard(display, foster_hwnd.Handle);
+ Dnd = new X11Dnd (display, Keyboard);
+
+ ErrorExceptions = false;
+
+ // Handle any upcoming errors
+ ErrorHandler = new XErrorHandler (HandleError);
+ Xlib.XSetErrorHandler (ErrorHandler);
+
+ X11DesktopColors.Initialize(); // XXX we need to figure out how to make this display specific?
+
+ // Disable keyboard autorepeat
+ try {
+ Xlib.XkbSetDetectableAutoRepeat (display, true, IntPtr.Zero);
+ detectable_key_auto_repeat = true;
+ } catch {
+ Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually.");
+ detectable_key_auto_repeat = false;
+ }
+
+ // we re-set our error handler here, X11DesktopColor stuff might have stolen it (gtk does)
+ Xlib.XSetErrorHandler (ErrorHandler);
+
+ // create our event thread (just sits on the X socket waiting for events)
+ event_thread = new Thread (new ThreadStart (XEventThread));
+ event_thread.IsBackground = true;
+ event_thread.Start ();
+ }
+
+ #region Callbacks
+ private void MouseHover(object sender, EventArgs e)
+ {
+ HoverState.Timer.Enabled = false;
+
+ if (HoverState.Window != IntPtr.Zero) {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (HoverState.Window);
+ if (hwnd != null) {
+ XEvent xevent = new XEvent ();
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = display;
+ xevent.ClientMessageEvent.window = HoverState.Window;
+ xevent.ClientMessageEvent.message_type = HoverState.Atom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
+
+ hwnd.Queue.Enqueue (xevent);
+ }
+ }
+ }
+
+ private void CaretCallback (object sender, EventArgs e)
+ {
+ if (Caret.Paused) {
+ return;
+ }
+ Caret.On = !Caret.On;
+
+ Xlib.XDrawLine (display, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+
+ internal string WhereString ()
+ {
+ StackTrace stack;
+ StackFrame frame;
+ string newline;
+ string unknown;
+ StringBuilder sb;
+ MethodBase method;
+
+ newline = String.Format("{0}\t {1} ", Environment.NewLine, "at");
+ unknown = "<unknown method>";
+ sb = new StringBuilder();
+ stack = new StackTrace(true);
+
+ for (int i = 0; i < stack.FrameCount; i++) {
+ frame = stack.GetFrame (i);
+ sb.Append(newline);
+
+ method = frame.GetMethod();
+ if (method != null) {
+ if (frame.GetFileLineNumber() != 0)
+ sb.AppendFormat ("{0}.{1} () [{2}:{3}]",
+ method.DeclaringType.FullName, method.Name,
+ Path.GetFileName(frame.GetFileName()), frame.GetFileLineNumber());
+ else
+ sb.AppendFormat ("{0}.{1} ()", method.DeclaringType.FullName, method.Name);
+ } else {
+ sb.Append(unknown);
+ }
+ }
+ return sb.ToString();
+ }
+
+ private int HandleError (IntPtr display, ref XErrorEvent error_event)
+ {
+ if (ErrorExceptions)
+ throw new X11Exception (error_event.display, error_event.resourceid,
+ error_event.serial, error_event.error_code,
+ error_event.request_code, error_event.minor_code);
+ else
+ Console.WriteLine ("X11 Error encountered: {0}{1}\n",
+ X11Exception.GetMessage(error_event.display, error_event.resourceid,
+ error_event.serial, error_event.error_code,
+ error_event.request_code, error_event.minor_code),
+ WhereString());
+ return 0;
+ }
+ #endregion // Callbacks
+
+ private void ShowCaret()
+ {
+ if ((Caret.gc == IntPtr.Zero) || Caret.On) {
+ return;
+ }
+ Caret.On = true;
+
+ Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+
+ private void HideCaret()
+ {
+ if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
+ return;
+ }
+ Caret.On = false;
+
+ Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+
+ public void CaretVisible (IntPtr handle, bool visible)
+ {
+ if (Caret.Hwnd == handle) {
+ if (visible) {
+ if (!Caret.Visible) {
+ Caret.Visible = true;
+ ShowCaret();
+ Caret.Timer.Start();
+ }
+ } else {
+ Caret.Visible = false;
+ Caret.Timer.Stop();
+ HideCaret();
+ }
+ }
+ }
+
+ public void AudibleAlert ()
+ {
+ Xlib.XBell (display, 0);
+ }
+
+ public void Flush ()
+ {
+ Xlib.XFlush (display);
+ }
+
+ public void Close ()
+ {
+ // XXX shut down the event_thread
+ Xlib.XCloseDisplay (display);
+ }
+
+ public IntPtr XGetParent(IntPtr handle)
+ {
+ IntPtr Root;
+ IntPtr Parent;
+ IntPtr Children;
+ int ChildCount;
+
+ Xlib.XQueryTree (display, handle, out Root, out Parent, out Children, out ChildCount);
+
+ if (Children!=IntPtr.Zero) {
+ Xlib.XFree(Children);
+ }
+
+ return Parent;
+ }
+
+ public bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt)
+ {
+ IntPtr SystrayMgrWindow;
+
+ Xlib.XGrabServer (display);
+ SystrayMgrWindow = Xlib.XGetSelectionOwner (display, Atoms._NET_SYSTEM_TRAY_S);
+ Xlib.XUngrabServer (display);
+
+ if (SystrayMgrWindow != IntPtr.Zero) {
+ XSizeHints size_hints;
+ X11Hwnd hwnd;
+
+ hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+#if DriverDebug
+ Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}",
+ hwnd.WholeWindow.ToInt32(), hwnd.ClientWindow.ToInt32());
+#endif
+
+ // Oh boy.
+ if (hwnd.ClientWindow != hwnd.WholeWindow) {
+ Xlib.XDestroyWindow (display, hwnd.ClientWindow);
+ hwnd.ClientWindow = hwnd.WholeWindow;
+
+ try {
+ hwnd.Queue.Lock ();
+
+ /* by virtue of the way the tests are ordered when determining if it's PAINT
+ or NCPAINT, ClientWindow == WholeWindow will always be PAINT. So, if we're
+ waiting on an nc_expose, drop it and remove the hwnd from the list (unless
+ there's a pending expose). */
+ hwnd.PendingNCExpose = false;
+ }
+ finally {
+ hwnd.Queue.Unlock ();
+ }
+ }
+
+ size_hints = new XSizeHints();
+
+ size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
+
+ size_hints.min_width = 24;
+ size_hints.min_height = 24;
+ size_hints.max_width = 24;
+ size_hints.max_height = 24;
+ size_hints.base_width = 24;
+ size_hints.base_height = 24;
+
+ Xlib.XSetWMNormalHints (display, hwnd.WholeWindow, ref size_hints);
+
+ int[] atoms = new int[2];
+ atoms [0] = 1; // Version 1
+ atoms [1] = 1; // we want to be mapped
+
+ // This line cost me 3 days...
+ Xlib.XChangeProperty (display,
+ hwnd.WholeWindow, Atoms._XEMBED_INFO, Atoms._XEMBED_INFO, 32,
+ PropertyMode.Replace, atoms, 2);
+
+ // Need to pick some reasonable defaults
+ tt = new ToolTip();
+ tt.AutomaticDelay = 100;
+ tt.InitialDelay = 250;
+ tt.ReshowDelay = 250;
+ tt.ShowAlways = true;
+
+ if ((tip != null) && (tip != string.Empty)) {
+ tt.SetToolTip(Widget.FromHandle(handle), tip);
+ tt.Active = true;
+ } else {
+ tt.Active = false;
+ }
+
+ SendNetClientMessage (SystrayMgrWindow,
+ Atoms._NET_SYSTEM_TRAY_OPCODE,
+ IntPtr.Zero,
+ (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK,
+ hwnd.WholeWindow);
+
+ return true;
+ }
+
+ tt = null;
+ return false;
+ }
+
+ public bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt)
+ {
+ Widget Widget;
+
+ Widget = Widget.FromHandle(handle);
+ if (Widget != null && tt != null) {
+ tt.SetToolTip(Widget, tip);
+ tt.Active = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void SystrayRemove(IntPtr handle, ref ToolTip tt)
+ {
+#if GTKSOCKET_SUPPORTS_REPARENTING
+ X11Hwnd hwnd;
+
+ hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ /* in the XEMBED spec, it mentions 3 ways for a client window to break the protocol with the embedder.
+ * 1. The embedder can unmap the window and reparent to the root window (we should probably handle this...)
+ * 2. The client can reparent its window out of the embedder window.
+ * 3. The client can destroy its window.
+ *
+ * this call to SetParent is case 2, but in
+ * the spec it also mentions that gtk doesn't
+ * support this at present. Looking at HEAD
+ * gtksocket-x11.c jives with this statement.
+ *
+ * so we can't reparent. we have to destroy.
+ */
+ SetParent(hwnd.WholeWindow, FosterParent);
+#else
+ Widget Widget = Widget.FromHandle(handle);
+ if (Widget is NotifyIcon.NotifyIconWindow)
+ ((NotifyIcon.NotifyIconWindow)Widget).InternalRecreateHandle ();
+#endif
+
+ // The caller can now re-dock it later...
+ if (tt != null) {
+ tt.Dispose();
+ tt = null;
+ }
+ }
+
+ public void ResetMouseHover (X11Hwnd hovering)
+ {
+ HoverState.Timer.Enabled = hovering != null;
+ HoverState.X = MousePosition.X;
+ HoverState.Y = MousePosition.Y;
+ HoverState.Window = hovering == null ? IntPtr.Zero : hovering.Handle;
+ }
+
+ public void ShowCursor (bool show)
+ {
+ ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
+ }
+
+ public void SetModal (X11Hwnd hwnd, bool Modal)
+ {
+ if (Modal) {
+ ModalWindows.Push(hwnd);
+ } else {
+ // XXX do we need to pop until the
+ // hwnd is off the stack? or just the
+ // most recently pushed hwnd?
+ if (ModalWindows.Contains(hwnd)) {
+ ModalWindows.Pop();
+ }
+
+ if (ModalWindows.Count > 0) {
+ X11Hwnd top_hwnd = (X11Hwnd)ModalWindows.Peek();
+ top_hwnd.Activate();
+ }
+ }
+ }
+
+ public TransparencySupport SupportsTransparency ()
+ {
+ // compiz adds _NET_WM_WINDOW_OPACITY to _NET_SUPPORTED on the root window, check for that
+ return ((IList)root_hwnd._NET_SUPPORTED).Contains (Atoms._NET_WM_WINDOW_OPACITY) ? TransparencySupport.GetSet : TransparencySupport.None;
+ }
+
+ public void SendAsyncMethod (AsyncMethodData method)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(method.Handle);
+ XEvent xevent = new XEvent ();
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = display;
+ xevent.ClientMessageEvent.window = method.Handle;
+ xevent.ClientMessageEvent.message_type = Atoms.AsyncAtom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
+
+ hwnd.Queue.Enqueue (xevent);
+ }
+
+ delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
+
+ public IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+ if (hwnd == null)
+ return IntPtr.Zero;
+
+ if (hwnd.Queue.Thread != Thread.CurrentThread) {
+ AsyncMethodResult result;
+ AsyncMethodData data;
+
+ result = new AsyncMethodResult ();
+ data = new AsyncMethodData ();
+
+ data.Handle = hwnd.Handle;
+ data.Method = new WndProcDelegate (NativeWindow.WndProc);
+ data.Args = new object[] { hwnd.Handle, message, wParam, lParam };
+ data.Result = result;
+
+ SendAsyncMethod (data);
+#if DriverDebug || DriverDebugThreads
+ Console.WriteLine ("Sending {0} message across.", message);
+#endif
+
+ return IntPtr.Zero;
+ }
+ else {
+ return NativeWindow.WndProc (hwnd.Handle, message, wParam, lParam);
+ }
+ }
+
+ public int SendInput (IntPtr handle, Queue keys) {
+ if (handle == IntPtr.Zero)
+ return 0;
+
+ int count = keys.Count;
+ Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
+
+ while (keys.Count > 0) {
+
+ MSG msg = (MSG)keys.Dequeue();
+
+ XEvent xevent = new XEvent ();
+
+ xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
+ xevent.KeyEvent.display = display;
+
+ if (hwnd != null) {
+ xevent.KeyEvent.window = hwnd.whole_window;
+ } else {
+ xevent.KeyEvent.window = IntPtr.Zero;
+ }
+
+ xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
+
+ hwnd.Queue.EnqueueLocked (xevent);
+ }
+ return count;
+ }
+
+ // FIXME - I think this should just enqueue directly
+ public bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam)
+ {
+ XEvent xevent = new XEvent ();
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = display;
+
+ if (hwnd != null) {
+ xevent.ClientMessageEvent.window = hwnd.WholeWindow;
+ } else {
+ xevent.ClientMessageEvent.window = IntPtr.Zero;
+ }
+
+ xevent.ClientMessageEvent.message_type = Atoms.PostAtom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = handle;
+ xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
+ xevent.ClientMessageEvent.ptr3 = wparam;
+ xevent.ClientMessageEvent.ptr4 = lparam;
+
+ hwnd.Queue.Enqueue (xevent);
+
+ return true;
+ }
+
+ public void SendNetWMMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
+ {
+ XEvent xev;
+
+ xev = new XEvent();
+ xev.ClientMessageEvent.type = XEventName.ClientMessage;
+ xev.ClientMessageEvent.send_event = true;
+ xev.ClientMessageEvent.window = window;
+ xev.ClientMessageEvent.message_type = message_type;
+ xev.ClientMessageEvent.format = 32;
+ xev.ClientMessageEvent.ptr1 = l0;
+ xev.ClientMessageEvent.ptr2 = l1;
+ xev.ClientMessageEvent.ptr3 = l2;
+
+ Xlib.XSendEvent (display, root_hwnd.Handle, false,
+ new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
+ }
+
+ public void SendNetClientMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
+ {
+ XEvent xev;
+
+ xev = new XEvent();
+ xev.ClientMessageEvent.type = XEventName.ClientMessage;
+ xev.ClientMessageEvent.send_event = true;
+ xev.ClientMessageEvent.window = window;
+ xev.ClientMessageEvent.message_type = message_type;
+ xev.ClientMessageEvent.format = 32;
+ xev.ClientMessageEvent.ptr1 = l0;
+ xev.ClientMessageEvent.ptr2 = l1;
+ xev.ClientMessageEvent.ptr3 = l2;
+
+ Xlib.XSendEvent (display, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev);
+ }
+
+ public bool TranslateMessage (ref MSG msg)
+ {
+ return Keyboard.TranslateMessage (ref msg);
+ }
+
+ public IntPtr DispatchMessage (ref MSG msg)
+ {
+ return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ }
+
+ private void QueryPointer (IntPtr w, out IntPtr root, out IntPtr child,
+ out int root_x, out int root_y, out int child_x, out int child_y,
+ out int mask)
+ {
+ /* this code was written with the help of
+ glance at gdk. I never would have realized we
+ needed a loop in order to traverse down in the
+ hierarchy. I would have assumed you'd get the
+ most deeply nested child and have to do
+ XQueryTree to move back up the hierarchy..
+ stupid me, of course. */
+ IntPtr c;
+
+ // Xlib.XGrabServer (display);
+
+ Xlib.XQueryPointer (display, w, out root, out c,
+ out root_x, out root_y, out child_x, out child_y,
+ out mask);
+
+ if (root != w)
+ c = root;
+
+ IntPtr child_last = IntPtr.Zero;
+ while (c != IntPtr.Zero) {
+ child_last = c;
+ Xlib.XQueryPointer (display, c, out root, out c,
+ out root_x, out root_y, out child_x, out child_y,
+ out mask);
+ }
+
+ // Xlib.XUngrabServer (display);
+
+ child = child_last;
+ }
+
+ public void SetCursorPos (int x, int y)
+ {
+ IntPtr root, child;
+ int root_x, root_y, child_x, child_y, mask;
+
+ /* we need to do a
+ * QueryPointer before warping
+ * because if the warp is on
+ * the RootWindow, the x/y are
+ * relative to the current
+ * mouse position
+ */
+ QueryPointer (RootWindow.Handle,
+ out root,
+ out child,
+ out root_x, out root_y,
+ out child_x, out child_y,
+ out mask);
+
+ Xlib.XWarpPointer (display, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
+
+ Xlib.XFlush (display);
+
+ /* then we need to a
+ * QueryPointer after warping
+ * to manually generate a
+ * motion event for the window
+ * we move into.
+ */
+ QueryPointer (RootWindow.Handle,
+ out root,
+ out child,
+ out root_x, out root_y,
+ out child_x, out child_y,
+ out mask);
+
+ X11Hwnd child_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(child);
+ if (child_hwnd == null)
+ return;
+
+ XEvent xevent = new XEvent ();
+
+ xevent.type = XEventName.MotionNotify;
+ xevent.MotionEvent.display = display;
+ xevent.MotionEvent.window = child_hwnd.Handle;
+ xevent.MotionEvent.root = RootWindow.Handle;
+ xevent.MotionEvent.x = child_x;
+ xevent.MotionEvent.y = child_y;
+ xevent.MotionEvent.x_root = root_x;
+ xevent.MotionEvent.y_root = root_y;
+ xevent.MotionEvent.state = mask;
+
+ child_hwnd.Queue.Enqueue (xevent);
+ }
+
+ public void SetFocus (X11Hwnd new_focus)
+ {
+ if (new_focus == FocusWindow)
+ return;
+
+ X11Hwnd prev_focus = FocusWindow;
+ FocusWindow = new_focus;
+
+ if (prev_focus != null)
+ SendMessage (prev_focus.Handle, Msg.WM_KILLFOCUS,
+ FocusWindow == null ? IntPtr.Zero : FocusWindow.Handle, IntPtr.Zero);
+ if (FocusWindow != null)
+ SendMessage (FocusWindow.Handle, Msg.WM_SETFOCUS,
+ prev_focus == null ? IntPtr.Zero : prev_focus.Handle, IntPtr.Zero);
+
+ //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).ClientWindow, RevertTo.None, IntPtr.Zero);
+ }
+
+ public IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
+ {
+ IntPtr cursor;
+ Bitmap cursor_bitmap;
+ Bitmap cursor_mask;
+ Byte[] cursor_bits;
+ Byte[] mask_bits;
+ Color c_pixel;
+ Color m_pixel;
+ int width;
+ int height;
+ IntPtr cursor_pixmap;
+ IntPtr mask_pixmap;
+ XColor fg;
+ XColor bg;
+ bool and;
+ bool xor;
+
+ if (Xlib.XQueryBestCursor (display, RootWindow.Handle, bitmap.Width, bitmap.Height, out width, out height) == 0) {
+ return IntPtr.Zero;
+ }
+
+ // Win32 only allows creation cursors of a certain size
+ if ((bitmap.Width != width) || (bitmap.Width != height)) {
+ cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
+ cursor_mask = new Bitmap(mask, new Size(width, height));
+ } else {
+ cursor_bitmap = bitmap;
+ cursor_mask = mask;
+ }
+
+ width = cursor_bitmap.Width;
+ height = cursor_bitmap.Height;
+
+ cursor_bits = new Byte[(width / 8) * height];
+ mask_bits = new Byte[(width / 8) * height];
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ c_pixel = cursor_bitmap.GetPixel(x, y);
+ m_pixel = cursor_mask.GetPixel(x, y);
+
+ and = c_pixel == cursor_pixel;
+ xor = m_pixel == mask_pixel;
+
+ if (!and && !xor) {
+ // Black
+ // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
+ mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+ } else if (and && !xor) {
+ // White
+ cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+ mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+#if notneeded
+ } else if (and && !xor) {
+ // Screen
+ } else if (and && xor) {
+ // Inverse Screen
+
+ // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
+ // we want both to be 0 so nothing to be done
+ //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
+ //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
+#endif
+ }
+ }
+ }
+
+ cursor_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle,
+ cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
+ mask_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle,
+ mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
+ fg = new XColor();
+ bg = new XColor();
+
+ fg.pixel = Xlib.XWhitePixel (display, DefaultScreen);
+ fg.red = (ushort)65535;
+ fg.green = (ushort)65535;
+ fg.blue = (ushort)65535;
+
+ bg.pixel = Xlib.XBlackPixel (display, DefaultScreen);
+
+ cursor = Xlib.XCreatePixmapCursor (display, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
+
+ Xlib.XFreePixmap (display, cursor_pixmap);
+ Xlib.XFreePixmap (display, mask_pixmap);
+
+ return cursor;
+ }
+
+ public Bitmap DefineStdCursorBitmap (StdCursor id)
+ {
+ CursorFontShape shape;
+ string name;
+ IntPtr theme;
+ int size;
+ Bitmap bmp = null;
+
+ try {
+ shape = XplatUIX11.StdCursorToFontShape (id);
+ name = shape.ToString ().Replace ("XC_", string.Empty);
+ size = XplatUIX11.XcursorGetDefaultSize (Handle);
+ theme = XplatUIX11.XcursorGetTheme (Handle);
+ IntPtr images_ptr = XplatUIX11.XcursorLibraryLoadImages (name, theme, size);
+#if debug
+ Console.WriteLine ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr);
+#endif
+
+ if (images_ptr == IntPtr.Zero) {
+ return null;
+ }
+
+ XcursorImages images = (XcursorImages)Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
+#if debug
+ Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
+#endif
+
+ if (images.nimage > 0) {
+ // We only care about the first image.
+ XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
+
+#if debug
+ Console.WriteLine ("DefineStdCursorBitmap, loaded image <size={0}, height={1}, width={2}, xhot={3}, yhot={4}, pixels={5}", image.size, image.height, image.width, image.xhot, image.yhot, image.pixels);
+#endif
+ // A sanity check
+ if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
+ int [] pixels = new int [image.width * image.height];
+ Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
+ bmp = new Bitmap (image.width, image.height);
+ for (int w = 0; w < image.width; w++) {
+ for (int h = 0; h < image.height; h++) {
+ bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
+ }
+ }
+ }
+ }
+
+ XplatUIX11.XcursorImagesDestroy (images_ptr);
+
+ } catch (DllNotFoundException ex) {
+ Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
+ return null;
+ }
+
+ return bmp;
+ }
+
+ public IntPtr DefineStdCursor (StdCursor id)
+ {
+ CursorFontShape shape;
+
+ // FIXME - define missing shapes
+
+ switch (id) {
+ case StdCursor.AppStarting:
+ shape = CursorFontShape.XC_watch;
+ break;
+
+ case StdCursor.Arrow:
+ shape = CursorFontShape.XC_top_left_arrow;
+ break;
+
+ case StdCursor.Cross:
+ shape = CursorFontShape.XC_crosshair;
+ break;
+
+ case StdCursor.Default:
+ shape = CursorFontShape.XC_top_left_arrow;
+ break;
+
+ case StdCursor.Hand:
+ shape = CursorFontShape.XC_hand1;
+ break;
+
+ case StdCursor.Help:
+ shape = CursorFontShape.XC_question_arrow;
+ break;
+
+ case StdCursor.HSplit:
+ shape = CursorFontShape.XC_sb_v_double_arrow;
+ break;
+
+ case StdCursor.IBeam:
+ shape = CursorFontShape.XC_xterm;
+ break;
+
+ case StdCursor.No:
+ shape = CursorFontShape.XC_circle;
+ break;
+
+ case StdCursor.NoMove2D:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.NoMoveHoriz:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.NoMoveVert:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanEast:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanNE:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanNorth:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanNW:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanSE:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanSouth:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanSW:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.PanWest:
+ shape = CursorFontShape.XC_sizing;
+ break;
+
+ case StdCursor.SizeAll:
+ shape = CursorFontShape.XC_fleur;
+ break;
+
+ case StdCursor.SizeNESW:
+ shape = CursorFontShape.XC_top_right_corner;
+ break;
+
+ case StdCursor.SizeNS:
+ shape = CursorFontShape.XC_sb_v_double_arrow;
+ break;
+
+ case StdCursor.SizeNWSE:
+ shape = CursorFontShape.XC_top_left_corner;
+ break;
+
+ case StdCursor.SizeWE:
+ shape = CursorFontShape.XC_sb_h_double_arrow;
+ break;
+
+ case StdCursor.UpArrow:
+ shape = CursorFontShape.XC_center_ptr;
+ break;
+
+ case StdCursor.VSplit:
+ shape = CursorFontShape.XC_sb_h_double_arrow;
+ break;
+
+ case StdCursor.WaitCursor:
+ shape = CursorFontShape.XC_watch;
+ break;
+
+ default:
+ return IntPtr.Zero;
+ }
+
+ return Xlib.XCreateFontCursor (display, shape);
+ }
+
+ // XXX this should take an X11Hwnd.
+ public void CreateCaret (IntPtr handle, int width, int height)
+ {
+ XGCValues gc_values;
+ X11Hwnd hwnd;
+
+ hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (Caret.Hwnd != IntPtr.Zero)
+ DestroyCaret(Caret.Hwnd);
+
+ Caret.Hwnd = handle;
+ Caret.Window = hwnd.ClientWindow;
+ Caret.Width = width;
+ Caret.Height = height;
+ Caret.Visible = false;
+ Caret.On = false;
+
+ gc_values = new XGCValues();
+ gc_values.line_width = width;
+
+ Caret.gc = Xlib.XCreateGC (display, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
+ if (Caret.gc == IntPtr.Zero) {
+ Caret.Hwnd = IntPtr.Zero;
+ return;
+ }
+
+ Xlib.XSetFunction (display, Caret.gc, GXFunction.GXinvert);
+ }
+
+
+ // XXX this should take an X11Hwnd.
+ public void DestroyCaret (IntPtr handle)
+ {
+ if (Caret.Hwnd == handle) {
+ if (Caret.Visible == true) {
+ Caret.Timer.Stop ();
+ }
+ if (Caret.gc != IntPtr.Zero) {
+ Xlib.XFreeGC (display, Caret.gc);
+ Caret.gc = IntPtr.Zero;
+ }
+ Caret.Hwnd = IntPtr.Zero;
+ Caret.Visible = false;
+ Caret.On = false;
+ }
+ }
+
+ public void SetCaretPos (IntPtr handle, int x, int y)
+ {
+ if (Caret.Hwnd == handle) {
+ Caret.Timer.Stop();
+ HideCaret();
+
+ Caret.X = x;
+ Caret.Y = y;
+
+ if (Caret.Visible == true) {
+ ShowCaret();
+ Caret.Timer.Start();
+ }
+ }
+ }
+
+ public void DestroyCursor (IntPtr cursor)
+ {
+ Xlib.XFreeCursor (display, cursor);
+ }
+
+ private void AccumulateDestroyedHandles (Widget c, ArrayList list)
+ {
+ if (c != null) {
+ Widget[] Widgets = c.Widgets.GetAllWidgets ();
+
+ if (c.IsHandleCreated && !c.IsDisposed) {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(c.Handle);
+
+#if DriverDebug || DriverDebugDestroy
+ Console.WriteLine (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
+ Console.WriteLine (" + parent X window is {0:X}", XGetParent (hwnd.WholeWindow).ToInt32());
+#endif
+
+ list.Add (hwnd);
+ CleanupCachedWindows (hwnd);
+ hwnd.zombie = true;
+ }
+
+ for (int i = 0; i < Widgets.Length; i ++) {
+ AccumulateDestroyedHandles (Widgets[i], list);
+ }
+ }
+
+ }
+
+ void CleanupCachedWindows (X11Hwnd hwnd)
+ {
+ if (ActiveWindow == hwnd) {
+ SendMessage (hwnd.ClientWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
+ ActiveWindow = null;
+ }
+
+ if (FocusWindow == hwnd) {
+ SendMessage (hwnd.ClientWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
+ FocusWindow = null;
+ }
+
+ if (Grab.Hwnd == hwnd.Handle) {
+ Grab.Hwnd = IntPtr.Zero;
+ Grab.Confined = false;
+ }
+
+ DestroyCaret (hwnd.Handle);
+ }
+
+
+ public void DestroyWindow (X11Hwnd hwnd)
+ {
+ CleanupCachedWindows (hwnd);
+
+ hwnd.SendParentNotify (Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
+
+ ArrayList windows = new ArrayList ();
+
+ AccumulateDestroyedHandles (Widget.WidgetNativeWindow.WidgetFromHandle(hwnd.Handle), windows);
+
+ hwnd.DestroyWindow ();
+
+ foreach (X11Hwnd h in windows) {
+ SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ public X11Hwnd GetActiveWindow ()
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr active = IntPtr.Zero;
+
+ Xlib.XGetWindowProperty (display, RootWindow.Handle,
+ Atoms._NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false,
+ Atoms.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
+ active = (IntPtr)Marshal.ReadInt32(prop);
+ Xlib.XFree(prop);
+ }
+
+ return (X11Hwnd)Hwnd.GetObjectFromWindow(active);
+ }
+
+ public void SetActiveWindow (X11Hwnd new_active_window)
+ {
+ if (new_active_window != ActiveWindow) {
+ if (ActiveWindow != null)
+ PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE,
+ (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
+
+ ActiveWindow = new_active_window;
+
+ if (ActiveWindow != null)
+ PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE,
+ (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
+ }
+
+ if (ModalWindows.Count > 0) {
+ // Modality handling, if we are modal and the new active window is one
+ // of ours but not the modal one, switch back to the modal window
+
+ if (ActiveWindow != null &&
+ NativeWindow.FromHandle (ActiveWindow.Handle) != null) {
+ if (ActiveWindow != (X11Hwnd)ModalWindows.Peek())
+ ((X11Hwnd)ModalWindows.Peek()).Activate ();
+ }
+ }
+ }
+
+ public void GetDisplaySize (out Size size)
+ {
+ XWindowAttributes attributes = new XWindowAttributes();
+
+ // FIXME - use _NET_WM messages instead?
+ Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
+
+ size = new Size(attributes.width, attributes.height);
+ }
+
+ // XXX this method doesn't really fit well anywhere in the backend
+ public 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; // XXX my god, where did this number come from?
+
+ g = Graphics.FromHwnd (FosterParent.Handle);
+
+ width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
+ return new SizeF(width, font.Height);
+ }
+
+ public void GetCursorPos (X11Hwnd hwnd, out int x, out int y)
+ {
+ IntPtr use_handle;
+ IntPtr root;
+ IntPtr child;
+ int root_x;
+ int root_y;
+ int win_x;
+ int win_y;
+ int keys_buttons;
+
+ if (hwnd != null)
+ use_handle = hwnd.Handle;
+ else
+ use_handle = RootWindow.Handle;
+
+ QueryPointer (use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
+
+ if (hwnd != null) {
+ x = win_x;
+ y = win_y;
+ } else {
+ x = root_x;
+ y = root_y;
+ }
+ }
+
+ public IntPtr GetFocus ()
+ {
+ return FocusWindow.Handle;
+ }
+
+ public 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;
+ }
+
+ public void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea)
+ {
+ handle = Grab.Hwnd;
+ GrabConfined = Grab.Confined;
+ GrabArea = Grab.Area;
+ }
+
+ public void GrabWindow (X11Hwnd hwnd, X11Hwnd confine_to)
+ {
+ IntPtr confine_to_window;
+
+ confine_to_window = IntPtr.Zero;
+
+ if (confine_to != null) {
+ Console.WriteLine (Environment.StackTrace);
+
+ XWindowAttributes attributes = new XWindowAttributes();
+
+ Xlib.XGetWindowAttributes (display, confine_to.ClientWindow, ref attributes);
+
+ Grab.Area.X = attributes.x;
+ Grab.Area.Y = attributes.y;
+ Grab.Area.Width = attributes.width;
+ Grab.Area.Height = attributes.height;
+ Grab.Confined = true;
+ confine_to_window = confine_to.ClientWindow;
+ }
+
+ Grab.Hwnd = hwnd.ClientWindow;
+
+ Xlib.XGrabPointer (display, hwnd.ClientWindow, false,
+ EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
+ EventMask.ButtonReleaseMask | EventMask.PointerMotionMask,
+ GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ public void UngrabWindow (X11Hwnd hwnd)
+ {
+ Xlib.XUngrabPointer (display, IntPtr.Zero);
+ Xlib.XFlush (display);
+
+ // XXX make sure hwnd is what should have the grab and throw if not
+ Grab.Hwnd = IntPtr.Zero;
+ Grab.Confined = false;
+ }
+
+#if notyet
+ private void TranslatePropertyToClipboard (IntPtr property)
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Clipboard.Item = null;
+
+ Xlib.XGetWindowProperty (display, FosterParent.Handle,
+ property, IntPtr.Zero, new IntPtr (0x7fffffff), true,
+ Atoms.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if ((long)nitems > 0) {
+ if (property == Atoms.XA_STRING) {
+ Clipboard.Item = Marshal.PtrToStringAnsi(prop);
+ } else if (property == Atoms.XA_BITMAP) {
+ // FIXME - convert bitmap to image
+ } else if (property == Atoms.XA_PIXMAP) {
+ // FIXME - convert pixmap to image
+ } else if (property == Atoms.OEMTEXT) {
+ Clipboard.Item = Marshal.PtrToStringAnsi(prop);
+ } else if (property == Atoms.UNICODETEXT) {
+ Clipboard.Item = Marshal.PtrToStringAnsi(prop);
+ }
+
+ Xlib.XFree(prop);
+ }
+ }
+#endif
+
+ // XXX should we be using @handle instead of Atoms.CLIPBOARD here?
+ public int[] ClipboardAvailableFormats (IntPtr handle)
+ {
+ // XXX deal with the updatemessagequeue stuff
+#if true
+ return new int[0];
+#else
+ DataFormats.Format f;
+ int[] result;
+
+ f = DataFormats.Format.List;
+
+ if (Xlib.XGetSelectionOwner (display, Atoms.CLIPBOARD) == IntPtr.Zero) {
+ return null;
+ }
+
+ Clipboard.Formats = new ArrayList();
+
+ while (f != null) {
+ Xlib.XConvertSelection (display, Atoms.CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent.Handle, IntPtr.Zero);
+
+ Clipboard.Enumerating = true;
+ while (Clipboard.Enumerating) {
+ UpdateMessageQueue(null);
+ }
+ f = f.Next;
+ }
+
+ result = new int[Clipboard.Formats.Count];
+
+ for (int i = 0; i < Clipboard.Formats.Count; i++) {
+ result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
+ }
+
+ Clipboard.Formats = null;
+ return result;
+#endif
+ }
+
+ public void ClipboardClose (IntPtr handle)
+ {
+ if (handle != ClipMagic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+ return;
+ }
+
+ public int ClipboardGetID (IntPtr handle, string format)
+ {
+ if (handle != ClipMagic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+
+ if (format == "Text" ) return Atoms.XA_STRING.ToInt32();
+ else if (format == "Bitmap" ) return Atoms.XA_BITMAP.ToInt32();
+ //else if (format == "MetaFilePict" ) return 3;
+ //else if (format == "SymbolicLink" ) return 4;
+ //else if (format == "DataInterchangeFormat" ) return 5;
+ //else if (format == "Tiff" ) return 6;
+ else if (format == "OEMText" ) return Atoms.OEMTEXT.ToInt32();
+ else if (format == "DeviceIndependentBitmap" ) return Atoms.XA_PIXMAP.ToInt32();
+ else if (format == "Palette" ) return Atoms.XA_COLORMAP.ToInt32(); // Useless
+ //else if (format == "PenData" ) return 10;
+ //else if (format == "RiffAudio" ) return 11;
+ //else if (format == "WaveAudio" ) return 12;
+ else if (format == "UnicodeText" ) return Atoms.UNICODETEXT.ToInt32();
+ //else if (format == "EnhancedMetafile" ) return 14;
+ //else if (format == "FileDrop" ) return 15;
+ //else if (format == "Locale" ) return 16;
+
+ return Xlib.XInternAtom (display, format, false).ToInt32();
+ }
+
+ public IntPtr ClipboardOpen (bool primary_selection)
+ {
+ if (!primary_selection)
+ ClipMagic = Atoms.CLIPBOARD;
+ else
+ ClipMagic = Atoms.PRIMARY;
+
+ return ClipMagic;
+ }
+
+ // XXX @converter?
+ public object ClipboardRetrieve (IntPtr handle, int type, XplatUI.ClipboardToObject converter)
+ {
+ // XXX deal with the UpdateMessageQueue stuff
+#if true
+ return null;
+#else
+ Xlib.XConvertSelection (display, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
+
+ Clipboard.Retrieving = true;
+ while (Clipboard.Retrieving) {
+ UpdateMessageQueue(null);
+ }
+
+ return Clipboard.Item;
+#endif
+ }
+
+ public PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (Caret.Visible == true) {
+ Caret.Paused = true;
+ HideCaret();
+ }
+
+ return hwnd.PaintEventStart (ref m, client);
+ }
+
+ public void PaintEventEnd (ref Message m, IntPtr handle, bool client)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ hwnd.PaintEventEnd (ref m, client);
+
+ if (Caret.Visible == true) {
+ ShowCaret();
+ Caret.Paused = false;
+ }
+ }
+
+ public void SetCursor (IntPtr handle, IntPtr cursor)
+ {
+ Hwnd hwnd;
+
+ if (OverrideCursorHandle == IntPtr.Zero) {
+ if ((LastCursorWindow == handle) && (LastCursorHandle == cursor))
+ return;
+
+ LastCursorHandle = cursor;
+ LastCursorWindow = handle;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (cursor != IntPtr.Zero)
+ Xlib.XDefineCursor (display, hwnd.whole_window, cursor);
+ else
+ Xlib.XUndefineCursor (display, hwnd.whole_window);
+ Xlib.XFlush (display);
+ }
+ else {
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ Xlib.XDefineCursor (display, hwnd.whole_window, OverrideCursorHandle);
+ }
+ }
+
+ public DragDropEffects StartDrag (IntPtr handle, object data,
+ DragDropEffects allowed_effects)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd == null)
+ throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
+
+ return Dnd.StartDrag (hwnd.ClientWindow, data, allowed_effects);
+ }
+
+ public X11Atoms Atoms {
+ get { return atoms; }
+ }
+
+ public int CurrentTimestamp {
+ get {
+ TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
+
+ return (int) t.TotalSeconds;
+ }
+ }
+
+ public Size CursorSize {
+ get {
+ int x;
+ int y;
+
+ if (Xlib.XQueryBestCursor (display, RootWindow.Handle, 32, 32, out x, out y) != 0) {
+ return new Size (x, y);
+ } else {
+ return new Size (16, 16);
+ }
+ }
+ }
+
+ public IntPtr Handle {
+ get { return display; }
+ }
+
+ public Size IconSize {
+ get {
+ IntPtr list;
+ XIconSize size;
+ int count;
+
+ if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) {
+ long current;
+ int largest;
+
+ current = (long)list;
+ largest = 0;
+
+ size = new XIconSize();
+
+ for (int i = 0; i < count; i++) {
+ size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
+ current += Marshal.SizeOf(size);
+
+ // Look for our preferred size
+ if (size.min_width == 32) {
+ Xlib.XFree(list);
+ return new Size(32, 32);
+ }
+
+ if (size.max_width == 32) {
+ Xlib.XFree(list);
+ return new Size(32, 32);
+ }
+
+ if (size.min_width < 32 && size.max_width > 32) {
+ int x;
+
+ // check if we can fit one
+ x = size.min_width;
+ while (x < size.max_width) {
+ x += size.width_inc;
+ if (x == 32) {
+ Xlib.XFree(list);
+ return new Size(32, 32);
+ }
+ }
+ }
+
+ if (largest < size.max_width) {
+ largest = size.max_width;
+ }
+ }
+
+ // We didn't find a match or we wouldn't be here
+ return new Size(largest, largest);
+
+ } else {
+ return new Size(32, 32);
+ }
+ }
+ }
+
+ public int KeyboardSpeed {
+ get {
+ //
+ // A lot harder: need to do:
+ // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
+ // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
+ // XkbGetWidgets(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
+ //
+ // And from that we can tell the repetition rate
+ //
+ // Notice, the values must map to:
+ // [0, 31] which maps to 2.5 to 30 repetitions per second.
+ //
+ return 0;
+ }
+ }
+
+ public int KeyboardDelay {
+ get {
+ //
+ // Return values must range from 0 to 4, 0 meaning 250ms,
+ // and 4 meaning 1000 ms.
+ //
+ return 1; // ie, 500 ms
+ }
+ }
+
+ public int DefaultScreen {
+ get { return Xlib.XDefaultScreen (display); }
+ }
+
+ public IntPtr DefaultColormap {
+ // XXX multiscreen
+ get { return Xlib.XDefaultColormap (display, DefaultScreen); }
+ }
+
+ public Keys ModifierKeys {
+ get { return Keyboard.ModifierKeys; }
+ }
+
+ public IntPtr OverrideCursor {
+ get { return OverrideCursorHandle; }
+ set {
+ if (Grab.Hwnd != IntPtr.Zero) {
+ Xlib.XChangeActivePointerGrab (display,
+ EventMask.ButtonMotionMask |
+ EventMask.PointerMotionMask |
+ EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask,
+ value, IntPtr.Zero);
+ return;
+ }
+
+ OverrideCursorHandle = value;
+ }
+ }
+
+ public X11RootHwnd RootWindow {
+ get { return root_hwnd; }
+ }
+
+ public Size SmallIconSize {
+ get {
+ IntPtr list;
+ XIconSize size;
+ int count;
+
+ if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) {
+ long current;
+ int smallest;
+
+ current = (long)list;
+ smallest = 0;
+
+ size = new XIconSize();
+
+ for (int i = 0; i < count; i++) {
+ size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
+ current += Marshal.SizeOf(size);
+
+ // Look for our preferred size
+ if (size.min_width == 16) {
+ Xlib.XFree(list);
+ return new Size(16, 16);
+ }
+
+ if (size.max_width == 16) {
+ Xlib.XFree(list);
+ return new Size(16, 16);
+ }
+
+ if (size.min_width < 16 && size.max_width > 16) {
+ int x;
+
+ // check if we can fit one
+ x = size.min_width;
+ while (x < size.max_width) {
+ x += size.width_inc;
+ if (x == 16) {
+ Xlib.XFree(list);
+ return new Size(16, 16);
+ }
+ }
+ }
+
+ if (smallest == 0 || smallest > size.min_width) {
+ smallest = size.min_width;
+ }
+ }
+
+ // We didn't find a match or we wouldn't be here
+ return new Size(smallest, smallest);
+
+ } else {
+ return new Size(16, 16);
+ }
+ }
+ }
+
+ public X11Hwnd FosterParent {
+ get { return foster_hwnd; }
+ }
+
+ public int MouseHoverTime {
+ get { return HoverState.Interval; }
+ }
+
+ public Rectangle VirtualScreen {
+ get {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ int width;
+ int height;
+
+ Xlib.XGetWindowProperty (display, RootWindow.Handle,
+ Atoms._NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL,
+ out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if ((long)nitems < 2)
+ goto failsafe;
+
+ width = Marshal.ReadIntPtr(prop, 0).ToInt32();
+ height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
+ Xlib.XFree(prop);
+
+ return new Rectangle(0, 0, width, height);
+
+ failsafe:
+ XWindowAttributes attributes = new XWindowAttributes();
+
+ Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
+
+ return new Rectangle(0, 0, attributes.width, attributes.height);
+ }
+ }
+
+ public Rectangle WorkingArea {
+ get {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ int width;
+ int height;
+ int current_desktop;
+ int x;
+ int y;
+
+ Xlib.XGetWindowProperty (display, RootWindow.Handle,
+ Atoms._NET_CURRENT_DESKTOP, IntPtr.Zero, new IntPtr(1), false, Atoms.XA_CARDINAL,
+ out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if ((long)nitems < 1) {
+ goto failsafe;
+ }
+
+ current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
+ Xlib.XFree(prop);
+
+ Xlib.XGetWindowProperty (display, RootWindow.Handle,
+ Atoms._NET_WORKAREA, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL,
+ out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if ((long)nitems < 4 * current_desktop) {
+ goto failsafe;
+ }
+
+ x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
+ y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
+ width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
+ height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
+ Xlib.XFree(prop);
+
+ return new Rectangle(x, y, width, height);
+
+ failsafe:
+ XWindowAttributes attributes = new XWindowAttributes();
+
+ Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
+
+ return new Rectangle(0, 0, attributes.width, attributes.height);
+ }
+ }
+
+ private void XEventThread ()
+ {
+ while (true) {
+#if __MonoCS__
+ Syscall.poll (pollfds, 1U, -1);
+
+ while (Xlib.XPending (display) > 0) {
+#endif
+ XEvent xevent = new XEvent ();
+ Xlib.XNextEvent (display, ref xevent);
+
+ // this is kind of a gross place to put this, but we don't know about the
+ // key repeat state in X11ThreadQueue, nor to we want the queue code calling
+ // XPeekEvent.
+ if (!detectable_key_auto_repeat &&
+ xevent.type == XEventName.KeyRelease &&
+ Xlib.XPending (display) > 0) {
+
+ XEvent nextevent = new XEvent ();
+ Xlib.XPeekEvent (display, ref nextevent);
+
+ if (nextevent.type == XEventName.KeyPress &&
+ nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
+ nextevent.KeyEvent.time == xevent.KeyEvent.time) {
+ continue;
+ }
+ }
+
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
+ if (hwnd != null)
+ hwnd.Queue.Enqueue (xevent);
+#if __MonoCS__
+ }
+#endif
+ }
+ }
+
+ private void RedirectMsgToEnabledAncestor (X11Hwnd hwnd, MSG msg, IntPtr window,
+ ref int event_x, ref int event_y)
+ {
+ int x, y;
+
+ IntPtr dummy;
+ msg.hwnd = hwnd.EnabledHwnd;
+ Xlib.XTranslateCoordinates (display, window,
+ Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow,
+ event_x, event_y,
+ out x, out y, out dummy);
+ event_x = x;
+ event_y = y;
+ msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
+ }
+
+
+ // This is called from the thread owning the corresponding X11ThreadQueue
+ [MonoTODO("Implement filtering")]
+ public bool GetMessage (object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax)
+ {
+ X11ThreadQueue queue = (X11ThreadQueue)queue_id;
+ XEvent xevent;
+ bool client;
+ bool got_xevent = false;
+
+ X11Hwnd hwnd;
+
+ ProcessNextMessage:
+ do {
+ got_xevent = queue.Dequeue (out xevent);
+
+ if (!got_xevent) {
+#if spew
+ Console.WriteLine (">");
+ Console.Out.Flush ();
+#endif
+ break;
+ }
+
+#if spew
+ Console.Write ("-");
+ Console.Out.Flush ();
+#endif
+
+ hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
+
+ // Handle messages for windows that are already or are about to be destroyed.
+
+ // we need a special block for this because unless we remove the hwnd from the paint
+ // queue it will always stay there (since we don't handle the expose), and we'll
+ // effectively loop infinitely trying to repaint a non-existant window.
+ if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
+ hwnd.PendingExpose = hwnd.PendingNCExpose = false;
+ goto ProcessNextMessage;
+ }
+
+ // We need to make sure we only allow DestroyNotify events through for zombie
+ // hwnds, since much of the event handling code makes requests using the hwnd's
+ // ClientWindow, and that'll result in BadWindow errors if there's some lag
+ // between the XDestroyWindow call and the DestroyNotify event.
+ if (hwnd == null || hwnd.zombie) {
+#if DriverDebug || DriverDebugDestroy
+ Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}",
+ xevent.type, xevent.AnyEvent.window.ToInt32());
+#endif
+ goto ProcessNextMessage;
+ }
+
+ client = hwnd.ClientWindow == xevent.AnyEvent.window;
+
+ msg.hwnd = hwnd.Handle;
+
+ switch (xevent.type) {
+ case XEventName.KeyPress:
+ Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg);
+ return true;
+
+ case XEventName.KeyRelease:
+ Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg);
+ return true;
+
+ case XEventName.ButtonPress: {
+ switch(xevent.ButtonEvent.button) {
+ case 1:
+ MouseState |= MouseButtons.Left;
+ if (client) {
+ msg.message = Msg.WM_LBUTTONDOWN;
+ } else {
+ msg.message = Msg.WM_NCLBUTTONDOWN;
+ hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
+ msg.wParam=GetMousewParam(0);
+ break;
+
+ case 2:
+ MouseState |= MouseButtons.Middle;
+ if (client) {
+ msg.message = Msg.WM_MBUTTONDOWN;
+ } else {
+ msg.message = Msg.WM_NCMBUTTONDOWN;
+ hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ msg.wParam=GetMousewParam(0);
+ break;
+
+ case 3:
+ MouseState |= MouseButtons.Right;
+ if (client) {
+ msg.message = Msg.WM_RBUTTONDOWN;
+ } else {
+ msg.message = Msg.WM_NCRBUTTONDOWN;
+ hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ msg.wParam=GetMousewParam(0);
+ break;
+
+ case 4:
+ msg.hwnd = FocusWindow.Handle;
+ msg.message=Msg.WM_MOUSEWHEEL;
+ msg.wParam=GetMousewParam(120);
+ break;
+
+ case 5:
+ msg.hwnd = FocusWindow.Handle;
+ msg.message=Msg.WM_MOUSEWHEEL;
+ msg.wParam=GetMousewParam(-120);
+ break;
+ }
+
+ msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ MousePosition.X = xevent.ButtonEvent.x;
+ MousePosition.Y = xevent.ButtonEvent.y;
+
+ if (!hwnd.Enabled) {
+ RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
+ ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+
+ if (Grab.Hwnd != IntPtr.Zero)
+ msg.hwnd = Grab.Hwnd;
+
+ if (ClickPending.Pending &&
+ ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) &&
+ (msg.wParam == ClickPending.wParam) &&
+ (msg.lParam == ClickPending.lParam) &&
+ (msg.message == ClickPending.Message))) {
+ // Looks like a genuine double click, clicked twice on the same spot with the same keys
+ switch(xevent.ButtonEvent.button) {
+ case 1:
+ msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
+ break;
+
+ case 2:
+ msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
+ break;
+
+ case 3:
+ msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
+ break;
+ }
+
+ ClickPending.Pending = false;
+
+ }
+ else {
+ ClickPending.Pending = true;
+ ClickPending.Hwnd = msg.hwnd;
+ ClickPending.Message = msg.message;
+ ClickPending.wParam = msg.wParam;
+ ClickPending.lParam = msg.lParam;
+ ClickPending.Time = (long)xevent.ButtonEvent.time;
+ }
+
+ if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
+ hwnd.SendParentNotify (msg.message, MousePosition.X, MousePosition.Y);
+
+ // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
+ // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
+ // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
+ XEvent motionEvent = new XEvent ();
+ motionEvent.type = XEventName.MotionNotify;
+ motionEvent.MotionEvent.display = display;
+ motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
+ motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
+ motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
+ hwnd.Queue.Enqueue (motionEvent);
+ }
+
+ return true;
+ }
+
+ case XEventName.ButtonRelease:
+ switch(xevent.ButtonEvent.button) {
+ case 1:
+ if (client) {
+ msg.message = Msg.WM_LBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCLBUTTONUP;
+ hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ MouseState &= ~MouseButtons.Left;
+ msg.wParam=GetMousewParam(0);
+ break;
+
+ case 2:
+ if (client) {
+ msg.message = Msg.WM_MBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCMBUTTONUP;
+ hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ MouseState &= ~MouseButtons.Middle;
+ msg.wParam=GetMousewParam(0);
+ break;
+
+ case 3:
+ if (client) {
+ msg.message = Msg.WM_RBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCRBUTTONUP;
+ hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ MouseState &= ~MouseButtons.Right;
+ msg.wParam=GetMousewParam(0);
+ break;
+
+ case 4:
+ goto ProcessNextMessage;
+
+ case 5:
+ goto ProcessNextMessage;
+ }
+
+ if (!hwnd.Enabled) {
+ RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
+ ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+
+ if (Grab.Hwnd != IntPtr.Zero)
+ msg.hwnd = Grab.Hwnd;
+
+ msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ MousePosition.X = xevent.ButtonEvent.x;
+ MousePosition.Y = xevent.ButtonEvent.y;
+
+ // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
+ // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
+ // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
+ if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
+ XEvent motionEvent = new XEvent ();
+ motionEvent.type = XEventName.MotionNotify;
+ motionEvent.MotionEvent.display = display;
+ motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
+ motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
+ motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
+ hwnd.Queue.Enqueue (motionEvent);
+ }
+ return true;
+
+ case XEventName.MotionNotify:
+ /* XXX move the compression stuff here */
+
+ if (client) {
+#if DriverDebugExtra
+ Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}",
+ client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(),
+ xevent.MotionEvent.x, xevent.MotionEvent.y);
+#endif
+
+ if (Grab.Hwnd != IntPtr.Zero)
+ msg.hwnd = Grab.Hwnd;
+ else
+ NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
+
+ msg.message = Msg.WM_MOUSEMOVE;
+ msg.wParam = GetMousewParam(0);
+ msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
+
+ if (!hwnd.Enabled) {
+ RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
+ ref xevent.MotionEvent.x, ref xevent.MotionEvent.y);
+ }
+
+ MousePosition.X = xevent.MotionEvent.x;
+ MousePosition.Y = xevent.MotionEvent.y;
+
+ if ((HoverState.Timer.Enabled) &&
+ (((MousePosition.X + HoverState.Size.Width) < HoverState.X) ||
+ ((MousePosition.X - HoverState.Size.Width) > HoverState.X) ||
+ ((MousePosition.Y + HoverState.Size.Height) < HoverState.Y) ||
+ ((MousePosition.Y - HoverState.Size.Height) > HoverState.Y))) {
+
+ HoverState.Timer.Stop();
+ HoverState.Timer.Start();
+ HoverState.X = MousePosition.X;
+ HoverState.Y = MousePosition.Y;
+ }
+ }
+ else {
+ HitTest ht;
+ IntPtr dummy;
+ int screen_x;
+ int screen_y;
+
+ #if DriverDebugExtra
+ Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}",
+ client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(),
+ xevent.MotionEvent.x, xevent.MotionEvent.y);
+ #endif
+ msg.message = Msg.WM_NCMOUSEMOVE;
+
+ if (!hwnd.Enabled) {
+ RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
+ ref xevent.MotionEvent.x, ref xevent.MotionEvent.y);
+ }
+
+ // The hit test is sent in screen coordinates
+ Xlib.XTranslateCoordinates (display, xevent.AnyEvent.window, RootWindow.Handle,
+ xevent.MotionEvent.x, xevent.MotionEvent.y,
+ out screen_x, out screen_y, out dummy);
+
+ msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF);
+ ht = (HitTest)NativeWindow.WndProc (hwnd.ClientWindow, Msg.WM_NCHITTEST,
+ IntPtr.Zero, msg.lParam).ToInt32 ();
+ NativeWindow.WndProc(hwnd.ClientWindow, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
+
+ MousePosition.X = xevent.MotionEvent.x;
+ MousePosition.Y = xevent.MotionEvent.y;
+ }
+
+ return true;
+
+ case XEventName.EnterNotify:
+ if (!hwnd.Enabled)
+ goto ProcessNextMessage;
+
+ if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal)
+ goto ProcessNextMessage;
+
+ msg.message = Msg.WM_MOUSE_ENTER;
+ HoverState.X = xevent.CrossingEvent.x;
+ HoverState.Y = xevent.CrossingEvent.y;
+ HoverState.Timer.Enabled = true;
+ HoverState.Window = xevent.CrossingEvent.window;
+
+ return true;
+
+ case XEventName.LeaveNotify:
+ if (!hwnd.Enabled)
+ goto ProcessNextMessage;
+
+ if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) ||
+ (xevent.CrossingEvent.window != hwnd.ClientWindow))
+ goto ProcessNextMessage;
+
+ msg.message=Msg.WM_MOUSELEAVE;
+ HoverState.Timer.Enabled = false;
+ HoverState.Window = IntPtr.Zero;
+
+ return true;
+
+ case XEventName.ReparentNotify:
+ if (hwnd.parent == null) { // Toplevel
+ if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.WholeWindow)) {
+ // We need to adjust x/y
+ // This sucks ass, part 2
+ // Every WM does the reparenting of toplevel windows different, so there's
+ // no standard way of getting our adjustment considering frames/decorations
+ // The code below is needed for metacity. KDE doesn't works just fine without this
+ int dummy_int;
+ IntPtr dummy_ptr;
+ int new_x;
+ int new_y;
+ int frame_left;
+ int frame_top;
+
+ hwnd.Reparented = true;
+
+ Xlib.XGetGeometry(display, XGetParent(hwnd.WholeWindow),
+ out dummy_ptr, out new_x, out new_y,
+ out dummy_int, out dummy_int, out dummy_int, out dummy_int);
+ hwnd.FrameExtents(out frame_left, out frame_top);
+ if ((frame_left != 0) && (frame_top != 0) && (new_x != frame_left) && (new_y != frame_top)) {
+ hwnd.x = new_x;
+ hwnd.y = new_y;
+ hwnd.whacky_wm = true;
+ }
+
+ if (hwnd.opacity != 0xffffffff) {
+ IntPtr opacity;
+
+ opacity = (IntPtr)(Int32)hwnd.opacity;
+ Xlib.XChangeProperty (display, XGetParent(hwnd.WholeWindow),
+ Atoms._NET_WM_WINDOW_OPACITY, Atoms.XA_CARDINAL, 32,
+ PropertyMode.Replace, ref opacity, 1);
+ }
+ SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
+ goto ProcessNextMessage;
+ } else {
+ hwnd.Reparented = false;
+ goto ProcessNextMessage;
+ }
+ }
+ goto ProcessNextMessage;
+
+ case XEventName.ConfigureNotify:
+ hwnd.HandleConfigureNotify (xevent);
+ goto ProcessNextMessage;
+
+ case XEventName.MapNotify: {
+ if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+ hwnd.Mapped = true;
+ msg.message = Msg.WM_SHOWWINDOW;
+ msg.wParam = (IntPtr) 1;
+ // XXX we're missing the lParam..
+ break;
+ }
+ goto ProcessNextMessage;
+ }
+
+ case XEventName.UnmapNotify: {
+ if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+ hwnd.Mapped = false;
+ msg.message = Msg.WM_SHOWWINDOW;
+ msg.wParam = (IntPtr) 0;
+ // XXX we're missing the lParam..
+ break;
+ }
+ goto ProcessNextMessage;
+ }
+
+ case XEventName.FocusIn:
+ // We received focus. We use X11 focus only to know if the app window does or does not have focus
+ // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
+ // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
+ // about it having focus again
+ if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear)
+ goto ProcessNextMessage;
+
+ if (FocusWindow == null) {
+ Widget c = Widget.FromHandle (hwnd.ClientWindow);
+ if (c == null)
+ goto ProcessNextMessage;
+ Form form = c.FindForm ();
+ if (form == null)
+ goto ProcessNextMessage;
+ X11Hwnd new_active = (X11Hwnd)Hwnd.ObjectFromHandle (form.Handle);
+ if (ActiveWindow != new_active) {
+ ActiveWindow = new_active;
+ SendMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
+ }
+ goto ProcessNextMessage;
+ }
+ Keyboard.FocusIn(FocusWindow.Handle);
+ SendMessage(FocusWindow.Handle, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
+ goto ProcessNextMessage;
+
+ case XEventName.FocusOut:
+ // Se the comment for our FocusIn handler
+ if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear)
+ goto ProcessNextMessage;
+
+ if (FocusWindow == null)
+ goto ProcessNextMessage;
+
+ Keyboard.FocusOut(FocusWindow.Handle);
+
+ while (Keyboard.ResetKeyState(FocusWindow.Handle, ref msg))
+ SendMessage(FocusWindow.Handle, msg.message, msg.wParam, msg.lParam);
+
+ SendMessage(FocusWindow.Handle, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
+ goto ProcessNextMessage;
+
+ case XEventName.Expose:
+ if (!hwnd.Mapped) {
+ hwnd.PendingExpose = hwnd.PendingNCExpose = false;
+ continue;
+ }
+
+ msg.hwnd = hwnd.Handle;
+
+ if (client) {
+#if DriverDebugExtra
+ Console.WriteLine("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}",
+ hwnd.client_window.ToInt32(),
+ xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+ xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+#endif
+ msg.message = Msg.WM_PAINT;
+ }
+ else {
+ Graphics g;
+
+ switch (hwnd.border_style) {
+ case FormBorderStyle.Fixed3D:
+ g = Graphics.FromHwnd(hwnd.WholeWindow);
+ WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height),
+ Border3DStyle.Sunken);
+ g.Dispose();
+ break;
+
+ case FormBorderStyle.FixedSingle:
+ g = Graphics.FromHwnd(hwnd.WholeWindow);
+ WidgetPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height),
+ Color.Black, ButtonBorderStyle.Solid);
+ g.Dispose();
+ break;
+ }
+#if DriverDebugExtra
+ Console.WriteLine("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}",
+ hwnd.ClientWindow.ToInt32(),
+ xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+ xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+#endif
+
+ Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+ xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ Region region = new Region (rect);
+ IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
+ msg.message = Msg.WM_NCPAINT;
+ msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
+ msg.refobject = region;
+ }
+
+ return true;
+
+ case XEventName.DestroyNotify:
+
+ // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
+ hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
+
+ // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
+ if ((hwnd != null) && (hwnd.ClientWindow == xevent.DestroyWindowEvent.window)) {
+ CleanupCachedWindows (hwnd);
+
+ #if DriverDebugDestroy
+ Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.ClientWindow));
+ #endif
+
+ msg.hwnd = hwnd.ClientWindow;
+ msg.message=Msg.WM_DESTROY;
+ hwnd.Dispose();
+ }
+ else
+ goto ProcessNextMessage;
+
+ return true;
+
+ case XEventName.ClientMessage:
+ if (Dnd.HandleClientMessage (ref xevent))
+ goto ProcessNextMessage;
+
+ if (xevent.ClientMessageEvent.message_type == Atoms.AsyncAtom) {
+ XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
+ goto ProcessNextMessage;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
+ msg.message = Msg.WM_MOUSEHOVER;
+ msg.wParam = GetMousewParam(0);
+ msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
+ return true;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == Atoms.PostAtom) {
+ msg.hwnd = xevent.ClientMessageEvent.ptr1;
+ msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
+ msg.wParam = xevent.ClientMessageEvent.ptr3;
+ msg.lParam = xevent.ClientMessageEvent.ptr4;
+
+ // if we posted a WM_QUIT message, make sure we return
+ // false here as well.
+ if (msg.message == (Msg)Msg.WM_QUIT)
+ return false;
+ else
+ return true;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == Atoms._XEMBED) {
+#if DriverDebugXEmbed
+ Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}",
+ xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
+#endif
+
+ if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
+ XSizeHints hints = new XSizeHints();
+ IntPtr dummy;
+
+ Xlib.XGetWMNormalHints (display, hwnd.WholeWindow, ref hints, out dummy);
+
+ hwnd.width = hints.max_width;
+ hwnd.height = hints.max_height;
+ hwnd.ClientRect = Rectangle.Empty;
+ SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ if (xevent.ClientMessageEvent.message_type == Atoms.WM_PROTOCOLS) {
+ if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_DELETE_WINDOW) {
+ msg.message = Msg.WM_CLOSE;
+ return true;
+ }
+
+ // We should not get this, but I'll leave the code in case we need it in the future
+ if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_TAKE_FOCUS) {
+ goto ProcessNextMessage;
+ }
+ }
+
+ goto ProcessNextMessage;
+
+ case XEventName.PropertyNotify:
+ // The Hwnd's themselves handle this
+ hwnd.PropertyChanged (xevent);
+ goto ProcessNextMessage;
+ }
+ } while (true);
+
+ msg.hwnd= IntPtr.Zero;
+ msg.message = Msg.WM_ENTERIDLE;
+ return true;
+ }
+
+ [MonoTODO("Implement filtering and PM_NOREMOVE")]
+ public bool PeekMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
+ {
+ X11ThreadQueue queue = (X11ThreadQueue) queue_id;
+ bool pending;
+
+ if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
+ throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
+ }
+
+ try {
+ queue.Lock ();
+ pending = false;
+ if (queue.CountUnlocked > 0)
+ pending = true;
+ }
+ catch {
+ return false;
+ }
+ finally {
+ queue.Unlock ();
+ }
+
+ queue.CheckTimers ();
+
+ if (!pending)
+ return false;
+
+ return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
+ }
+
+ public void DoEvents (X11ThreadQueue queue)
+ {
+ MSG msg = new MSG ();
+
+ if (OverrideCursorHandle != IntPtr.Zero)
+ OverrideCursorHandle = IntPtr.Zero;
+
+ queue.DispatchIdle = false;
+
+ while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
+ TranslateMessage (ref msg);
+ DispatchMessage (ref msg);
+ }
+
+ queue.DispatchIdle = true;
+ }
+
+ // double buffering support
+ public void CreateOffscreenDrawable (IntPtr handle,
+ int width, int height,
+ out object offscreen_drawable)
+ {
+ IntPtr root_out;
+ int x_out, y_out, width_out, height_out, border_width_out, depth_out;
+
+ Xlib.XGetGeometry (display, handle,
+ out root_out,
+ out x_out, out y_out,
+ out width_out, out height_out,
+ out border_width_out, out depth_out);
+
+ IntPtr pixmap = Xlib.XCreatePixmap (display, handle, width, height, depth_out);
+
+ offscreen_drawable = pixmap;
+ }
+
+ public void DestroyOffscreenDrawable (object offscreen_drawable)
+ {
+ Xlib.XFreePixmap (display, (IntPtr)offscreen_drawable);
+ }
+
+ public Graphics GetOffscreenGraphics (object offscreen_drawable)
+ {
+ return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
+ }
+
+ public void BlitFromOffscreen (IntPtr dest_handle,
+ Graphics dest_dc,
+ object offscreen_drawable,
+ Graphics offscreen_dc,
+ Rectangle r)
+ {
+ XGCValues gc_values;
+ IntPtr gc;
+
+ gc_values = new XGCValues();
+
+ gc = Xlib.XCreateGC (display, dest_handle, IntPtr.Zero, ref gc_values);
+
+ Xlib.XCopyArea (display, (IntPtr)offscreen_drawable, dest_handle,
+ gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
+
+ Xlib.XFreeGC (display, gc);
+ }
+
+
+ // reversible screen-level drawing
+ IntPtr GetReversibleScreenGC (Color backColor)
+ {
+ XGCValues gc_values;
+ IntPtr gc;
+ uint pixel;
+
+ XColor xcolor = new XColor();
+ xcolor.red = (ushort)(backColor.R * 257);
+ xcolor.green = (ushort)(backColor.G * 257);
+ xcolor.blue = (ushort)(backColor.B * 257);
+ Xlib.XAllocColor (display, DefaultColormap, ref xcolor);
+ pixel = (uint)xcolor.pixel.ToInt32();
+
+
+ gc_values = new XGCValues();
+
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+ gc_values.foreground = (IntPtr)pixel;
+
+ gc = Xlib.XCreateGC (display, RootWindow.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
+ Xlib.XSetForeground (display, gc, (UIntPtr)pixel);
+ Xlib.XSetFunction (display, gc, GXFunction.GXxor);
+
+ return gc;
+ }
+
+ public void DrawReversibleLine (Point start, Point end, Color backColor)
+ {
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
+ IntPtr gc = GetReversibleScreenGC (backColor);
+
+ Xlib.XDrawLine (display, RootWindow.Handle, gc, start.X, start.Y, end.X, end.Y);
+
+ Xlib.XFreeGC (display, gc);
+ }
+
+ public void FillReversibleRectangle (Rectangle rectangle, Color backColor)
+ {
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
+ IntPtr gc = GetReversibleScreenGC (backColor);
+
+ if (rectangle.Width < 0) {
+ rectangle.X += rectangle.Width;
+ rectangle.Width = -rectangle.Width;
+ }
+ if (rectangle.Height < 0) {
+ rectangle.Y += rectangle.Height;
+ rectangle.Height = -rectangle.Height;
+ }
+
+ Xlib.XFillRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
+
+ Xlib.XFreeGC (display, gc);
+ }
+
+ public void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
+ {
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
+ IntPtr gc = GetReversibleScreenGC (backColor);
+
+ if (rectangle.Width < 0) {
+ rectangle.X += rectangle.Width;
+ rectangle.Width = -rectangle.Width;
+ }
+ if (rectangle.Height < 0) {
+ rectangle.Y += rectangle.Height;
+ rectangle.Height = -rectangle.Height;
+ }
+
+ int line_width = 1;
+ GCLineStyle line_style = GCLineStyle.LineSolid;
+ GCCapStyle cap_style = GCCapStyle.CapButt;
+ GCJoinStyle join_style = GCJoinStyle.JoinMiter;
+
+ switch (style) {
+ case FrameStyle.Dashed:
+ line_style = GCLineStyle.LineOnOffDash;
+ break;
+ case FrameStyle.Thick:
+ line_width = 2;
+ break;
+ }
+
+ Xlib.XSetLineAttributes (display, gc, line_width, line_style, cap_style, join_style);
+
+ Xlib.XDrawRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
+
+ Xlib.XFreeGC (display, gc);
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/X11Dnd.cs b/source/ShiftUI/Internal/X11Dnd.cs
new file mode 100644
index 0000000..82f6568
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Dnd.cs
@@ -0,0 +1,1421 @@
+// 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) 2005 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+//
+// NOTE: We have some tests in Test/ShiftUI/DragAndDropTest.cs, which I *highly* recommend
+// to run after any change made here, since those tests are interactive, and thus are not part of
+// the common tests.
+//
+
+
+using System;
+using System.IO;
+using System.Text;
+using System.Drawing;
+using System.Threading;
+using System.Collections;
+using System.Runtime.Serialization;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization.Formatters.Binary;
+
+namespace ShiftUI {
+
+ internal class X11Dnd {
+
+ private enum State {
+ Accepting,
+ Dragging
+ }
+
+ private enum DragState {
+ None,
+ Beginning,
+ Dragging,
+ Entered
+ }
+
+ private interface IDataConverter {
+ void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent);
+ void SetData (X11Dnd dnd, object data, ref XEvent xevent);
+ }
+
+ private delegate void MimeConverter (IntPtr dsp,
+ IDataObject data, ref XEvent xevent);
+
+ private class MimeHandler {
+ public string Name;
+ public string [] Aliases;
+ public IntPtr Type;
+ public IntPtr NonProtocol;
+ public IDataConverter Converter;
+
+ public MimeHandler (string name, IDataConverter converter) : this (name, converter, name)
+ {
+ }
+
+ public MimeHandler (string name, IDataConverter converter, params string [] aliases)
+ {
+ Name = name;
+ Converter = converter;
+ Aliases = aliases;
+ }
+
+ public override string ToString ()
+ {
+ return "MimeHandler {" + Name + "}";
+ }
+ }
+
+ private MimeHandler [] MimeHandlers = {
+// new MimeHandler ("WCF_DIB"),
+// new MimeHandler ("image/gif", new MimeConverter (ImageConverter)),
+// new MimeHandler ("text/rtf", new MimeConverter (RtfConverter)),
+// new MimeHandler ("text/richtext", new MimeConverter (RtfConverter)),
+
+ new MimeHandler ("text/plain", new TextConverter ()),
+ new MimeHandler ("text/plain", new TextConverter (), "System.String", DataFormats.Text),
+ new MimeHandler ("text/html", new HtmlConverter (), DataFormats.Html),
+ new MimeHandler ("text/uri-list", new UriListConverter (), DataFormats.FileDrop),
+ new MimeHandler ("application/x-mono-serialized-object",
+ new SerializedObjectConverter ())
+ };
+
+ private class SerializedObjectConverter : IDataConverter {
+
+ public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent)
+ {
+ MemoryStream stream = dnd.GetData (ref xevent);
+ BinaryFormatter bf = new BinaryFormatter ();
+
+ if (stream.Length == 0)
+ return;
+
+ stream.Seek (0, 0);
+ object obj = bf.Deserialize (stream);
+ data.SetData (obj);
+ }
+
+ public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
+ {
+ if (data == null)
+ return;
+
+ MemoryStream stream = new MemoryStream ();
+ BinaryFormatter bf = new BinaryFormatter ();
+
+ bf.Serialize (stream, data);
+
+ IntPtr buffer = Marshal.AllocHGlobal ((int) stream.Length);
+ stream.Seek (0, 0);
+
+ for (int i = 0; i < stream.Length; i++) {
+ Marshal.WriteByte (buffer, i, (byte) stream.ReadByte ());
+ }
+
+ dnd.SetProperty (ref xevent, buffer, (int) stream.Length);
+ }
+ }
+
+ private class HtmlConverter : IDataConverter {
+
+ public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent)
+ {
+ string text = dnd.GetText (ref xevent, false);
+ if (text == null)
+ return;
+ data.SetData (DataFormats.Text, text);
+ data.SetData (DataFormats.UnicodeText, text);
+ }
+
+ public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
+ {
+ IntPtr buffer;
+ int len;
+ string str = data as string;
+
+ if (str == null)
+ return;
+
+ if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) {
+ byte [] bytes = Encoding.ASCII.GetBytes (str);
+ buffer = Marshal.AllocHGlobal (bytes.Length);
+ len = bytes.Length;
+ for (int i = 0; i < len; i++)
+ Marshal.WriteByte (buffer, i, bytes [i]);
+ } else {
+ buffer = Marshal.StringToHGlobalAnsi (str);
+ len = 0;
+ while (Marshal.ReadByte (buffer, len) != 0)
+ len++;
+ }
+
+ dnd.SetProperty (ref xevent, buffer, len);
+
+ Marshal.FreeHGlobal (buffer);
+ }
+ }
+
+ private class TextConverter : IDataConverter {
+
+ public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent)
+ {
+ string text = dnd.GetText (ref xevent, true);
+ if (text == null)
+ return;
+ data.SetData (DataFormats.Text, text);
+ data.SetData (DataFormats.UnicodeText, text);
+ }
+
+ public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
+ {
+ IntPtr buffer;
+ int len;
+ string str = data as string;
+
+ if (str == null) {
+ IDataObject dobj = data as IDataObject;
+ if (dobj == null)
+ return;
+ str = (string) dobj.GetData ("System.String", true);
+ }
+
+ if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) {
+ byte [] bytes = Encoding.ASCII.GetBytes (str);
+ buffer = Marshal.AllocHGlobal (bytes.Length);
+ len = bytes.Length;
+ for (int i = 0; i < len; i++)
+ Marshal.WriteByte (buffer, i, bytes [i]);
+ } else {
+ buffer = Marshal.StringToHGlobalAnsi (str);
+ len = 0;
+ while (Marshal.ReadByte (buffer, len) != 0)
+ len++;
+ }
+
+ dnd.SetProperty (ref xevent, buffer, len);
+
+ Marshal.FreeHGlobal (buffer);
+ }
+ }
+
+ private class UriListConverter : IDataConverter {
+
+ public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent)
+ {
+ string text = dnd.GetText (ref xevent, false);
+ if (text == null)
+ return;
+
+ // TODO: Do this in a loop instead of just splitting
+ ArrayList uri_list = new ArrayList ();
+ string [] lines = text.Split (new char [] { '\r', '\n' });
+ foreach (string line in lines) {
+ // # is a comment line (see RFC 2483)
+ if (line.StartsWith ("#"))
+ continue;
+ try {
+ Uri uri = new Uri (line);
+ uri_list.Add (uri.LocalPath);
+ } catch { }
+ }
+
+ string [] l = (string []) uri_list.ToArray (typeof (string));
+ if (l.Length < 1)
+ return;
+ data.SetData (DataFormats.FileDrop, l);
+ data.SetData ("FileName", l [0]);
+ data.SetData ("FileNameW", l [0]);
+ }
+
+ public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
+ {
+ string [] uri_list = data as string [];
+
+ if (uri_list == null) {
+ IDataObject dobj = data as IDataObject;
+ if (dobj == null)
+ return;
+ uri_list = dobj.GetData (DataFormats.FileDrop, true) as string [];
+ }
+
+ if (uri_list == null)
+ return;
+
+ StringBuilder res = new StringBuilder ();
+ foreach (string uri_str in uri_list) {
+ Uri uri = new Uri (uri_str);
+ res.Append (uri.ToString ());
+ res.Append ("\r\n");
+ }
+
+ IntPtr buffer = Marshal.StringToHGlobalAnsi ((string) res.ToString ());
+ int len = 0;
+ while (Marshal.ReadByte (buffer, len) != 0)
+ len++;
+
+ dnd.SetProperty (ref xevent, buffer, len);
+ }
+ }
+
+ private class DragData {
+ public IntPtr Window;
+ public DragState State;
+ public object Data;
+ public IntPtr Action;
+ public IntPtr [] SupportedTypes;
+ public MouseButtons MouseState;
+ public DragDropEffects AllowedEffects;
+ public Point CurMousePos;
+
+ public IntPtr LastWindow;
+ public IntPtr LastTopLevel;
+
+ public bool WillAccept;
+
+ public void Reset ()
+ {
+ State = DragState.None;
+ Data = null;
+ SupportedTypes = null;
+ WillAccept = false;
+ }
+ }
+
+ // This version seems to be the most common
+ private static readonly IntPtr [] XdndVersion = new IntPtr [] { new IntPtr (4) };
+
+ private IntPtr display;
+ private DragData drag_data;
+
+ private IntPtr XdndAware;
+ private IntPtr XdndSelection;
+ private IntPtr XdndEnter;
+ private IntPtr XdndLeave;
+ private IntPtr XdndPosition;
+ private IntPtr XdndDrop;
+ private IntPtr XdndFinished;
+ private IntPtr XdndStatus;
+ private IntPtr XdndTypeList;
+ private IntPtr XdndActionCopy;
+ private IntPtr XdndActionMove;
+ private IntPtr XdndActionLink;
+ //private IntPtr XdndActionPrivate;
+ private IntPtr XdndActionList;
+ //private IntPtr XdndActionDescription;
+ //private IntPtr XdndActionAsk;
+
+ //private State state;
+
+ private int converts_pending;
+ private bool position_recieved;
+ private bool status_sent;
+ private IntPtr target;
+ private IntPtr source;
+ private IntPtr toplevel;
+ private IDataObject data;
+
+ private Widget Widget;
+ private int pos_x, pos_y;
+ private DragDropEffects allowed;
+ private DragEventArgs drag_event;
+
+ private Cursor CursorNo;
+ private Cursor CursorCopy;
+ private Cursor CursorMove;
+ private Cursor CursorLink;
+ // check out the TODO below
+ //private IntPtr CurrentCursorHandle;
+
+ private bool tracking = false;
+ private bool dropped = false;
+ private int motion_poll;
+ //private X11Keyboard keyboard;
+
+ public X11Dnd (IntPtr display, X11Keyboard keyboard)
+ {
+ this.display = display;
+ //this.keyboard = keyboard;
+
+ Init ();
+ }
+
+ public bool InDrag()
+ {
+ if (drag_data == null)
+ return false;
+ return drag_data.State != DragState.None;
+ }
+
+ public void SetAllowDrop (Hwnd hwnd, bool allow)
+ {
+ int[] atoms;
+
+ if (hwnd.allow_drop == allow)
+ return;
+
+ atoms = new int[XdndVersion.Length];
+ for (int i = 0; i < XdndVersion.Length; i++) {
+ atoms[i] = XdndVersion[i].ToInt32();
+ }
+
+ XplatUIX11.XChangeProperty (display, hwnd.whole_window, XdndAware,
+ (IntPtr) Atom.XA_ATOM, 32,
+ PropertyMode.Replace, atoms, allow ? 1 : 0);
+ hwnd.allow_drop = allow;
+ }
+
+ public DragDropEffects StartDrag (IntPtr handle, object data,
+ DragDropEffects allowed_effects)
+ {
+ drag_data = new DragData ();
+ drag_data.Window = handle;
+ drag_data.State = DragState.Beginning;
+ drag_data.MouseState = XplatUIX11.MouseState;
+ drag_data.Data = data;
+ drag_data.SupportedTypes = DetermineSupportedTypes (data);
+ drag_data.AllowedEffects = allowed_effects;
+ drag_data.Action = ActionFromEffect (allowed_effects);
+
+ if (CursorNo == null) {
+ // Make sure the cursors are created
+ CursorNo = new Cursor (Properties.Resources.DnDNo);
+ CursorCopy = new Cursor (Properties.Resources.DnDCopy);
+ CursorMove = new Cursor (Properties.Resources.DnDMove);
+ CursorLink = new Cursor (Properties.Resources.DnDLink);
+ }
+
+ drag_data.LastTopLevel = IntPtr.Zero;
+ Widget = null;
+
+ ShiftUI.MSG msg = new MSG();
+ object queue_id = XplatUI.StartLoop (Thread.CurrentThread);
+
+ Timer timer = new Timer ();
+ timer.Tick += new EventHandler (DndTickHandler);
+ timer.Interval = 100;
+
+ int suc;
+ drag_data.State = DragState.Dragging;
+
+ suc = XplatUIX11.XSetSelectionOwner (display, XdndSelection,
+ drag_data.Window, IntPtr.Zero);
+
+ if (suc == 0) {
+ Console.Error.WriteLine ("Could not take ownership of XdndSelection aborting drag.");
+ drag_data.Reset ();
+ return DragDropEffects.None;
+ }
+
+ drag_data.State = DragState.Dragging;
+ drag_data.CurMousePos = new Point ();
+ source = toplevel = target = IntPtr.Zero;
+ dropped = false;
+ tracking = true;
+ motion_poll = -1;
+ timer.Start ();
+
+ // Send Enter to the window initializing the dnd operation - which initializes the data
+ SendEnter (drag_data.Window, drag_data.Window, drag_data.SupportedTypes);
+ drag_data.LastTopLevel = toplevel;
+
+ while (tracking && XplatUI.GetMessage (queue_id, ref msg, IntPtr.Zero, 0, 0)) {
+
+ if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST) {
+ HandleKeyMessage (msg);
+ } else {
+ switch (msg.message) {
+ case Msg.WM_LBUTTONUP:
+ case Msg.WM_RBUTTONUP:
+ case Msg.WM_MBUTTONUP:
+ if (msg.message == Msg.WM_LBUTTONDOWN && drag_data.MouseState != MouseButtons.Left)
+ break;;
+ if (msg.message == Msg.WM_RBUTTONDOWN && drag_data.MouseState != MouseButtons.Right)
+ break;
+ if (msg.message == Msg.WM_MBUTTONDOWN && drag_data.MouseState != MouseButtons.Middle)
+ break;
+
+ HandleButtonUpMsg ();
+
+ // We don't want to dispatch button up neither (Match .Net)
+ // Thus we have to remove capture by ourselves
+ RemoveCapture (msg.hwnd);
+ continue;
+ case Msg.WM_MOUSEMOVE:
+ motion_poll = 0;
+
+ drag_data.CurMousePos.X = Widget.LowOrder ((int) msg.lParam.ToInt32 ());
+ drag_data.CurMousePos.Y = Widget.HighOrder ((int) msg.lParam.ToInt32 ());
+
+ HandleMouseOver ();
+ // We don't want to dispatch mouse move
+ continue;
+ }
+
+ XplatUI.DispatchMessage (ref msg);
+ }
+ }
+
+ timer.Stop ();
+
+ // If the target is a mwf Widget, return until DragEnter/DragLeave has been fired,
+ // which means the respective -already sent- dnd ClientMessages have been received and handled.
+ if (Widget != null)
+ Application.DoEvents ();
+
+ if (!dropped)
+ return DragDropEffects.None;
+ if (drag_event != null)
+ return drag_event.Effect;
+
+ // Fallback.
+ return DragDropEffects.None;
+ }
+
+ private void DndTickHandler (object sender, EventArgs e)
+ {
+ // This is to make sure we don't get stuck in a loop if another
+ // app doesn't finish the DND operation
+ if (dropped) {
+ Timer t = (Timer) sender;
+ if (t.Interval == 500)
+ tracking = false;
+ else
+ t.Interval = 500;
+ }
+
+
+ // If motion_poll is -1, there hasn't been motion at all, so don't simulate motion yet.
+ // Otherwise if more than 100 milliseconds have lapsed, we assume the pointer is not
+ // in motion anymore, and we simulate the mouse over operation, like .Net does.
+ if (motion_poll > 1)
+ HandleMouseOver ();
+ else if (motion_poll > -1)
+ motion_poll++;
+ }
+
+ // This routines helps us to have a DndEnter/DndLeave fallback when there wasn't any mouse movement
+ // as .Net does
+ private void DefaultEnterLeave (object user_data)
+ {
+ IntPtr toplevel, window;
+ int x_root, y_root;
+
+ // The window generating the operation could be a different than the one under pointer
+ GetWindowsUnderPointer (out window, out toplevel, out x_root, out y_root);
+ Widget source_Widget = Widget.FromHandle (window);
+ if (source_Widget == null || !source_Widget.AllowDrop)
+ return;
+
+ // `data' and other members are already available
+ Point pos = Widget.MousePosition;
+ DragEventArgs drag_args = new DragEventArgs (data, 0, pos.X, pos.Y, drag_data.AllowedEffects, DragDropEffects.None);
+
+ source_Widget.DndEnter (drag_args);
+ if ((drag_args.Effect & drag_data.AllowedEffects) != 0)
+ source_Widget.DndDrop (drag_args);
+ else
+ source_Widget.DndLeave (EventArgs.Empty);
+ }
+
+ public void HandleButtonUpMsg ()
+ {
+ if (drag_data.State == DragState.Beginning) {
+ //state = State.Accepting;
+ } else if (drag_data.State != DragState.None) {
+
+ if (drag_data.WillAccept) {
+
+ if (QueryContinue (false, DragAction.Drop))
+ return;
+ } else {
+
+ if (QueryContinue (false, DragAction.Cancel))
+ return;
+
+ // fallback if no movement was detected, as .net does.
+ if (motion_poll == -1)
+ DefaultEnterLeave (drag_data.Data);
+ }
+
+ drag_data.State = DragState.None;
+ // WE can't reset the drag data yet as it is still
+ // most likely going to be used by the SelectionRequest
+ // handlers
+ }
+
+ return;
+ }
+
+ private void RemoveCapture (IntPtr handle)
+ {
+ Widget c = MwfWindow (handle);
+ if (c.InternalCapture)
+ c.InternalCapture = false;
+ }
+
+ public bool HandleMouseOver ()
+ {
+ IntPtr toplevel, window;
+ int x_root, y_root;
+
+ GetWindowsUnderPointer (out window, out toplevel, out x_root, out y_root);
+
+ if (window != drag_data.LastWindow && drag_data.State == DragState.Entered) {
+ drag_data.State = DragState.Dragging;
+
+ // TODO: Send a Leave if this is an MWF window
+
+ if (toplevel != drag_data.LastTopLevel)
+ SendLeave (drag_data.LastTopLevel, toplevel);
+ }
+
+ drag_data.State = DragState.Entered;
+ if (toplevel != drag_data.LastTopLevel) {
+ // Entering a new toplevel window
+ SendEnter (toplevel, drag_data.Window, drag_data.SupportedTypes);
+ } else {
+ // Already in a toplevel window, so send a position
+ SendPosition (toplevel, drag_data.Window,
+ drag_data.Action,
+ x_root, y_root,
+ IntPtr.Zero);
+ }
+
+ drag_data.LastTopLevel = toplevel;
+ drag_data.LastWindow = window;
+ return true;
+ }
+
+ void GetWindowsUnderPointer (out IntPtr window, out IntPtr toplevel, out int x_root, out int y_root)
+ {
+ toplevel = IntPtr.Zero;
+ window = XplatUIX11.RootWindowHandle;
+
+ IntPtr root, child;
+ bool dnd_aware = false;
+ int x_temp, y_temp;
+ int mask_return;
+ int x = x_root = drag_data.CurMousePos.X;
+ int y = y_root = drag_data.CurMousePos.Y;
+
+ while (XplatUIX11.XQueryPointer (display, window, out root, out child,
+ out x_temp, out y_temp, out x, out y, out mask_return)) {
+
+ if (!dnd_aware) {
+ dnd_aware = IsWindowDndAware (window);
+ if (dnd_aware) {
+ toplevel = window;
+ x_root = x_temp;
+ y_root = y_temp;
+ }
+ }
+
+ if (child == IntPtr.Zero)
+ break;
+
+ window = child;
+ }
+ }
+
+ public void HandleKeyMessage (MSG msg)
+ {
+ if (VirtualKeys.VK_ESCAPE == (VirtualKeys) msg.wParam.ToInt32()) {
+ QueryContinue (true, DragAction.Cancel);
+ }
+ }
+
+ // return true if the event is handled here
+ public bool HandleClientMessage (ref XEvent xevent)
+ {
+ // most common so we check it first
+ if (xevent.ClientMessageEvent.message_type == XdndPosition)
+ return Accepting_HandlePositionEvent (ref xevent);
+ if (xevent.ClientMessageEvent.message_type == XdndEnter)
+ return Accepting_HandleEnterEvent (ref xevent);
+ if (xevent.ClientMessageEvent.message_type == XdndDrop)
+ return Accepting_HandleDropEvent (ref xevent);
+ if (xevent.ClientMessageEvent.message_type == XdndLeave)
+ return Accepting_HandleLeaveEvent (ref xevent);
+ if (xevent.ClientMessageEvent.message_type == XdndStatus)
+ return HandleStatusEvent (ref xevent);
+ if (xevent.ClientMessageEvent.message_type == XdndFinished)
+ return HandleFinishedEvent (ref xevent);
+
+ return false;
+ }
+
+ public bool HandleSelectionNotifyEvent (ref XEvent xevent)
+ {
+ MimeHandler handler = FindHandler ((IntPtr) xevent.SelectionEvent.target);
+ if (handler == null)
+ return false;
+ if (data == null)
+ data = new DataObject ();
+
+ handler.Converter.GetData (this, data, ref xevent);
+
+ converts_pending--;
+ if (converts_pending <= 0 && position_recieved) {
+ drag_event = new DragEventArgs (data, 0, pos_x, pos_y,
+ allowed, DragDropEffects.None);
+ Widget.DndEnter (drag_event);
+ SendStatus (source, drag_event.Effect);
+ status_sent = true;
+ }
+ return true;
+ }
+
+ public bool HandleSelectionRequestEvent (ref XEvent xevent)
+ {
+ if (xevent.SelectionRequestEvent.selection != XdndSelection)
+ return false;
+
+ MimeHandler handler = FindHandler (xevent.SelectionRequestEvent.target);
+ if (handler == null)
+ return false;
+
+ handler.Converter.SetData (this, drag_data.Data, ref xevent);
+
+ return true;
+ }
+
+ private bool QueryContinue (bool escape, DragAction action)
+ {
+ QueryContinueDragEventArgs qce = new QueryContinueDragEventArgs ((int) XplatUI.State.ModifierKeys,
+ escape, action);
+
+ Widget c = MwfWindow (source);
+
+ if (c == null) {
+ tracking = false;
+ return false;
+ }
+
+ c.DndContinueDrag (qce);
+
+ switch (qce.Action) {
+ case DragAction.Continue:
+ return true;
+ case DragAction.Drop:
+ SendDrop (drag_data.LastTopLevel, source, IntPtr.Zero);
+ tracking = false;
+ return true;
+ case DragAction.Cancel:
+ drag_data.Reset ();
+ c.InternalCapture = false;
+ break;
+ }
+
+ SendLeave (drag_data.LastTopLevel, toplevel);
+
+ RestoreDefaultCursor ();
+ tracking = false;
+ return false;
+ }
+
+ private void RestoreDefaultCursor ()
+ {
+ // Releasing the mouse buttons should automatically restore the default cursor,
+ // but canceling the operation using QueryContinue should restore it even if the
+ // mouse buttons are not released yet.
+ XplatUIX11.XChangeActivePointerGrab (display,
+ EventMask.ButtonMotionMask |
+ EventMask.PointerMotionMask |
+ EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask,
+ Cursors.Default.Handle, IntPtr.Zero);
+
+ }
+
+ private void GiveFeedback (IntPtr action)
+ {
+ GiveFeedbackEventArgs gfe = new GiveFeedbackEventArgs (EffectFromAction (drag_data.Action), true);
+
+ Widget c = MwfWindow (source);
+ c.DndFeedback (gfe);
+
+ if (gfe.UseDefaultCursors) {
+ Cursor cursor = CursorNo;
+ if (drag_data.WillAccept) {
+ // Same order as on MS
+ if (action == XdndActionCopy)
+ cursor = CursorCopy;
+ else if (action == XdndActionLink)
+ cursor = CursorLink;
+ else if (action == XdndActionMove)
+ cursor = CursorMove;
+ }
+ // TODO: Try not to set the cursor so much
+ //if (cursor.Handle != CurrentCursorHandle) {
+ XplatUIX11.XChangeActivePointerGrab (display,
+ EventMask.ButtonMotionMask |
+ EventMask.PointerMotionMask |
+ EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask,
+ cursor.Handle, IntPtr.Zero);
+ //CurrentCursorHandle = cursor.Handle;
+ //}
+ }
+ }
+
+ private void SetProperty (ref XEvent xevent, IntPtr data, int length)
+ {
+ XEvent sel = new XEvent();
+ sel.SelectionEvent.type = XEventName.SelectionNotify;
+ sel.SelectionEvent.send_event = true;
+ sel.SelectionEvent.display = display;
+ sel.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
+ sel.SelectionEvent.target = xevent.SelectionRequestEvent.target;
+ sel.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
+ sel.SelectionEvent.time = xevent.SelectionRequestEvent.time;
+ sel.SelectionEvent.property = IntPtr.Zero;
+
+ XplatUIX11.XChangeProperty (display, xevent.SelectionRequestEvent.requestor,
+ xevent.SelectionRequestEvent.property,
+ xevent.SelectionRequestEvent.target,
+ 8, PropertyMode.Replace, data, length);
+ sel.SelectionEvent.property = xevent.SelectionRequestEvent.property;
+
+ XplatUIX11.XSendEvent (display, xevent.SelectionRequestEvent.requestor, false,
+ (IntPtr)EventMask.NoEventMask, ref sel);
+ return;
+ }
+
+ private void Reset ()
+ {
+ ResetSourceData ();
+ ResetTargetData ();
+ }
+
+ private void ResetSourceData ()
+ {
+ converts_pending = 0;
+ data = null;
+ }
+
+ private void ResetTargetData ()
+ {
+ position_recieved = false;
+ status_sent = false;
+ }
+
+ private bool Accepting_HandleEnterEvent (ref XEvent xevent)
+ {
+ Reset ();
+
+ source = xevent.ClientMessageEvent.ptr1;
+ toplevel = xevent.AnyEvent.window;
+ target = IntPtr.Zero;
+
+ ConvertData (ref xevent);
+
+ return true;
+ }
+
+ private bool Accepting_HandlePositionEvent (ref XEvent xevent)
+ {
+ pos_x = (int) xevent.ClientMessageEvent.ptr3 >> 16;
+ pos_y = (int) xevent.ClientMessageEvent.ptr3 & 0xFFFF;
+
+ // Copy is implicitly allowed
+ Widget source_Widget = MwfWindow (source);
+ if (source_Widget == null)
+ allowed = EffectsFromX11Source (source, xevent.ClientMessageEvent.ptr5) | DragDropEffects.Copy;
+ else
+ allowed = drag_data.AllowedEffects;
+
+ IntPtr parent, child, new_child, last_drop_child;
+ parent = XplatUIX11.XRootWindow (display, 0);
+ child = toplevel;
+ last_drop_child = IntPtr.Zero;
+ while (true) {
+ int xd, yd;
+ new_child = IntPtr.Zero;
+
+ if (!XplatUIX11.XTranslateCoordinates (display,
+ parent, child, pos_x, pos_y,
+ out xd, out yd, out new_child))
+ break;
+ if (new_child == IntPtr.Zero)
+ break;
+ child = new_child;
+
+ Hwnd h = Hwnd.ObjectFromHandle (child);
+ if (h != null) {
+ Widget d = Widget.FromHandle (h.client_window);
+ if (d != null && d.allow_drop)
+ last_drop_child = child;
+ }
+ }
+
+ if (last_drop_child != IntPtr.Zero)
+ child = last_drop_child;
+
+ if (target != child) {
+ // We have moved into a new Widget
+ // or into a Widget for the first time
+ Finish ();
+ }
+ target = child;
+ Hwnd hwnd = Hwnd.ObjectFromHandle (target);
+ if (hwnd == null)
+ return true;
+
+ Widget c = Widget.FromHandle (hwnd.client_window);
+
+ if (c == null)
+ return true;
+ if (!c.allow_drop) {
+ SendStatus (source, DragDropEffects.None);
+ Finish ();
+ return true;
+ }
+
+ Widget = c;
+ position_recieved = true;
+
+ if (converts_pending > 0)
+ return true;
+
+ if (!status_sent) {
+ drag_event = new DragEventArgs (data, 0, pos_x, pos_y,
+ allowed, DragDropEffects.None);
+ Widget.DndEnter (drag_event);
+
+ SendStatus (source, drag_event.Effect);
+ status_sent = true;
+ } else {
+ drag_event.x = pos_x;
+ drag_event.y = pos_y;
+ Widget.DndOver (drag_event);
+
+ SendStatus (source, drag_event.Effect);
+ }
+
+ return true;
+ }
+
+ private void Finish ()
+ {
+ if (Widget != null) {
+ if (drag_event == null) {
+ if (data == null)
+ data = new DataObject ();
+ drag_event = new DragEventArgs (data,
+ 0, pos_x, pos_y,
+ allowed, DragDropEffects.None);
+ }
+ Widget.DndLeave (drag_event);
+ Widget = null;
+ }
+ ResetTargetData ();
+ }
+
+ private bool Accepting_HandleDropEvent (ref XEvent xevent)
+ {
+ if (Widget != null && drag_event != null) {
+ drag_event = new DragEventArgs (data,
+ 0, pos_x, pos_y,
+ allowed, drag_event.Effect);
+ Widget.DndDrop (drag_event);
+ }
+ SendFinished ();
+ return true;
+ }
+
+ private bool Accepting_HandleLeaveEvent (ref XEvent xevent)
+ {
+ if (Widget != null && drag_event != null)
+ Widget.DndLeave (drag_event);
+ // Reset ();
+ return true;
+ }
+
+ private bool HandleStatusEvent (ref XEvent xevent)
+ {
+ if (drag_data != null && drag_data.State == DragState.Entered) {
+
+ if (!QueryContinue (false, DragAction.Continue))
+ return true;
+
+ drag_data.WillAccept = ((int) xevent.ClientMessageEvent.ptr2 & 0x1) != 0;
+
+ GiveFeedback (xevent.ClientMessageEvent.ptr5);
+ }
+ return true;
+ }
+
+ private bool HandleFinishedEvent (ref XEvent xevent)
+ {
+ return true;
+ }
+
+ private DragDropEffects EffectsFromX11Source (IntPtr source, IntPtr action_atom)
+ {
+ DragDropEffects allowed = DragDropEffects.None;
+ IntPtr type, count, remaining, data = IntPtr.Zero;
+ int format;
+
+ XplatUIX11.XGetWindowProperty (display, source, XdndActionList,
+ IntPtr.Zero, new IntPtr (32), false, (IntPtr) Atom.AnyPropertyType,
+ out type, out format, out count, out remaining, ref data);
+
+ int intptr_size = Marshal.SizeOf (typeof (IntPtr));
+ for (int i = 0; i < count.ToInt32 (); i++) {
+ IntPtr current_atom = Marshal.ReadIntPtr (data, i * intptr_size);
+ allowed |= EffectFromAction (current_atom);
+ }
+
+ // if source is not providing the action list, use the
+ // default action passed in the x11 dnd position message
+ if (allowed == DragDropEffects.None)
+ allowed = EffectFromAction (action_atom);
+
+ return allowed;
+ }
+
+ private DragDropEffects EffectFromAction (IntPtr action)
+ {
+ if (action == XdndActionCopy)
+ return DragDropEffects.Copy;
+ else if (action == XdndActionMove)
+ return DragDropEffects.Move;
+ if (action == XdndActionLink)
+ return DragDropEffects.Link;
+
+ return DragDropEffects.None;
+ }
+
+ private IntPtr ActionFromEffect (DragDropEffects effect)
+ {
+ IntPtr action = IntPtr.Zero;
+
+ // We can't OR together actions on XDND so sadly the primary
+ // is the only one shown here
+ if ((effect & DragDropEffects.Copy) != 0)
+ action = XdndActionCopy;
+ else if ((effect & DragDropEffects.Move) != 0)
+ action = XdndActionMove;
+ else if ((effect & DragDropEffects.Link) != 0)
+ action = XdndActionLink;
+ return action;
+ }
+
+ private bool ConvertData (ref XEvent xevent)
+ {
+ bool match = false;
+
+ Widget mwfWidget = MwfWindow (source);
+
+ /* To take advantage of the mwfWidget, we have to be sure
+ that the dnd operation is still happening (since messages are asynchronous) */
+ if (mwfWidget != null && drag_data != null) {
+ if (!tracking)
+ return false;
+
+ IDataObject dragged = drag_data.Data as IDataObject;
+ if (dragged != null) {
+ data = dragged;
+ } else {
+ if (data == null)
+ data = new DataObject ();
+ SetDataWithFormats (drag_data.Data);
+ }
+ return true;
+ }
+
+ foreach (IntPtr atom in SourceSupportedList (ref xevent)) {
+ MimeHandler handler = FindHandler (atom);
+ if (handler == null)
+ continue;
+ XplatUIX11.XConvertSelection (display, XdndSelection, handler.Type,
+ handler.NonProtocol, toplevel, IntPtr.Zero /* CurrentTime */);
+ converts_pending++;
+ match = true;
+ }
+ return match;
+ }
+
+ private void SetDataWithFormats (object value)
+ {
+ if (value is string) {
+ data.SetData (DataFormats.Text, value);
+ data.SetData (DataFormats.UnicodeText, value);
+ }
+
+ data.SetData (value);
+ }
+
+ private MimeHandler FindHandler (IntPtr atom)
+ {
+ if (atom == IntPtr.Zero)
+ return null;
+ foreach (MimeHandler handler in MimeHandlers) {
+ if (handler.Type == atom)
+ return handler;
+ }
+ return null;
+ }
+
+ private MimeHandler FindHandler (string name)
+ {
+ foreach (MimeHandler handler in MimeHandlers) {
+ foreach (string alias in handler.Aliases) {
+ if (alias == name)
+ return handler;
+ }
+ }
+ return null;
+ }
+
+ private void SendStatus (IntPtr source, DragDropEffects effect)
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.AnyEvent.type = XEventName.ClientMessage;
+ xevent.AnyEvent.display = display;
+ xevent.ClientMessageEvent.window = source;
+ xevent.ClientMessageEvent.message_type = XdndStatus;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = toplevel;
+ if (effect != DragDropEffects.None && (effect & allowed) != 0)
+ xevent.ClientMessageEvent.ptr2 = (IntPtr) 1;
+
+ xevent.ClientMessageEvent.ptr5 = ActionFromEffect (effect);
+ XplatUIX11.XSendEvent (display, source, false, IntPtr.Zero, ref xevent);
+ }
+
+ private void SendEnter (IntPtr handle, IntPtr from, IntPtr [] supported)
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.AnyEvent.type = XEventName.ClientMessage;
+ xevent.AnyEvent.display = display;
+ xevent.ClientMessageEvent.window = handle;
+ xevent.ClientMessageEvent.message_type = XdndEnter;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = from;
+
+ // (int) xevent.ClientMessageEvent.ptr2 & 0x1)
+ // int ptr2 = 0x1;
+ // xevent.ClientMessageEvent.ptr2 = (IntPtr) ptr2;
+ // (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24)
+ xevent.ClientMessageEvent.ptr2 = (IntPtr) ((long)XdndVersion [0] << 24);
+
+ if (supported.Length > 0)
+ xevent.ClientMessageEvent.ptr3 = supported [0];
+ if (supported.Length > 1)
+ xevent.ClientMessageEvent.ptr4 = supported [1];
+ if (supported.Length > 2)
+ xevent.ClientMessageEvent.ptr5 = supported [2];
+
+ XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent);
+ }
+
+ private void SendDrop (IntPtr handle, IntPtr from, IntPtr time)
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.AnyEvent.type = XEventName.ClientMessage;
+ xevent.AnyEvent.display = display;
+ xevent.ClientMessageEvent.window = handle;
+ xevent.ClientMessageEvent.message_type = XdndDrop;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = from;
+ xevent.ClientMessageEvent.ptr3 = time;
+
+ XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent);
+ dropped = true;
+ }
+
+ private void SendPosition (IntPtr handle, IntPtr from, IntPtr action, int x, int y, IntPtr time)
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.AnyEvent.type = XEventName.ClientMessage;
+ xevent.AnyEvent.display = display;
+ xevent.ClientMessageEvent.window = handle;
+ xevent.ClientMessageEvent.message_type = XdndPosition;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = from;
+ xevent.ClientMessageEvent.ptr3 = (IntPtr) ((x << 16) | (y & 0xFFFF));
+ xevent.ClientMessageEvent.ptr4 = time;
+ xevent.ClientMessageEvent.ptr5 = action;
+
+ XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent);
+ }
+
+ private void SendLeave (IntPtr handle, IntPtr from)
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.AnyEvent.type = XEventName.ClientMessage;
+ xevent.AnyEvent.display = display;
+ xevent.ClientMessageEvent.window = handle;
+ xevent.ClientMessageEvent.message_type = XdndLeave;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = from;
+
+ XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent);
+ }
+
+ private void SendFinished ()
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.AnyEvent.type = XEventName.ClientMessage;
+ xevent.AnyEvent.display = display;
+ xevent.ClientMessageEvent.window = source;
+ xevent.ClientMessageEvent.message_type = XdndFinished;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = toplevel;
+
+ XplatUIX11.XSendEvent (display, source, false, IntPtr.Zero, ref xevent);
+ }
+
+ // There is a somewhat decent amount of overhead
+ // involved in setting up dnd so we do it lazily
+ // as a lot of applications do not even use it.
+ private void Init ()
+ {
+ XdndAware = XplatUIX11.XInternAtom (display, "XdndAware", false);
+ XdndEnter = XplatUIX11.XInternAtom (display, "XdndEnter", false);
+ XdndLeave = XplatUIX11.XInternAtom (display, "XdndLeave", false);
+ XdndPosition = XplatUIX11.XInternAtom (display, "XdndPosition", false);
+ XdndStatus = XplatUIX11.XInternAtom (display, "XdndStatus", false);
+ XdndDrop = XplatUIX11.XInternAtom (display, "XdndDrop", false);
+ XdndSelection = XplatUIX11.XInternAtom (display, "XdndSelection", false);
+ XdndFinished = XplatUIX11.XInternAtom (display, "XdndFinished", false);
+ XdndTypeList = XplatUIX11.XInternAtom (display, "XdndTypeList", false);
+ XdndActionCopy = XplatUIX11.XInternAtom (display, "XdndActionCopy", false);
+ XdndActionMove = XplatUIX11.XInternAtom (display, "XdndActionMove", false);
+ XdndActionLink = XplatUIX11.XInternAtom (display, "XdndActionLink", false);
+ //XdndActionPrivate = XplatUIX11.XInternAtom (display, "XdndActionPrivate", false);
+ XdndActionList = XplatUIX11.XInternAtom (display, "XdndActionList", false);
+ //XdndActionDescription = XplatUIX11.XInternAtom (display, "XdndActionDescription", false);
+ //XdndActionAsk = XplatUIX11.XInternAtom (display, "XdndActionAsk", false);
+
+ foreach (MimeHandler handler in MimeHandlers) {
+ handler.Type = XplatUIX11.XInternAtom (display, handler.Name, false);
+ handler.NonProtocol = XplatUIX11.XInternAtom (display,
+ String.Concat ("MWFNonP+", handler.Name), false);
+ }
+
+ }
+
+ private IntPtr [] SourceSupportedList (ref XEvent xevent)
+ {
+ IntPtr [] res;
+
+
+ if (((int) xevent.ClientMessageEvent.ptr2 & 0x1) == 0) {
+ res = new IntPtr [3];
+ res [0] = xevent.ClientMessageEvent.ptr3;
+ res [1] = xevent.ClientMessageEvent.ptr4;
+ res [2] = xevent.ClientMessageEvent.ptr5;
+ } else {
+ IntPtr type;
+ int format;
+ IntPtr count;
+ IntPtr remaining;
+ IntPtr data = IntPtr.Zero;
+
+ XplatUIX11.XGetWindowProperty (display, source, XdndTypeList,
+ IntPtr.Zero, new IntPtr(32), false, (IntPtr) Atom.XA_ATOM,
+ out type, out format, out count,
+ out remaining, ref data);
+
+ res = new IntPtr [count.ToInt32()];
+ for (int i = 0; i < count.ToInt32(); i++) {
+ res [i] = (IntPtr) Marshal.ReadInt32 (data, i *
+ Marshal.SizeOf (typeof (int)));
+ }
+
+ XplatUIX11.XFree (data);
+ }
+
+ return res;
+ }
+
+ private string GetText (ref XEvent xevent, bool unicode)
+ {
+ int nread = 0;
+ IntPtr nitems;
+ IntPtr bytes_after;
+
+ StringBuilder builder = new StringBuilder ();
+ do {
+ IntPtr actual_type;
+ int actual_fmt;
+ IntPtr data = IntPtr.Zero;
+
+ if (0 != XplatUIX11.XGetWindowProperty (display,
+ xevent.AnyEvent.window,
+ (IntPtr) xevent.SelectionEvent.property,
+ IntPtr.Zero, new IntPtr(0xffffff), false,
+ (IntPtr) Atom.AnyPropertyType, out actual_type,
+ out actual_fmt, out nitems, out bytes_after,
+ ref data)) {
+ XplatUIX11.XFree (data);
+ break;
+ }
+
+ if (unicode)
+ builder.Append (Marshal.PtrToStringUni (data));
+ else
+ builder.Append (Marshal.PtrToStringAnsi (data));
+ nread += nitems.ToInt32();
+
+ XplatUIX11.XFree (data);
+ } while (bytes_after.ToInt32() > 0);
+ if (nread == 0)
+ return null;
+ return builder.ToString ();
+ }
+
+ private MemoryStream GetData (ref XEvent xevent)
+ {
+ int nread = 0;
+ IntPtr nitems;
+ IntPtr bytes_after;
+
+ MemoryStream res = new MemoryStream ();
+ do {
+ IntPtr actual_type;
+ int actual_fmt;
+ IntPtr data = IntPtr.Zero;
+
+ if (0 != XplatUIX11.XGetWindowProperty (display,
+ xevent.AnyEvent.window,
+ (IntPtr) xevent.SelectionEvent.property,
+ IntPtr.Zero, new IntPtr(0xffffff), false,
+ (IntPtr) Atom.AnyPropertyType, out actual_type,
+ out actual_fmt, out nitems, out bytes_after,
+ ref data)) {
+ XplatUIX11.XFree (data);
+ break;
+ }
+
+ for (int i = 0; i < nitems.ToInt32(); i++)
+ res.WriteByte (Marshal.ReadByte (data, i));
+ nread += nitems.ToInt32();
+
+ XplatUIX11.XFree (data);
+ } while (bytes_after.ToInt32() > 0);
+ return res;
+ }
+
+ private Widget MwfWindow (IntPtr window)
+ {
+ Hwnd hwnd = Hwnd.ObjectFromHandle (window);
+ if (hwnd == null)
+ return null;
+
+ Widget res = Widget.FromHandle (hwnd.client_window);
+
+ if (res == null)
+ res = Widget.FromHandle (window);
+
+ return res;
+ }
+
+ private bool IsWindowDndAware (IntPtr handle)
+ {
+ bool res = true;
+ // Check the version number, we need greater than 3
+ IntPtr actual;
+ int format;
+ IntPtr count;
+ IntPtr remaining;
+ IntPtr data = IntPtr.Zero;
+
+ XplatUIX11.XGetWindowProperty (display, handle, XdndAware, IntPtr.Zero, new IntPtr(0x8000000), false,
+ (IntPtr) Atom.XA_ATOM, out actual, out format,
+ out count, out remaining, ref data);
+
+ if (actual != (IntPtr) Atom.XA_ATOM || format != 32 ||
+ count.ToInt32() == 0 || data == IntPtr.Zero) {
+ if (data != IntPtr.Zero)
+ XplatUIX11.XFree (data);
+ return false;
+ }
+
+ int version = Marshal.ReadInt32 (data, 0);
+
+ if (version < 3) {
+ Console.Error.WriteLine ("XDND Version too old (" + version + ").");
+ XplatUIX11.XFree (data);
+ return false;
+ }
+
+ // First type is actually the XDND version
+ if (count.ToInt32() > 1) {
+ res = false;
+ for (int i = 1; i < count.ToInt32(); i++) {
+ IntPtr type = (IntPtr) Marshal.ReadInt32 (data, i *
+ Marshal.SizeOf (typeof (int)));
+ for (int j = 0; j < drag_data.SupportedTypes.Length; j++) {
+ if (drag_data.SupportedTypes [j] == type) {
+ res = true;
+ break;
+ }
+ }
+ }
+ }
+
+ XplatUIX11.XFree (data);
+ return res;
+ }
+
+ private IntPtr [] DetermineSupportedTypes (object data)
+ {
+ ArrayList res = new ArrayList ();
+
+ if (data is string) {
+ MimeHandler handler = FindHandler ("text/plain");
+ if (handler != null)
+ res.Add (handler.Type);
+ }/* else if (data is Bitmap)
+ res.Add (data);
+
+ */
+
+ IDataObject data_object = data as IDataObject;
+ if (data_object != null) {
+ foreach (string format in data_object.GetFormats (true)) {
+ MimeHandler handler = FindHandler (format);
+ if (handler != null && !res.Contains (handler.Type))
+ res.Add (handler.Type);
+ }
+ }
+
+ if (data is ISerializable) {
+ MimeHandler handler = FindHandler ("application/x-mono-serialized-object");
+ if (handler != null)
+ res.Add (handler.Type);
+ }
+
+ return (IntPtr []) res.ToArray (typeof (IntPtr));
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/X11Exception.cs b/source/ShiftUI/Internal/X11Exception.cs
new file mode 100644
index 0000000..5d3d47e
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Exception.cs
@@ -0,0 +1,87 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+//
+
+using System;
+using System.Text;
+using System.Threading;
+using ShiftUI;
+
+namespace ShiftUI.X11Internal {
+
+ internal class X11Exception : ApplicationException {
+ IntPtr Display;
+ IntPtr ResourceID;
+ IntPtr Serial;
+ XRequest RequestCode;
+ byte ErrorCode;
+ byte MinorCode;
+
+ public X11Exception (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode)
+ {
+ this.Display = Display;
+ this.ResourceID = ResourceID;
+ this.Serial = Serial;
+ this.RequestCode = RequestCode;
+ this.ErrorCode = ErrorCode;
+ this.MinorCode = MinorCode;
+ }
+
+ public override string Message {
+ get {
+ return GetMessage (Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode);
+ }
+ }
+
+ public static string GetMessage (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode)
+ {
+ StringBuilder sb;
+ string x_error_text;
+ string error;
+ string hwnd_text;
+ string Widget_text;
+ Hwnd hwnd;
+ Widget c;
+
+ sb = new StringBuilder(160);
+ Xlib.XGetErrorText (Display, ErrorCode, sb, sb.Capacity);
+ x_error_text = sb.ToString();
+ hwnd = Hwnd.ObjectFromHandle(ResourceID);
+ if (hwnd != null) {
+ hwnd_text = hwnd.ToString();
+ c = Widget.FromHandle(hwnd.Handle);
+ if (c != null) {
+ Widget_text = c.ToString();
+ } else {
+ Widget_text = String.Format("<handle {0:X} non-existant>", hwnd.Handle);
+ }
+ }
+ else {
+ hwnd_text = "<null>";
+ Widget_text = "<null>";
+ }
+
+ error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:X}\n Serial: {4}\n Hwnd: {5}\n Widget: {6}", x_error_text, RequestCode, RequestCode, ResourceID.ToInt32(), Serial, hwnd_text, Widget_text);
+ return error;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/X11Hwnd.cs b/source/ShiftUI/Internal/X11Hwnd.cs
new file mode 100644
index 0000000..0ef248d
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Hwnd.cs
@@ -0,0 +1,1750 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+//
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using ShiftUI;
+
+namespace ShiftUI.X11Internal {
+
+ internal class X11Hwnd : Hwnd
+ {
+ X11Display display;
+
+ bool refetch_window_type = true;
+ bool refetch_window_opacity = true;
+
+ IntPtr[] wm_state = new IntPtr[0];
+ IntPtr[] window_type = new IntPtr[0];
+ double trans = 1.0;
+
+ string text;
+ new X11ThreadQueue queue;
+
+ const EventMask SelectInputMask = (EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask |
+ EventMask.KeyPressMask |
+ EventMask.KeyReleaseMask |
+ EventMask.EnterWindowMask |
+ EventMask.LeaveWindowMask |
+ EventMask.ExposureMask |
+ EventMask.FocusChangeMask |
+ EventMask.PointerMotionMask |
+ EventMask.SubstructureNotifyMask);
+
+ public X11Hwnd (X11Display display)
+ {
+ this.display = display;
+ Queue = XplatUIX11_new.GetInstance().ThreadQueue(Thread.CurrentThread);
+ }
+
+ public X11Hwnd (X11Display display, IntPtr handle) : this (display)
+ {
+ if (handle == IntPtr.Zero)
+ throw new ArgumentNullException ("handle");
+ WholeWindow = ClientWindow = handle;
+ }
+
+ // XXX this needs to be here so we don't have to
+ // change Hwnd. once we land, remove this and make
+ // Hwnd.Queue virtual or abstract
+ public new X11ThreadQueue Queue {
+ get { return queue; }
+ set { queue = value; }
+ }
+
+ public virtual void CreateWindow (CreateParams cp)
+ {
+ if (WholeWindow != IntPtr.Zero || ClientWindow != IntPtr.Zero)
+ throw new Exception ("createwindow called a second time on live X11Hwnd");
+
+ XSetWindowAttributes Attributes;
+ int x;
+ int y;
+ int width;
+ int height;
+ IntPtr ParentHandle;
+ SetWindowValuemask ValueMask;
+
+ Attributes = new XSetWindowAttributes();
+ x = cp.X;
+ y = cp.Y;
+ width = cp.Width;
+ height = cp.Height;
+ initial_ex_style = (WindowExStyles) cp.ExStyle;
+
+ /* Figure out our parent handle */
+ if (cp.Parent != IntPtr.Zero)
+ // the parent handle is specified in the CreateParams
+ ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).ClientWindow;
+ else if (StyleSet (cp.Style, WindowStyles.WS_CHILD))
+ // a child Widget with an unassigned parent gets created under the FosterParent
+ ParentHandle = display.FosterParent.Handle;
+ else
+ // for all other cases, the parent is the root window
+ ParentHandle = display.RootWindow.Handle;
+
+ ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
+
+ Attributes.bit_gravity = Gravity.NorthWestGravity;
+ Attributes.win_gravity = Gravity.NorthWestGravity;
+
+ // Save what's under the toolwindow
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
+ Attributes.save_under = true;
+ ValueMask |= SetWindowValuemask.SaveUnder;
+ }
+
+ // If we're a popup without caption we override the WM
+ if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
+ Attributes.override_redirect = true;
+ ValueMask |= SetWindowValuemask.OverrideRedirect;
+ }
+
+ // Default position on screen, if window manager doesn't place us somewhere else
+ if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)
+ && !StyleSet (cp.Style, WindowStyles.WS_POPUP)) {
+ if (x<0) x = 50;
+ if (y<0) y = 50;
+ }
+ // minimum width/height
+ if (width<1) width=1;
+ if (height<1) height=1;
+
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ Parent = Hwnd.ObjectFromHandle (cp.Parent);
+
+ Enabled = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
+
+ ClientWindow = IntPtr.Zero;
+
+ WholeWindow = Xlib.XCreateWindow (display.Handle, ParentHandle,
+ X, Y, Width, Height, 0,
+ (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput,
+ IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes);
+ if (WholeWindow == IntPtr.Zero)
+ throw new Exception ("Coult not create X11 nc window");
+
+ ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
+
+ if (display.CustomVisual != IntPtr.Zero && display.CustomColormap != IntPtr.Zero) {
+ ValueMask |= SetWindowValuemask.ColorMap;
+ Attributes.colormap = display.CustomColormap;
+ }
+
+ ClientWindow = Xlib.XCreateWindow (display.Handle, WholeWindow,
+ ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0,
+ (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput,
+ display.CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes);
+
+ if (ClientWindow == IntPtr.Zero)
+ throw new Exception("Could not create X11 client window");
+
+#if DriverDebug || DriverDebugCreate
+ Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), Parent != null ? Parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle);
+#endif
+
+ if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
+ if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
+ XSizeHints hints;
+
+ hints = new XSizeHints();
+ hints.x = X;
+ hints.y = Y;
+ hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition);
+ Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints);
+ }
+ }
+
+ Xlib.XSelectInput (display.Handle, WholeWindow, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask)));
+ if (WholeWindow != ClientWindow)
+ Xlib.XSelectInput (display.Handle, ClientWindow, new IntPtr ((int)SelectInputMask));
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
+ WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL;
+ Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.Handle);
+ }
+
+ SetWMStyles (cp);
+
+ // set the group leader
+ XWMHints wm_hints = new XWMHints ();
+
+ wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint);
+ wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
+ wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState;
+ wm_hints.window_group = ParentHandle == display.RootWindow.Handle ? ParentHandle : WholeWindow;
+
+ Xlib.XSetWMHints (display.Handle, WholeWindow, ref wm_hints );
+
+ if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE))
+ SetWindowState (FormWindowState.Minimized);
+ else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE))
+ SetWindowState (FormWindowState.Maximized);
+
+ // for now make all windows dnd enabled
+ display.Dnd.SetAllowDrop (this, true);
+
+ // Set caption/window title
+ Text = cp.Caption;
+
+ display.SendMessage (Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */);
+ SendParentNotify (Msg.WM_CREATE, int.MaxValue, int.MaxValue);
+
+ if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) {
+ visible = true;
+ Map ();
+ if (!(Widget.FromHandle(Handle) is Form))
+ display.SendMessage (Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
+ }
+ }
+
+ public virtual void DestroyWindow ()
+ {
+ if (WholeWindow != IntPtr.Zero) {
+#if DriverDebug || DriverDebugDestroy
+ Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", WholeWindow.ToInt32());
+#endif
+ Xlib.XDestroyWindow (display.Handle, WholeWindow);
+ }
+ else if (ClientWindow != IntPtr.Zero) {
+#if DriverDebug || DriverDebugDestroy
+ Console.WriteLine ("XDestroyWindow (client_window = {0:X})", ClientWindow.ToInt32());
+#endif
+ Xlib.XDestroyWindow (display.Handle, ClientWindow);
+ }
+ }
+
+ public void Activate ()
+ {
+ if (((IList)display.RootWindow._NET_SUPPORTED).Contains (display.Atoms._NET_ACTIVE_WINDOW)) {
+ display.SendNetWMMessage (WholeWindow, display.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
+ }
+ else {
+ Xlib.XRaiseWindow (display.Handle, WholeWindow);
+ }
+ }
+
+ public void Update ()
+ {
+ try {
+ Queue.Lock ();
+ if (!Visible || !PendingExpose || !Mapped)
+ return;
+
+ // XXX this SendMessage call should probably not be inside the lock
+ display.SendMessage (ClientWindow, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+
+ PendingExpose = false;
+ }
+ finally {
+ Queue.Unlock ();
+ }
+ }
+
+ public void MenuToScreen (ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+
+ Xlib.XTranslateCoordinates (display.Handle,
+ WholeWindow, display.RootWindow.Handle,
+ x, y, out dest_x_return, out dest_y_return, out child);
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ public virtual void PropertyChanged (XEvent xevent)
+ {
+ if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_WINDOW_TYPE) {
+ // we need to recache our WINDOW_TYPE on the next query
+ refetch_window_type = true;
+ window_type = null;
+ }
+ else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_STATE) {
+ // we need to recache our WM_STATE on the next query
+ }
+ else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_NAME) {
+ // update our Text property
+ }
+ else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_WINDOW_OPACITY) {
+ // we need to recache our _NET_WM_WINDOW_OPACITY on the next query.
+ refetch_window_opacity = true;
+ }
+ // else we don't care about it
+
+ }
+
+ public void SetIcon (Icon icon)
+ {
+ if (icon == null) {
+ Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms._NET_WM_ICON);
+ }
+ else {
+ Bitmap bitmap;
+ int size;
+ IntPtr[] data;
+ int index;
+
+ bitmap = icon.ToBitmap();
+ index = 0;
+ size = bitmap.Width * bitmap.Height + 2;
+ data = new IntPtr[size];
+
+ data[index++] = (IntPtr)bitmap.Width;
+ data[index++] = (IntPtr)bitmap.Height;
+
+ for (int y = 0; y < bitmap.Height; y++) {
+ for (int x = 0; x < bitmap.Width; x++) {
+ data[index++] = (IntPtr)bitmap.GetPixel(x, y).ToArgb();
+ }
+ }
+
+ Xlib.XChangeProperty (display.Handle, WholeWindow,
+ display.Atoms._NET_WM_ICON, display.Atoms.XA_CARDINAL, 32,
+ PropertyMode.Replace, data, size);
+ }
+ }
+
+ public double GetWindowTransparency ()
+ {
+ if (refetch_window_opacity) {
+ trans = 1.0;
+
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ IntPtr w = WholeWindow;
+ if (reparented)
+ w = display.XGetParent (WholeWindow);
+
+ Xlib.XGetWindowProperty (display.Handle, w,
+ display.Atoms._NET_WM_WINDOW_OPACITY, IntPtr.Zero, new IntPtr (16), false,
+ display.Atoms.XA_CARDINAL,
+ out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if (((long)nitems == 1) && (prop != IntPtr.Zero)) {
+ uint x11_opacity = (uint)Marshal.ReadInt32(prop, 0);
+ trans = ((double)x11_opacity) / (uint)0xffffffff;
+ }
+
+ if (prop != IntPtr.Zero) {
+ Xlib.XFree(prop);
+ }
+ }
+
+ return trans;
+ }
+
+ public void SetWindowTransparency (double transparency, Color key)
+ {
+ IntPtr x11_opacity;
+
+ opacity = (uint)(0xffffffff * transparency);
+ x11_opacity = (IntPtr)((int)opacity);
+
+ IntPtr w = WholeWindow;
+ if (reparented)
+ w = display.XGetParent (WholeWindow);
+ Xlib.XChangeProperty (display.Handle, w,
+ display.Atoms._NET_WM_WINDOW_OPACITY, display.Atoms.XA_CARDINAL, 32,
+ PropertyMode.Replace, ref x11_opacity, 1);
+ }
+
+ public IntPtr DefWndProc (ref Message msg)
+ {
+ switch ((Msg)msg.Msg) {
+ case Msg.WM_PAINT:
+ Queue.Lock ();
+ PendingExpose = false;
+ Queue.Unlock ();
+ return IntPtr.Zero;
+
+ case Msg.WM_NCPAINT:
+ Queue.Lock ();
+ PendingNCExpose = false;
+ Queue.Unlock ();
+ return IntPtr.Zero;
+
+ case Msg.WM_CONTEXTMENU:
+ if (Parent != null)
+ display.SendMessage (Parent.ClientWindow, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam);
+ return IntPtr.Zero;
+
+ case Msg.WM_MOUSEWHEEL:
+ if (Parent != null) {
+ display.SendMessage (Parent.ClientWindow, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam);
+ if (msg.Result == IntPtr.Zero)
+ return IntPtr.Zero;
+ }
+ return IntPtr.Zero;
+
+ case Msg.WM_SETCURSOR:
+ X11Hwnd parent = (X11Hwnd)Parent;
+ // Pass to parent window first
+ while ((parent != null) && (msg.Result == IntPtr.Zero)) {
+ msg.Result = NativeWindow.WndProc (parent.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam);
+ parent = (X11Hwnd)Parent;
+ }
+
+ 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)
+ display.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;
+ }
+
+ display.SetCursor (msg.HWnd, handle);
+ }
+ return (IntPtr)1;
+
+ default:
+ return IntPtr.Zero;
+ }
+ }
+
+
+ public void AddExpose (bool client, int x, int y, int width, int height)
+ {
+ // Don't waste time
+ if ((x > Width) || (y > Height) || ((x + width) <= 0) || ((y + height) <= 0))
+ return;
+
+ // Keep the invalid area as small as needed
+ if ((x + width) > Width)
+ width = Width - x;
+
+ if ((y + height) > Height)
+ height = Height - y;
+
+ if (client) {
+ AddInvalidArea(x, y, width, height);
+ PendingExpose = true;
+ }
+ else {
+ AddNcInvalidArea (x, y, width, height);
+ PendingNCExpose = true;
+ }
+ }
+
+ public void AddConfigureNotify (XEvent xevent)
+ {
+ // We drop configure events for Client windows
+ if ((xevent.ConfigureEvent.window != WholeWindow) || (xevent.ConfigureEvent.window != xevent.ConfigureEvent.xevent))
+ return;
+
+ if (!reparented) {
+ X = xevent.ConfigureEvent.x;
+ Y = xevent.ConfigureEvent.y;
+ } else {
+ // This sucks ass, part 1
+ // Every WM does the ConfigureEvents of toplevel windows different, so there's
+ // no standard way of getting our adjustment.
+ // The code below is needed for KDE and FVWM, the 'whacky_wm' part is for metacity
+ // Several other WMs do their decorations different yet again and we fail to deal
+ // with that, since I couldn't find any frigging commonality between them.
+ // The only sane WM seems to be KDE
+
+ if (!xevent.ConfigureEvent.send_event) {
+ IntPtr dummy_ptr;
+
+ int trans_x;
+ int trans_y;
+
+ Xlib.XTranslateCoordinates (display.Handle, WholeWindow, display.RootWindow.Handle,
+ -xevent.ConfigureEvent.x, -xevent.ConfigureEvent.y,
+ out trans_x, out trans_y, out dummy_ptr);
+
+ X = trans_x;
+ Y = trans_y;
+ } else {
+ // This is a synthetic event, coordinates are in root space
+ X = xevent.ConfigureEvent.x;
+ Y = xevent.ConfigureEvent.y;
+ if (whacky_wm) {
+ int frame_left;
+ int frame_top;
+
+ FrameExtents (out frame_left, out frame_top);
+ X -= frame_left;
+ Y -= frame_top;
+ }
+ }
+ }
+
+ Width = xevent.ConfigureEvent.width;
+ Height = xevent.ConfigureEvent.height;
+ ClientRect = Rectangle.Empty;
+
+ if (!configure_pending) {
+ Queue.AddConfigure (this);
+ configure_pending = true;
+ }
+ }
+
+ public void HandleMapEvent (XEvent xevent)
+ {
+ if (xevent.type == XEventName.MapNotify) {
+ }
+ else {
+ }
+ }
+
+ public void HandleConfigureNotify (XEvent xevent)
+ {
+ configure_pending = false;
+
+ display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+
+ // We need to adjust our client window to track the resize of whole_window
+ if (WholeWindow != ClientWindow)
+ PerformNCCalc ();
+ }
+
+ public void Invalidate (Rectangle rc, bool clear)
+ {
+ if (clear) {
+ AddExpose (true, X, Y, Width, Height);
+ } else {
+ AddExpose (true, rc.X, rc.Y, rc.Width, rc.Height);
+ }
+ }
+
+ public void InvalidateNC ()
+ {
+ AddExpose (false, 0, 0, Width, Height);
+ }
+
+ // XXX this assumes the queue lock is held
+ public bool PendingNCExpose {
+ get { return nc_expose_pending; }
+ set {
+ if (nc_expose_pending == value)
+ return;
+ nc_expose_pending = value;
+
+ if (nc_expose_pending && !expose_pending)
+ Queue.AddPaint (this);
+ else if (!nc_expose_pending && !expose_pending)
+ Queue.RemovePaint (this);
+ }
+ }
+
+ // XXX this assumes the queue lock is held
+ public bool PendingExpose {
+ get { return expose_pending; }
+ set {
+ if (expose_pending == value)
+ return;
+ expose_pending = value;
+
+ if (expose_pending && !nc_expose_pending)
+ Queue.AddPaint (this);
+ else if (!expose_pending && !nc_expose_pending)
+ Queue.RemovePaint (this);
+ }
+ }
+
+ public PaintEventArgs PaintEventStart (ref Message m, bool client)
+ {
+ PaintEventArgs paint_event;
+ Graphics dc;
+
+ if (client) {
+ dc = Graphics.FromHwnd (ClientWindow);
+
+ Region clip_region = new Region ();
+ clip_region.MakeEmpty();
+
+ foreach (Rectangle r in ClipRectangles)
+ clip_region.Union (r);
+
+ if (UserClip != null)
+ clip_region.Intersect(UserClip);
+
+ dc.Clip = clip_region;
+ paint_event = new PaintEventArgs(dc, Invalid);
+ PendingExpose = false;
+
+ ClearInvalidArea();
+
+ drawing_stack.Push (paint_event);
+ drawing_stack.Push (dc);
+
+ return paint_event;
+ }
+ else {
+ dc = Graphics.FromHwnd (WholeWindow);
+
+ if (!nc_invalid.IsEmpty) {
+ dc.SetClip (nc_invalid);
+ paint_event = new PaintEventArgs(dc, nc_invalid);
+ }
+ else {
+ paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, width, height));
+ }
+ PendingNCExpose = false;
+
+ ClearNcInvalidArea ();
+
+ drawing_stack.Push (paint_event);
+ drawing_stack.Push (dc);
+
+ return paint_event;
+ }
+ }
+
+ public void PaintEventEnd (ref Message m, bool client)
+ {
+ Graphics dc = (Graphics)drawing_stack.Pop ();
+ dc.Flush();
+ dc.Dispose();
+
+ PaintEventArgs pe = (PaintEventArgs)drawing_stack.Pop();
+ pe.SetGraphics (null);
+ pe.Dispose ();
+ }
+
+ public void DrawReversibleRectangle (Rectangle rect, int line_width)
+ {
+ XGCValues gc_values;
+ IntPtr gc;
+
+ gc_values = new XGCValues ();
+
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+ gc_values.line_width = line_width;
+
+ // XXX multiscreen support
+ gc_values.foreground = Xlib.XBlackPixel (display.Handle, display.DefaultScreen);
+
+ // This logic will give us true rubber bands: (libsx, SANE_XOR)
+ //mask = foreground ^ background;
+ //XSetForeground(DisplayHandle, gc, 0xffffffff);
+ //XSetBackground(DisplayHandle, gc, background);
+ //XSetFunction(DisplayHandle, gc, GXxor);
+ //XSetPlaneMask(DisplayHandle, gc, mask);
+
+
+ gc = Xlib.XCreateGC (display.Handle, ClientWindow,
+ new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values);
+ uint foreground;
+ uint background;
+
+ Widget Widget;
+ Widget = Widget.FromHandle(Handle);
+
+ XColor xcolor = new XColor();
+
+ xcolor.red = (ushort)(Widget.ForeColor.R * 257);
+ xcolor.green = (ushort)(Widget.ForeColor.G * 257);
+ xcolor.blue = (ushort)(Widget.ForeColor.B * 257);
+ Xlib.XAllocColor (display.Handle, display.DefaultColormap, ref xcolor);
+ foreground = (uint)xcolor.pixel.ToInt32();
+
+ xcolor.red = (ushort)(Widget.BackColor.R * 257);
+ xcolor.green = (ushort)(Widget.BackColor.G * 257);
+ xcolor.blue = (ushort)(Widget.BackColor.B * 257);
+ Xlib.XAllocColor (display.Handle, display.DefaultColormap, ref xcolor);
+ background = (uint)xcolor.pixel.ToInt32();
+
+ uint mask = foreground ^ background;
+
+ Xlib.XSetForeground (display.Handle, gc, (UIntPtr)0xffffffff);
+ Xlib.XSetBackground (display.Handle, gc, (UIntPtr)background);
+ Xlib.XSetFunction (display.Handle, gc, GXFunction.GXxor);
+ Xlib.XSetPlaneMask (display.Handle, gc, (IntPtr)mask);
+
+ if ((rect.Width > 0) && (rect.Height > 0))
+ Xlib.XDrawRectangle (display.Handle, ClientWindow, gc, rect.Left, rect.Top, rect.Width, rect.Height);
+ else if (rect.Width > 0)
+ Xlib.XDrawLine (display.Handle, ClientWindow, gc, rect.X, rect.Y, rect.Right, rect.Y);
+ else
+ Xlib.XDrawLine (display.Handle, ClientWindow, gc, rect.X, rect.Y, rect.X, rect.Bottom);
+
+ Xlib.XFreeGC (display.Handle, gc);
+ }
+
+ private void WaitForMessage (Msg message)
+ {
+ MSG msg = new MSG ();
+
+ queue.DispatchIdle = false;
+
+ bool done = false;
+ do {
+ if (display.PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
+ if ((Msg)msg.message == Msg.WM_QUIT) {
+ // XXX this should live someplace else
+ XplatUI.PostQuitMessage (0);
+ done = true;
+ }
+ else {
+ if ((msg.hwnd == Handle) &&
+ ((Msg)msg.message == message || (Msg)msg.message == Msg.WM_DESTROY))
+ done = true;
+ display.TranslateMessage (ref msg);
+ display.DispatchMessage (ref msg);
+ }
+ }
+ } while (!done);
+
+ queue.DispatchIdle = true;
+ }
+
+ public void Map ()
+ {
+ // FIXME why do we set this here and also in the MapNotify event handling?
+ if (!mapped) {
+
+ Xlib.XMapWindow (display.Handle, WholeWindow);
+ Xlib.XMapWindow (display.Handle, ClientWindow);
+
+ mapped = true;
+
+ if (Widget.FromHandle(Handle) is Form)
+ WaitForMessage (Msg.WM_SHOWWINDOW);
+ }
+ }
+
+ public void Unmap ()
+ {
+ // FIXME why do we set this here and also in the UnmapNotify event handling?
+ if (mapped) {
+ Xlib.XUnmapWindow (display.Handle, ClientWindow);
+ Xlib.XUnmapWindow (display.Handle, WholeWindow);
+
+ mapped = false;
+
+ if (Widget.FromHandle(Handle) is Form)
+ WaitForMessage (Msg.WM_SHOWWINDOW);
+ }
+ }
+
+ public void PerformNCCalc ()
+ {
+ XplatUIWin32.NCCALCSIZE_PARAMS ncp;
+ IntPtr ptr;
+ Rectangle rect;
+
+ rect = DefaultClientRect;
+
+ 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 (ClientWindow, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr);
+ ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
+ Marshal.FreeHGlobal(ptr);
+
+ // FIXME - debug this with Menus
+
+ rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
+ ClientRect = rect;
+
+ if (Visible) {
+ if ((rect.Width < 1) || (rect.Height < 1))
+ Xlib.XMoveResizeWindow (display.Handle, ClientWindow, -5, -5, 1, 1);
+ else
+ Xlib.XMoveResizeWindow (display.Handle, ClientWindow, rect.X, rect.Y, rect.Width, rect.Height);
+ }
+
+ InvalidateNC ();
+ }
+
+ public void RequestNCRecalc ()
+ {
+ PerformNCCalc ();
+ display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ InvalidateNC ();
+ }
+
+ [MonoTODO]
+ public void RequestAdditionalWM_NCMessages (bool hover, bool leave)
+ {
+ // Missing messages won't crash anything so just don't generate them for the moment.
+ // throw new NotImplementedException( );
+ }
+
+ public void FrameExtents (out int left, out int top)
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Xlib.XGetWindowProperty (display.Handle, WholeWindow,
+ display.Atoms._NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false,
+ display.Atoms.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if (((long)nitems == 4) && (prop != IntPtr.Zero)) {
+ left = Marshal.ReadIntPtr(prop, 0).ToInt32();
+ //right = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
+ top = Marshal.ReadIntPtr(prop, IntPtr.Size * 2).ToInt32();
+ //bottom = Marshal.ReadIntPtr(prop, IntPtr.Size * 3).ToInt32();
+ } else {
+ left = 0;
+ top = 0;
+ }
+
+ if (prop != IntPtr.Zero) {
+ Xlib.XFree(prop);
+ }
+ }
+
+ static bool StyleSet (int s, WindowStyles ws)
+ {
+ return (s & (int)ws) == (int)ws;
+ }
+
+ static bool ExStyleSet (int ex, WindowExStyles exws)
+ {
+ return (ex & (int)exws) == (int)exws;
+ }
+
+ // XXX this should be a static method on Hwnd so other backends can use it
+ public static 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)
+ {
+
+ // Only MDI windows get caption_heights
+ caption_height = 0;
+ tool_caption_height = 19;
+ 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 (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) {
+ caption_height = 26;
+
+ if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
+ if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
+ title_style = TitleStyle.Tool;
+ else
+ title_style = TitleStyle.Normal;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ public void SetHwndStyles (CreateParams cp)
+ {
+ DeriveStyles(cp.Style, cp.ExStyle, out this.border_style, out this.border_static, out this.title_style, out this.caption_height, out this.tool_caption_height);
+ }
+
+ public void SetWMStyles (CreateParams cp)
+ {
+ MotifWmHints mwmHints;
+ MotifFunctions functions;
+ MotifDecorations decorations;
+ IntPtr[] atoms;
+ int atom_count;
+ Rectangle client_rect;
+
+ // Child windows don't need WM window styles
+ if (StyleSet (cp.Style, WindowStyles.WS_CHILDWINDOW))
+ return;
+
+ atoms = new IntPtr[8];
+ mwmHints = new MotifWmHints();
+ functions = 0;
+ decorations = 0;
+
+ mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
+ mwmHints.functions = (IntPtr)0;
+ mwmHints.decorations = (IntPtr)0;
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)
+ || !StyleSet (cp.Style, WindowStyles.WS_CAPTION | WindowStyles.WS_BORDER | WindowStyles.WS_DLGFRAME)) {
+ /* tool windows get no window manager
+ decorations, and neither do windows
+ which lack CAPTION/BORDER/DLGFRAME
+ styles.
+ */
+
+ /* just because the window doesn't get any decorations doesn't
+ mean we should disable the functions. for instance, without
+ MotifFunctions.Maximize, changing the windowstate to Maximized
+ is ignored by metacity. */
+ functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
+ }
+ else {
+ if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
+ functions |= MotifFunctions.Move;
+ decorations |= MotifDecorations.Title | MotifDecorations.Menu;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) {
+ functions |= MotifFunctions.Move | MotifFunctions.Resize;
+ decorations |= MotifDecorations.Border | MotifDecorations.ResizeH;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) {
+ functions |= MotifFunctions.Minimize;
+ decorations |= MotifDecorations.Minimize;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) {
+ functions |= MotifFunctions.Maximize;
+ decorations |= MotifDecorations.Maximize;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) {
+ functions |= MotifFunctions.Resize;
+ decorations |= MotifDecorations.ResizeH;
+ }
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
+ decorations |= MotifDecorations.Border;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) {
+ decorations |= MotifDecorations.Border;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) {
+ decorations |= MotifDecorations.Border;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) {
+ functions |= MotifFunctions.Close;
+ }
+ else {
+ functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close);
+ decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize);
+ if (cp.Caption == "") {
+ functions &= ~MotifFunctions.Move;
+ decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH);
+ }
+ }
+ }
+
+ if ((functions & MotifFunctions.Resize) == 0) {
+ fixed_size = true;
+ SetMinMax (new Rectangle(cp.X, cp.Y, cp.Width, cp.Height), new Size(cp.Width, cp.Height), new Size(cp.Width, cp.Height));
+ } else {
+ fixed_size = false;
+ }
+
+ mwmHints.functions = (IntPtr)functions;
+ mwmHints.decorations = (IntPtr)decorations;
+
+ FormWindowState current_state = GetWindowState ();
+ if (current_state == (FormWindowState)(-1))
+ current_state = FormWindowState.Normal;
+
+ client_rect = ClientRect;
+
+ atom_count = 0;
+
+ // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
+ // and get those windows in front of their parents
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
+ WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_UTILITY;
+
+ Form f = Widget.FromHandle(Handle) as Form;
+ if (f != null && !reparented) {
+ if (f.Owner != null && f.Owner.Handle != IntPtr.Zero) {
+ Hwnd owner_hwnd = Hwnd.ObjectFromHandle(f.Owner.Handle);
+ if (owner_hwnd != null)
+ Xlib.XSetTransientForHint (display.Handle, WholeWindow,
+ owner_hwnd.WholeWindow);
+ }
+ }
+ }
+
+ Xlib.XChangeProperty (display.Handle, WholeWindow,
+ display.Atoms._MOTIF_WM_HINTS, display.Atoms._MOTIF_WM_HINTS, 32,
+ PropertyMode.Replace, ref mwmHints, 5);
+
+ if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (parent != null) && (parent.WholeWindow != IntPtr.Zero)) {
+ WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL;
+ Xlib.XSetTransientForHint(display.Handle, WholeWindow, parent.WholeWindow);
+ } else if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_APPWINDOW)) {
+ /* this line keeps the window from showing up in gnome's taskbar */
+ atoms[atom_count++] = display.Atoms._NET_WM_STATE_SKIP_TASKBAR;
+ }
+ if ((client_rect.Width < 1) || (client_rect.Height < 1)) {
+ Xlib.XMoveResizeWindow (display.Handle, ClientWindow, -5, -5, 1, 1);
+ } else {
+ Xlib.XMoveResizeWindow (display.Handle, ClientWindow, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
+ }
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
+ atoms[atom_count++] = display.Atoms._NET_WM_STATE_SKIP_TASKBAR;
+
+ /* we need to add these atoms in the
+ * event we're maximized, since we're
+ * replacing the existing
+ * _NET_WM_STATE here. If we don't
+ * add them, future calls to
+ * GetWindowState will return Normal
+ * for a window which is maximized. */
+ if (current_state == FormWindowState.Maximized) {
+ atoms[atom_count++] = display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ;
+ atoms[atom_count++] = display.Atoms._NET_WM_STATE_MAXIMIZED_VERT;
+ }
+
+ Set_WM_STATE (atoms, atom_count);
+
+ atom_count = 0;
+ atoms[atom_count++] = display.Atoms.WM_DELETE_WINDOW;
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP))
+ atoms[atom_count++] = display.Atoms._NET_WM_CONTEXT_HELP;
+
+ Xlib.XSetWMProtocols (display.Handle, WholeWindow, atoms, atom_count);
+ }
+
+ public void ClientToScreen (ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+
+ Xlib.XTranslateCoordinates (display.Handle,
+ ClientWindow, display.RootWindow.Handle,
+ x, y, out dest_x_return, out dest_y_return, out child);
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ public void ScreenToClient (ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+
+ Xlib.XTranslateCoordinates (display.Handle,
+ display.RootWindow.Handle, ClientWindow,
+ x, y, out dest_x_return, out dest_y_return, out child);
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+
+ public void ScreenToMenu (ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+
+ Xlib.XTranslateCoordinates (display.Handle,
+ display.RootWindow.Handle, WholeWindow,
+ x, y, out dest_x_return, out dest_y_return, out child);
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ public void ScrollWindow (Rectangle area, int XAmount, int YAmount, bool with_children)
+ {
+ IntPtr gc;
+ XGCValues gc_values;
+
+ Rectangle r = Rectangle.Intersect (Invalid, area);
+ if (!r.IsEmpty) {
+ /* We have an invalid area in the window we're scrolling.
+ Adjust our stored invalid rectangle to to match the scrolled amount */
+
+ r.X += XAmount;
+ r.Y += YAmount;
+
+ if (r.X < 0) {
+ r.Width += r.X;
+ r.X =0;
+ }
+
+ if (r.Y < 0) {
+ r.Height += r.Y;
+ r.Y =0;
+ }
+
+ if (area.Contains (Invalid))
+ ClearInvalidArea();
+ AddInvalidArea(r);
+ }
+
+ gc_values = new XGCValues();
+
+ gc_values.graphics_exposures = false;
+ if (with_children)
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+
+ gc = Xlib.XCreateGC (display.Handle, ClientWindow, IntPtr.Zero, ref gc_values);
+
+ int src_x, src_y;
+ int dest_x, dest_y;
+ int width, height;
+
+ if (YAmount > 0) {
+ src_y = area.Y;
+ height = area.Height - YAmount;
+ dest_y = area.Y + YAmount;
+ }
+ else {
+ src_y = area.Y - YAmount;
+ height = area.Height + YAmount;
+ dest_y = area.Y;
+ }
+
+ if (XAmount > 0) {
+ src_x = area.X;
+ width = area.Width - XAmount;
+ dest_x = area.X + XAmount;
+ }
+ else {
+ src_x = area.X - XAmount;
+ width = area.Width + XAmount;
+ dest_x = area.X;
+ }
+
+ Xlib.XCopyArea (display.Handle, ClientWindow, ClientWindow, gc, src_x, src_y, width, height, dest_x, dest_y);
+
+ // Generate an expose for the area exposed by the horizontal scroll
+ // We don't use AddExpose since we're
+ if (XAmount > 0) {
+ AddExpose (true, area.X, area.Y, XAmount, area.Height);
+ } else if (XAmount < 0) {
+ AddExpose (true, XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
+ }
+
+ // Generate an expose for the area exposed by the vertical scroll
+ if (YAmount > 0) {
+ AddExpose (true, area.X, area.Y, area.Width, YAmount);
+ } else if (YAmount < 0) {
+ AddExpose (true, area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
+ }
+
+ Xlib.XFreeGC (display.Handle, gc);
+ }
+
+
+ public void SetBorderStyle (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);
+ }
+
+ BorderStyle = border_style;
+ RequestNCRecalc ();
+ }
+
+ // XXX this should probably be in Hwnd
+ public void SetClipRegion (Region region)
+ {
+ UserClip = region;
+ Invalidate (new Rectangle(0, 0, Width, Height), false);
+ }
+
+ // XXX this should probably be in Hwnd
+ public Region GetClipRegion ()
+ {
+ return UserClip;
+ }
+
+ public void SetMenu (Menu menu)
+ {
+ Menu = menu;
+
+ RequestNCRecalc ();
+ }
+
+ public void SetMinMax (Rectangle maximized, Size min, Size max)
+ {
+ XSizeHints hints;
+ IntPtr dummy;
+
+ hints = new XSizeHints();
+
+ Xlib.XGetWMNormalHints (display.Handle, WholeWindow, ref hints, out dummy);
+ if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
+ hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
+ hints.min_width = min.Width;
+ hints.min_height = min.Height;
+ }
+
+ if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
+ hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
+ hints.max_width = max.Width;
+ hints.max_height = max.Height;
+ }
+
+ if (hints.flags != IntPtr.Zero)
+ Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints);
+
+ if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
+ hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
+ hints.x = maximized.X;
+ hints.y = maximized.Y;
+ hints.width = maximized.Width;
+ hints.height = maximized.Height;
+
+ // Metacity does not seem to follow this constraint for maximized (zoomed) windows
+ Xlib.XSetZoomHints (display.Handle, WholeWindow, ref hints);
+ }
+ }
+
+ // For WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN
+ // WM_CREATE and WM_DESTROY causes
+ public void SendParentNotify (Msg cause, int x, int y)
+ {
+ if (Handle == IntPtr.Zero)
+ return;
+
+ if (ExStyleSet ((int) initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY))
+ return;
+
+ if (Parent == null || Parent.Handle == IntPtr.Zero)
+ return;
+
+ if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) {
+ display.SendMessage(Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), Handle);
+ } else {
+ display.SendMessage(Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), Widget.MakeParam(x, y));
+ }
+
+ ((X11Hwnd)Parent).SendParentNotify (cause, x, y);
+ }
+
+
+ public void GetPosition (bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height)
+ {
+ x = X;
+ y = Y;
+ width = Width;
+ height = Height;
+
+ PerformNCCalc ();
+
+ client_width = ClientRect.Width;
+ client_height = ClientRect.Height;
+ }
+
+ public void SetPosition (int x, int y, int width, int height)
+ {
+ // 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 (zero_sized && width > 0 && height > 0) {
+ if (Visible) {
+ Map ();
+ }
+ zero_sized = false;
+ }
+
+ if ((width < 1) || (height < 1)) {
+ zero_sized = true;
+ Unmap ();
+ }
+
+ // Save a server roundtrip (and prevent a feedback loop)
+ if ((X == x) && (Y == y) &&
+ (Width == width) && (Height == height)) {
+ return;
+ }
+
+ if (!zero_sized) {
+ //Hack?
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+
+ if (fixed_size) {
+ SetMinMax (Rectangle.Empty, new Size(width, height), new Size(width, height));
+ }
+
+ Xlib.XMoveResizeWindow (display.Handle, WholeWindow, x, y, width, height);
+ PerformNCCalc ();
+ }
+
+ // Update our position/size immediately, so
+ // that future calls to SetWindowPos aren't
+ // kept from calling XMoveResizeWindow (by the
+ // "Save a server roundtrip" block above).
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ ClientRect = Rectangle.Empty;
+ }
+
+ public void SetParent (X11Hwnd parent_hwnd)
+ {
+ Parent = parent_hwnd;
+
+#if DriverDebug || DriverDebugParent
+ Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(Handle), XplatUI.Window(hwnd.parent != null ? parent_hwnd.Handle : IntPtr.Zero));
+#endif
+ Xlib.XReparentWindow (display.Handle, WholeWindow,
+ parent_hwnd == null ? display.FosterParent.ClientWindow : parent_hwnd.ClientWindow,
+ X, Y);
+ }
+
+ public void SetCursorPos (int x, int y)
+ {
+ Xlib.XWarpPointer (display.Handle, IntPtr.Zero, ClientWindow, 0, 0, 0, 0, x, y);
+ }
+
+ public bool SetTopmost (bool enabled)
+ {
+ if (enabled) {
+ int[] atoms = new int[8];
+ atoms[0] = display.Atoms._NET_WM_STATE_ABOVE.ToInt32();
+ Xlib.XChangeProperty (display.Handle, WholeWindow, display.Atoms._NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
+ }
+ else {
+ Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms._NET_WM_STATE);
+ }
+
+ return true;
+ }
+
+ public bool SetOwner (X11Hwnd owner)
+ {
+ if (owner != null) {
+ WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL;
+ if (owner != null)
+ Xlib.XSetTransientForHint (display.Handle, WholeWindow, owner.WholeWindow);
+ else
+ Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.WholeWindow);
+ }
+ else {
+ Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms.XA_WM_TRANSIENT_FOR);
+ }
+
+ return true;
+ }
+
+ public bool SetVisible (bool visible, bool activate)
+ {
+ Visible = visible;
+
+ if (visible) {
+ Map ();
+
+ if (Widget.FromHandle (Handle) is Form) {
+ FormWindowState s;
+
+ s = ((Form)Widget.FromHandle(Handle)).WindowState;
+
+ switch(s) {
+ case FormWindowState.Minimized: SetWindowState (FormWindowState.Minimized); break;
+ case FormWindowState.Maximized: SetWindowState (FormWindowState.Maximized); break;
+ }
+
+ }
+
+ display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ }
+ else {
+ Unmap ();
+ }
+
+ return true;
+ }
+
+ public FormWindowState GetWindowState ()
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr atom;
+ int maximized;
+ bool minimized;
+ XWindowAttributes attributes;
+
+ maximized = 0;
+ minimized = false;
+ Xlib.XGetWindowProperty (display.Handle, WholeWindow,
+ display.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr (256), false,
+ display.Atoms.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
+ for (int i = 0; i < (long)nitems; i++) {
+ // XXX 64 bit clean?
+ atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
+ if ((atom == display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ) || (atom == display.Atoms._NET_WM_STATE_MAXIMIZED_VERT))
+ maximized++;
+ else if (atom == display.Atoms._NET_WM_STATE_HIDDEN)
+ minimized = true;
+ }
+ Xlib.XFree(prop);
+ }
+
+ if (minimized)
+ return FormWindowState.Minimized;
+ else if (maximized == 2)
+ return FormWindowState.Maximized;
+
+ attributes = new XWindowAttributes();
+ Xlib.XGetWindowAttributes (display.Handle, ClientWindow, ref attributes);
+ if (attributes.map_state == MapState.IsUnmapped)
+ return (FormWindowState)(-1);
+
+ return FormWindowState.Normal;
+ }
+
+
+ public void SetWindowState (FormWindowState state)
+ {
+ FormWindowState current_state;
+
+ current_state = GetWindowState ();
+
+ if (current_state == state)
+ return;
+
+ switch (state) {
+ case FormWindowState.Normal:
+ if (current_state == FormWindowState.Minimized)
+ Map ();
+ else if (current_state == FormWindowState.Maximized)
+ display.SendNetWMMessage (WholeWindow,
+ display.Atoms._NET_WM_STATE, (IntPtr)2 /* toggle */,
+ display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ,
+ display.Atoms._NET_WM_STATE_MAXIMIZED_VERT);
+ Activate ();
+ break;
+
+ case FormWindowState.Minimized:
+ if (current_state == FormWindowState.Maximized)
+ display.SendNetWMMessage (WholeWindow,
+ display.Atoms._NET_WM_STATE, (IntPtr)2 /* toggle */,
+ display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ,
+ display.Atoms._NET_WM_STATE_MAXIMIZED_VERT);
+
+ // FIXME multiscreen support
+ Xlib.XIconifyWindow (display.Handle, WholeWindow, display.DefaultScreen);
+ break;
+
+ case FormWindowState.Maximized:
+ if (current_state == FormWindowState.Minimized)
+ Map ();
+
+ display.SendNetWMMessage (WholeWindow,
+ display.Atoms._NET_WM_STATE, (IntPtr)1 /* Add */,
+ display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ,
+ display.Atoms._NET_WM_STATE_MAXIMIZED_VERT);
+ Activate ();
+ break;
+ }
+ }
+
+ public bool SetZOrder (X11Hwnd after_hwnd, bool top, bool bottom)
+ {
+ if (top) {
+ Xlib.XRaiseWindow (display.Handle, WholeWindow);
+ return true;
+ }
+ else if (bottom) {
+ Xlib.XLowerWindow (display.Handle, WholeWindow);
+ return true;
+ }
+ else {
+ if (after_hwnd == null) {
+ Update_USER_TIME ();
+ Xlib.XRaiseWindow (display.Handle, WholeWindow);
+ display.SendNetWMMessage (WholeWindow, display.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
+ return true;
+ }
+
+ XWindowChanges values = new XWindowChanges();
+ values.sibling = after_hwnd.WholeWindow;
+ values.stack_mode = StackMode.Below;
+
+ Xlib.XConfigureWindow (display.Handle, WholeWindow, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
+ }
+ return false;
+ }
+
+ public X11Display Display {
+ get { return display; }
+ }
+
+ public string Text {
+ get { return text; }
+ set {
+ if (value == null)
+ value = "";
+
+ if (value == text)
+ return;
+
+ text = value;
+
+ Xlib.XChangeProperty(display.Handle, WholeWindow,
+ display.Atoms._NET_WM_NAME, display.Atoms.UNICODETEXT, 8,
+ PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
+
+ // XXX this has problems with UTF8.
+ // we need to either use the actual
+ // text if it's latin-1, or convert it
+ // to compound text if it's in a
+ // different charset.
+ Xlib.XStoreName(display.Handle, WholeWindow, text);
+ }
+ }
+
+ public bool GetText (out string text)
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Xlib.XGetWindowProperty (display.Handle, WholeWindow,
+ display.Atoms._NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
+ display.Atoms.UNICODETEXT, out actual_atom, out actual_format,
+ out nitems, out bytes_after, ref prop);
+
+ if ((long)nitems > 0 && prop != IntPtr.Zero) {
+ text = Marshal.PtrToStringUni (prop, (int)nitems);
+ Xlib.XFree (prop);
+ return true;
+ }
+ else {
+ // fallback on the non-_NET property
+ IntPtr textptr;
+
+ textptr = IntPtr.Zero;
+
+ Xlib.XFetchName (display.Handle, WholeWindow, ref textptr);
+ if (textptr != IntPtr.Zero) {
+ text = Marshal.PtrToStringAnsi(textptr);
+ Xlib.XFree(textptr);
+ return true;
+ } else {
+ text = "";
+ return false;
+ }
+ }
+ }
+
+ public IntPtr WINDOW_TYPE {
+ get {
+ if (refetch_window_type) {
+ window_type = GetAtomListProperty (display.Atoms._NET_WM_WINDOW_TYPE);
+ refetch_window_type = false;
+ }
+
+ return window_type.Length > 0 ? window_type[0] : IntPtr.Zero;
+ }
+ set {
+ Set_WINDOW_TYPE (new IntPtr[] {value}, 1);
+ }
+ }
+
+ public void Set_WINDOW_TYPE (IntPtr[] value, int count)
+ {
+ if (refetch_window_type) {
+ window_type = GetAtomListProperty (display.Atoms._NET_WM_WINDOW_TYPE);
+ refetch_window_type = false;
+ }
+
+ if (ArrayDifferent (window_type, value)) {
+ window_type = value;
+ Xlib.XChangeProperty (display.Handle, WholeWindow,
+ display.Atoms._NET_WM_WINDOW_TYPE, display.Atoms.XA_ATOM, 32,
+ PropertyMode.Replace, window_type, window_type.Length);
+ }
+ }
+
+ public void Set_WM_STATE (IntPtr[] value, int count)
+ {
+ if (ArrayDifferent (wm_state, value)) {
+ wm_state = value;
+ Xlib.XChangeProperty (display.Handle, WholeWindow,
+ display.Atoms._NET_WM_STATE, display.Atoms.XA_ATOM, 32,
+ PropertyMode.Replace, wm_state, wm_state.Length);
+ }
+ }
+
+ public void Update_USER_TIME ()
+ {
+ int[] args;
+
+ args = new int[2];
+ args[0] = display.CurrentTimestamp;
+ Xlib.XChangeProperty (display.Handle, WholeWindow,
+ display.Atoms._NET_WM_USER_TIME, display.Atoms.XA_CARDINAL, 32,
+ PropertyMode.Replace, args, 1);
+ }
+
+ public IntPtr[] GetAtomListProperty (IntPtr atom)
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Xlib.XGetWindowProperty (display.Handle, WholeWindow,
+ atom, IntPtr.Zero, new IntPtr (Int32.MaxValue), false,
+ display.Atoms.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if (actual_atom != display.Atoms.XA_ATOM ||
+ (long)nitems == 0 ||
+ prop == IntPtr.Zero) {
+ return new IntPtr[0];
+ }
+
+ IntPtr[] values = new IntPtr[(long)nitems];
+ int ofs = 0;
+
+ for (int i = 0; i < values.Length; i ++) {
+ values[i] = Marshal.ReadIntPtr (prop, ofs); ofs += IntPtr.Size;
+ }
+
+ Xlib.XFree (prop);
+
+ return values;
+ }
+
+ bool ArrayDifferent (IntPtr[] a, IntPtr[] b)
+ {
+ if (a.Length != b.Length)
+ return true;
+
+ for (int i = 0; i < a.Length; i ++) {
+ if (a[i] != b[i])
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/source/ShiftUI/Internal/X11Keyboard.cs b/source/ShiftUI/Internal/X11Keyboard.cs
new file mode 100644
index 0000000..70a6c03
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Keyboard.cs
@@ -0,0 +1,1478 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+//
+//
+
+
+//
+// TODO:
+// - dead chars are not translated properly
+// - There is a lot of potential for optimmization in here
+//
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Drawing;
+using System.Text;
+using System.Globalization;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI {
+
+ public enum XLookupStatus
+ {
+ XBufferOverflow = -1,
+ XLookupNone = 1,
+ XLookupChars = 2,
+ XLookupKeySym = 3,
+ XLookupBoth = 4
+ }
+
+ internal class X11Keyboard : IDisposable {
+ internal static object XlibLock;
+
+ private IntPtr display;
+ private IntPtr client_window;
+ private IntPtr xim;
+ private Hashtable xic_table = new Hashtable ();
+ private XIMPositionContext positionContext;
+ private XIMCallbackContext callbackContext;
+ private XIMProperties ximStyle;
+ private EventMask xic_event_mask = EventMask.NoEventMask;
+ private StringBuilder lookup_buffer;
+ private byte [] lookup_byte_buffer = new byte [100];
+ private int min_keycode, max_keycode, keysyms_per_keycode, syms;
+ private int [] keyc2vkey = new int [256];
+ private int [] keyc2scan = new int [256];
+ private byte [] key_state_table = new byte [256];
+ private int lcid;
+ private bool num_state, cap_state;
+ private bool initialized;
+ private bool menu_state = false;
+ private Encoding encoding;
+
+ private int NumLockMask;
+ private int AltGrMask;
+
+ public X11Keyboard (IntPtr display, IntPtr clientWindow)
+ {
+ this.display = display;
+ lookup_buffer = new StringBuilder (24);
+ EnsureLayoutInitialized ();
+ }
+
+ private Encoding AnsiEncoding
+ {
+ get
+ {
+ if (encoding == null)
+ encoding = Encoding.GetEncoding(new CultureInfo(lcid).TextInfo.ANSICodePage);
+ return encoding;
+ }
+ }
+
+ public IntPtr ClientWindow {
+ get { return client_window; }
+ }
+
+ void IDisposable.Dispose ()
+ {
+ if (xim != IntPtr.Zero) {
+ foreach (IntPtr xic in xic_table.Values)
+ XDestroyIC (xic);
+ xic_table.Clear ();
+
+ XCloseIM (xim);
+ xim = IntPtr.Zero;
+ }
+ }
+
+ public void DestroyICForWindow (IntPtr window)
+ {
+ IntPtr xic = GetXic (window);
+ if (xic != IntPtr.Zero) {
+ xic_table.Remove ((long) window);
+ XDestroyIC (xic);
+ }
+ }
+
+ public void EnsureLayoutInitialized ()
+ {
+ if (initialized)
+ return;
+
+ KeyboardLayouts layouts = new KeyboardLayouts ();
+ KeyboardLayout layout = DetectLayout (layouts);
+ lcid = layout.Lcid;
+ CreateConversionArray (layouts, layout);
+ SetupXIM ();
+ initialized = true;
+ }
+
+ private void SetupXIM ()
+ {
+ xim = IntPtr.Zero;
+
+ if (!XSupportsLocale ()) {
+ Console.Error.WriteLine ("X does not support your locale");
+ return;
+ }
+
+ if (!XSetLocaleModifiers (String.Empty)) {
+ Console.Error.WriteLine ("Could not set X locale modifiers");
+ return;
+ }
+
+ if (Environment.GetEnvironmentVariable (ENV_NAME_XIM_STYLE) == "disabled") {
+ return;
+ }
+
+ xim = XOpenIM (display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ if (xim == IntPtr.Zero)
+ Console.Error.WriteLine ("Could not get XIM");
+
+ initialized = true;
+ }
+
+ void CreateXicForWindow (IntPtr window)
+ {
+ IntPtr xic = CreateXic (window, xim);
+ xic_table [(long) window] = xic;
+ if (xic == IntPtr.Zero)
+ Console.Error.WriteLine ("Could not get XIC");
+ else {
+ if (XGetICValues (xic, "filterEvents", out xic_event_mask, IntPtr.Zero) != null)
+ Console.Error.WriteLine ("Could not get XIC values");
+ EventMask mask = EventMask.ExposureMask | EventMask.KeyPressMask | EventMask.FocusChangeMask;
+ if ((xic_event_mask | mask) == xic_event_mask) {
+ xic_event_mask |= mask;
+ lock (XlibLock) {
+ XplatUIX11.XSelectInput(display, window, new IntPtr ((int) xic_event_mask));
+ }
+ }
+ }
+ }
+
+ public EventMask KeyEventMask {
+ get { return xic_event_mask; }
+ }
+
+ public Keys ModifierKeys {
+ get {
+ Keys keys = Keys.None;
+ if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0)
+ keys |= Keys.Shift;
+ if ((key_state_table [(int) VirtualKeys.VK_CONTROL ] & 0x80) != 0)
+ keys |= Keys.Widget;
+ if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0)
+ keys |= Keys.Alt;
+ return keys;
+ }
+ }
+
+ private IntPtr GetXic (IntPtr window)
+ {
+ if (xim != IntPtr.Zero && xic_table.ContainsKey ((long) window))
+ return (IntPtr) xic_table [(long) window];
+ else
+ return IntPtr.Zero;
+ }
+
+ private bool FilterKey (XEvent e, int vkey)
+ {
+ if (XplatUI.key_filters.Count == 0)
+ return false;
+ XLookupStatus status;
+ XKeySym ks;
+ KeyFilterData data;
+ data.Down = (e.type == XEventName.KeyPress);
+ data.ModifierKeys = ModifierKeys;
+ LookupString (ref e, 0, out ks, out status);
+ data.keysym = (int)ks;
+ data.keycode = e.KeyEvent.keycode;
+ data.str = lookup_buffer.ToString (0, lookup_buffer.Length);
+ return XplatUI.FilterKey (data);
+ }
+
+ public void FocusIn (IntPtr window)
+ {
+ this.client_window = window;
+ if (xim == IntPtr.Zero)
+ return;
+
+ if (!xic_table.ContainsKey ((long) window))
+ CreateXicForWindow (window);
+ IntPtr xic = GetXic (window);
+ if (xic != IntPtr.Zero)
+ XSetICFocus (xic);
+ }
+
+ private bool have_Xutf8ResetIC = true;
+
+ public void FocusOut (IntPtr window)
+ {
+ this.client_window = IntPtr.Zero;
+ if (xim == IntPtr.Zero)
+ return;
+
+ IntPtr xic = GetXic (window);
+ if (xic != IntPtr.Zero) {
+ if (have_Xutf8ResetIC) {
+ try {
+ Xutf8ResetIC (xic);
+ } catch (EntryPointNotFoundException) {
+ have_Xutf8ResetIC = false;
+ }
+ }
+ XUnsetICFocus (xic);
+ }
+ }
+
+ public bool ResetKeyState(IntPtr hwnd, ref MSG msg) {
+ // FIXME - keep defining events/msg and return true until we've 'restored' all
+ // pending keypresses
+ if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) {
+ key_state_table [(int) VirtualKeys.VK_SHIFT] &= unchecked((byte)~0x80);
+ }
+
+ if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
+ key_state_table [(int) VirtualKeys.VK_CONTROL] &= unchecked((byte)~0x80);
+ }
+
+ if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0) {
+ key_state_table [(int) VirtualKeys.VK_MENU] &= unchecked((byte)~0x80);
+ }
+ return false;
+ }
+
+ // Almost identical to UpdateKeyState() but does not call LookupString().
+ // The actual purpose is to handle shift state correctly.
+ public void PreFilter (XEvent xevent)
+ {
+ // It is still possible that some keyboards could have some shift
+ // keys outside this range, but let's think about such cases only
+ // if it actually happened.
+ if (xevent.KeyEvent.keycode >= keyc2vkey.Length)
+ return;
+
+ int vkey = keyc2vkey [xevent.KeyEvent.keycode];
+
+ switch (xevent.type) {
+ case XEventName.KeyRelease:
+ key_state_table [vkey & 0xff] &= unchecked ((byte) ~0x80);
+ break;
+ case XEventName.KeyPress:
+ if ((key_state_table [vkey & 0xff] & 0x80) == 0) {
+ key_state_table [vkey & 0xff] ^= 0x01;
+ }
+ key_state_table [vkey & 0xff] |= 0x80;
+ break;
+ }
+ }
+
+ public void KeyEvent (IntPtr hwnd, XEvent xevent, ref MSG msg)
+ {
+ XKeySym keysym;
+ int ascii_chars;
+
+ XLookupStatus status;
+ ascii_chars = LookupString (ref xevent, 24, out keysym, out status);
+
+ if (((int) keysym >= (int) MiscKeys.XK_ISO_Lock &&
+ (int) keysym <= (int) MiscKeys.XK_ISO_Last_Group_Lock) ||
+ (int) keysym == (int) MiscKeys.XK_Mode_switch) {
+ UpdateKeyState (xevent);
+ return;
+ }
+
+ if ((xevent.KeyEvent.keycode >> 8) == 0x10)
+ xevent.KeyEvent.keycode = xevent.KeyEvent.keycode & 0xFF;
+
+ int event_time = (int)xevent.KeyEvent.time;
+
+ if (status == XLookupStatus.XLookupChars) {
+ // do not ignore those inputs. They are mostly from XIM.
+ msg = SendImeComposition (lookup_buffer.ToString (0, lookup_buffer.Length));
+ msg.hwnd = hwnd;
+ return;
+ }
+
+ AltGrMask = xevent.KeyEvent.state & (0x6000 | (int) KeyMasks.ModMasks);
+ int vkey = EventToVkey (xevent);
+ if (vkey == 0 && ascii_chars != 0) {
+ vkey = (int) VirtualKeys.VK_NONAME;
+ }
+
+ if (FilterKey (xevent, vkey))
+ return;
+ switch ((VirtualKeys) (vkey & 0xFF)) {
+ case VirtualKeys.VK_NUMLOCK:
+ GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.KeyEvent.keycode, xevent.type, event_time);
+ break;
+ case VirtualKeys.VK_CAPITAL:
+ GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.KeyEvent.keycode, xevent.type, event_time);
+ break;
+ default:
+ if (((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) == 0) != ((xevent.KeyEvent.state & NumLockMask) == 0)) {
+ GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.KeyEvent.keycode, XEventName.KeyPress, event_time);
+ GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.KeyEvent.keycode, XEventName.KeyRelease, event_time);
+ }
+
+ if (((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) == 0) != ((xevent.KeyEvent.state & (int) KeyMasks.LockMask) == 0)) {
+ GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.KeyEvent.keycode, XEventName.KeyPress, event_time);
+ GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.KeyEvent.keycode, XEventName.KeyRelease, event_time);
+ }
+
+ num_state = false;
+ cap_state = false;
+
+ int bscan = (keyc2scan [xevent.KeyEvent.keycode] & 0xFF);
+ KeybdEventFlags dw_flags = KeybdEventFlags.None;
+ if (xevent.type == XEventName.KeyRelease)
+ dw_flags |= KeybdEventFlags.KeyUp;
+ if ((vkey & 0x100) != 0)
+ dw_flags |= KeybdEventFlags.ExtendedKey;
+ msg = SendKeyboardInput ((VirtualKeys) (vkey & 0xFF), bscan, xevent.KeyEvent.keycode, dw_flags, event_time);
+ msg.hwnd = hwnd;
+ break;
+ }
+ }
+
+ public bool TranslateMessage (ref MSG msg)
+ {
+ bool res = false;
+
+ if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
+ res = true;
+
+ if (msg.message == Msg.WM_SYSKEYUP && msg.wParam == (IntPtr) 0x12 && menu_state) {
+ msg.message = Msg.WM_KEYUP;
+ menu_state = false;
+ }
+
+ if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN)
+ return res;
+
+ if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 && msg.wParam != (IntPtr) 0x12)
+ menu_state = true;
+
+ EnsureLayoutInitialized ();
+
+ string buffer;
+ Msg message;
+ int tu = ToUnicode ((int) msg.wParam, Widget.HighOrder ((int) msg.lParam), out buffer);
+ switch (tu) {
+ case 1:
+ message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR);
+ XplatUI.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
+ break;
+ case -1:
+ message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_DEADCHAR : Msg.WM_SYSDEADCHAR);
+ XplatUI.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
+ return true;
+ }
+
+ return res;
+ }
+
+ public int ToKeycode(int key)
+ {
+ int keycode = 0;
+
+ if (nonchar_vkey_key[key] > 0)
+ keycode = XKeysymToKeycode (display, nonchar_vkey_key[key]);
+
+ if (keycode == 0)
+ keycode = XKeysymToKeycode (display, key);
+
+ return keycode;
+ }
+
+ public int ToUnicode (int vkey, int scan, out string buffer)
+ {
+ if ((scan & 0x8000) != 0) {
+ buffer = String.Empty;
+ return 0;
+ }
+
+ XEvent e = new XEvent ();
+ e.AnyEvent.type = XEventName.KeyPress;
+ e.KeyEvent.display = display;
+ e.KeyEvent.keycode = 0;
+ e.KeyEvent.state = 0;
+
+ if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) {
+ e.KeyEvent.state |= (int) KeyMasks.ShiftMask;
+ }
+
+ if ((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) != 0) {
+ e.KeyEvent.state |= (int) KeyMasks.LockMask;
+ }
+
+ if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
+ e.KeyEvent.state |= (int) KeyMasks.ControlMask;
+ }
+
+ if ((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) != 0) {
+ e.KeyEvent.state |= NumLockMask;
+ }
+
+ e.KeyEvent.state |= AltGrMask;
+
+ for (int keyc = min_keycode; (keyc <= max_keycode) && (e.KeyEvent.keycode == 0); keyc++) {
+ // find keycode that could have generated this vkey
+ if ((keyc2vkey [keyc] & 0xFF) == vkey) {
+ // filter extended bit because it is not known
+ e.KeyEvent.keycode = keyc;
+ if ((EventToVkey (e) & 0xFF) != vkey) {
+ // Wrong one (ex: because of num,lock state)
+ e.KeyEvent.keycode = 0;
+ }
+ }
+ }
+
+ if ((vkey >= (int) VirtualKeys.VK_NUMPAD0) && (vkey <= (int) VirtualKeys.VK_NUMPAD9))
+ e.KeyEvent.keycode = XKeysymToKeycode (display, vkey - (int) VirtualKeys.VK_NUMPAD0 + (int) KeypadKeys.XK_KP_0);
+
+ if (vkey == (int) VirtualKeys.VK_DECIMAL)
+ e.KeyEvent.keycode = XKeysymToKeycode (display, (int) KeypadKeys.XK_KP_Decimal);
+
+ if (vkey == (int) VirtualKeys.VK_SEPARATOR)
+ e.KeyEvent.keycode = XKeysymToKeycode(display, (int) KeypadKeys.XK_KP_Separator);
+
+ if (e.KeyEvent.keycode == 0 && vkey != (int) VirtualKeys.VK_NONAME) {
+ // And I couldn't find the keycode so i returned the vkey and was like whatever
+ Console.Error.WriteLine ("unknown virtual key {0:X}", vkey);
+ buffer = String.Empty;
+ return vkey;
+ }
+
+ XKeySym t;
+ XLookupStatus status;
+ int res = LookupString (ref e, 24, out t, out status);
+ int keysym = (int) t;
+
+ buffer = String.Empty;
+ if (res == 0) {
+ int dead_char = MapDeadKeySym (keysym);
+ if (dead_char != 0) {
+ byte [] bytes = new byte [1];
+ bytes [0] = (byte) dead_char;
+ buffer = new string (AnsiEncoding.GetChars (bytes));
+ res = -1;
+ }
+ } else {
+ // Shift + arrow, shift + home, ....
+ // X returns a char for it, but windows doesn't
+ if (((e.KeyEvent.state & NumLockMask) == 0) && ((e.KeyEvent.state & (int) KeyMasks.ShiftMask) != 0) &&
+ (keysym >= (int) KeypadKeys.XK_KP_0) && (keysym <= (int) KeypadKeys.XK_KP_9)) {
+ buffer = String.Empty;
+ res = 0;
+ }
+
+ // CTRL + number, X returns chars, windows does not
+ if ((e.KeyEvent.state & (int) KeyMasks.ControlMask) != 0) {
+ if (((keysym >= 33) && (keysym < 'A')) || ((keysym > 'Z') && (keysym < 'a'))) {
+ buffer = String.Empty;
+ res = 0;
+ }
+ }
+
+ // X returns a char for delete key on extended keyboards, windows does not
+ if (keysym == (int) TtyKeys.XK_Delete) {
+ buffer = String.Empty;
+ res = 0;
+ }
+
+ if (keysym == (int) TtyKeys.XK_BackSpace && (key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
+ buffer = new string (new char [] { (char) 127 });
+
+ return 1;
+ }
+
+ // For some special chars, such backspace and enter, looking up for a string
+ // can randomly fail to properly fill the buffer (either marshaling or X11), so we use
+ // the keysysm value to fill the gap
+ if (keysym == (int) XKeySym.XK_BackSpace) {
+ buffer = new string (new char [] { (char) 8 });
+ return 1;
+ }
+ if (keysym == (int) XKeySym.XK_Return) {
+ buffer = new string (new char [] { (char)13 });
+ return 1;
+ }
+
+ if (res != 0) {
+ buffer = lookup_buffer.ToString ();
+ res = buffer.Length;
+ }
+ }
+
+ return res;
+ }
+
+ string stored_keyevent_string;
+
+ internal string GetCompositionString ()
+ {
+ return stored_keyevent_string;
+ }
+
+ private MSG SendImeComposition (string s)
+ {
+ MSG msg = new MSG ();
+ msg.message = Msg.WM_IME_COMPOSITION;
+ msg.refobject = s;
+ stored_keyevent_string = s;
+ return msg;
+ }
+
+ private MSG SendKeyboardInput (VirtualKeys vkey, int scan, int keycode, KeybdEventFlags dw_flags, int time)
+ {
+ Msg message;
+
+ if ((dw_flags & KeybdEventFlags.KeyUp) != 0) {
+ bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
+ ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
+ key_state_table [(int) vkey] &= unchecked ((byte) ~0x80);
+ message = (sys_key ? Msg.WM_SYSKEYUP : Msg.WM_KEYUP);
+ } else {
+ if ((key_state_table [(int) vkey] & 0x80) == 0) {
+ key_state_table [(int) vkey] ^= 0x01;
+ }
+ key_state_table [(int) vkey] |= 0x80;
+ bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
+ ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
+ message = (sys_key ? Msg.WM_SYSKEYDOWN : Msg.WM_KEYDOWN);
+ }
+
+ MSG msg = new MSG ();
+ msg.message = message;
+ msg.wParam = (IntPtr) vkey;
+ msg.lParam = GenerateLParam (msg, keycode);
+ return msg;
+ }
+
+ private IntPtr GenerateLParam (MSG m, int keyCode)
+ {
+ // http://msdn.microsoft.com/en-us/library/ms646267(VS.85).aspx
+ //
+ byte flags = 0;
+
+ if (m.message == Msg.WM_SYSKEYUP || m.message == Msg.WM_KEYUP)
+ flags |= 0x80; // transition state flag = 1
+
+ flags |= 0x40; // previous key state flag = 1
+
+ if ((key_state_table [(int) VirtualKeys.VK_RMENU] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_LMENU] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0)
+ flags |= 0x20; // context code flag = 1
+
+ if ((key_state_table [(int) VirtualKeys.VK_INSERT] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_DELETE] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_HOME] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_END] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_UP] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_DOWN] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_LEFT] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_RIGHT] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_PRINT] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_RETURN] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_DIVIDE] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_PRIOR] & 0x80) != 0 ||
+ (key_state_table [(int) VirtualKeys.VK_NEXT] & 0x80) != 0)
+ flags |= 0x01; // extended key flag = 1
+
+ int lparam = ((((int)flags) & 0x000000FF) << 3*8); // message flags
+ lparam |= ((keyCode & 0x000000FF) << 2*8); // scan code
+ lparam |= 0x00000001; // repeat count = 1
+
+ return (IntPtr)lparam;
+ }
+
+ private void GenerateMessage (VirtualKeys vkey, int scan, int key_code, XEventName type, int event_time)
+ {
+ bool state = (vkey == VirtualKeys.VK_NUMLOCK ? num_state : cap_state);
+ KeybdEventFlags up, down;
+
+ if (state) {
+ // The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
+ // don't treat it. It's from the same key press. Then the state goes to ON.
+ // And from there, a 'release' event will switch off the toggle key.
+ SetState (vkey, false);
+ } else {
+ down = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey : KeybdEventFlags.None);
+ up = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey :
+ KeybdEventFlags.None) | KeybdEventFlags.KeyUp;
+ if ((key_state_table [(int) vkey] & 0x1) != 0) { // it was on
+ if (type != XEventName.KeyPress) {
+ SendKeyboardInput (vkey, scan, key_code, down, event_time);
+ SendKeyboardInput (vkey, scan, key_code, up, event_time);
+ SetState (vkey, false);
+ key_state_table [(int) vkey] &= unchecked ((byte) ~0x01);
+ }
+ } else {
+ if (type == XEventName.KeyPress) {
+ SendKeyboardInput (vkey, scan, key_code, down, event_time);
+ SendKeyboardInput (vkey, scan, key_code, up, event_time);
+ SetState (vkey, true);
+ key_state_table [(int) vkey] |= 0x01;
+ }
+ }
+ }
+ }
+
+ private void UpdateKeyState (XEvent xevent)
+ {
+ int vkey = EventToVkey (xevent);
+
+ switch (xevent.type) {
+ case XEventName.KeyRelease:
+ key_state_table [vkey & 0xff] &= unchecked ((byte) ~0x80);
+ break;
+ case XEventName.KeyPress:
+ if ((key_state_table [vkey & 0xff] & 0x80) == 0) {
+ key_state_table [vkey & 0xff] ^= 0x01;
+ }
+ key_state_table [vkey & 0xff] |= 0x80;
+ break;
+ }
+ }
+
+ private void SetState (VirtualKeys key, bool state)
+ {
+ if (VirtualKeys.VK_NUMLOCK == key)
+ num_state = state;
+ else
+ cap_state = state;
+ }
+
+ public int EventToVkey (XEvent e)
+ {
+ XLookupStatus status;
+ XKeySym ks;
+
+ LookupString (ref e, 0, out ks, out status);
+ int keysym = (int) ks;
+
+ if (((e.KeyEvent.state & NumLockMask) != 0) &&
+ (keysym == (int)KeypadKeys.XK_KP_Separator || keysym == (int)KeypadKeys.XK_KP_Decimal ||
+ (keysym >= (int)KeypadKeys.XK_KP_0 && keysym <= (int)KeypadKeys.XK_KP_9))) {
+ // Only the Keypad keys 0-9 and . send different keysyms
+ // depending on the NumLock state
+ return nonchar_key_vkey [keysym & 0xFF];
+ }
+
+ return keyc2vkey [e.KeyEvent.keycode];
+ }
+
+ private void CreateConversionArray (KeyboardLayouts layouts, KeyboardLayout layout)
+ {
+ XEvent e2 = new XEvent ();
+ uint keysym = 0;
+ int [] ckey = new int [] { 0, 0, 0, 0 };
+
+ e2.KeyEvent.display = display;
+ e2.KeyEvent.state = 0;
+
+ for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
+ int vkey = 0;
+ int scan = 0;
+
+ e2.KeyEvent.keycode = keyc;
+ XKeySym t;
+
+ XLookupStatus status;
+ LookupString (ref e2, 0, out t, out status);
+
+ keysym = (uint) t;
+ if (keysym != 0) {
+ if ((keysym >> 8) == 0xFF) {
+ vkey = nonchar_key_vkey [keysym & 0xFF];
+ scan = nonchar_key_scan [keysym & 0xFF];
+ // Set extended bit
+ if ((scan & 0x100) != 0)
+ vkey |= 0x100;
+ } else if (keysym == 0x20) { // spacebar
+ vkey = (int) VirtualKeys.VK_SPACE;
+ scan = 0x39;
+ } else {
+ // Search layout dependent scancodes
+ int maxlen = 0;
+ int maxval = -1;;
+
+ for (int i = 0; i < syms; i++) {
+ keysym = XKeycodeToKeysym (display, keyc, i);
+ if ((keysym < 0x800) && (keysym != ' '))
+ ckey [i] = (sbyte) (keysym & 0xFF);
+ else
+ ckey [i] = (sbyte) MapDeadKeySym ((int) keysym);
+ }
+
+ for (int keyn = 0; keyn < layout.Keys.Length; keyn++) {
+ int ml = Math.Min (layout.Keys [keyn].Length, 4);
+ int ok = -1;
+ for (int i = 0; (ok != 0) && (i < ml); i++) {
+ sbyte ck = (sbyte) layout.Keys [keyn][i];
+ if (ck != ckey [i])
+ ok = 0;
+ if ((ok != 0) || (i > maxlen)) {
+ maxlen = i;
+ maxval = keyn;
+ }
+ if (ok != 0)
+ break;
+ }
+ }
+ if (maxval >= 0) {
+ if (maxval < layouts.scan_table [(int) layout.ScanIndex].Length)
+ scan = layouts.scan_table [(int) layout.ScanIndex][maxval];
+ if (maxval < layouts.vkey_table [(int) layout.VKeyIndex].Length)
+ vkey = layouts.vkey_table [(int) layout.VKeyIndex][maxval];
+ }
+ }
+ }
+ keyc2vkey [e2.KeyEvent.keycode] = vkey;
+ keyc2scan [e2.KeyEvent.keycode] = scan;
+ }
+
+
+ }
+
+ private KeyboardLayout DetectLayout (KeyboardLayouts layouts)
+ {
+ XDisplayKeycodes (display, out min_keycode, out max_keycode);
+ IntPtr ksp = XGetKeyboardMapping (display, (byte) min_keycode,
+ max_keycode + 1 - min_keycode, out keysyms_per_keycode);
+ lock (XlibLock) {
+ XplatUIX11.XFree (ksp);
+ }
+
+ syms = keysyms_per_keycode;
+ if (syms > 4) {
+ //Console.Error.WriteLine ("{0} keysymbols per a keycode is not supported, setting to 4", syms);
+ syms = 2;
+ }
+
+ IntPtr modmap_unmanaged;
+ XModifierKeymap xmk = new XModifierKeymap ();
+
+ modmap_unmanaged = XGetModifierMapping (display);
+ xmk = (XModifierKeymap) Marshal.PtrToStructure (modmap_unmanaged, typeof (XModifierKeymap));
+
+ int mmp = 0;
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < xmk.max_keypermod; j++, mmp++) {
+ byte b = Marshal.ReadByte (xmk.modifiermap, mmp);
+ if (b != 0) {
+ for (int k = 0; k < keysyms_per_keycode; k++) {
+ if ((int) XKeycodeToKeysym (display, b, k) == (int) MiscKeys.XK_Num_Lock)
+ NumLockMask = 1 << i;
+ }
+ }
+ }
+ }
+ XFreeModifiermap (modmap_unmanaged);
+
+ int [] ckey = new int [4];
+ KeyboardLayout layout = null;
+ int max_score = 0;
+ int max_seq = 0;
+
+ foreach (KeyboardLayout current in layouts.Layouts) {
+ int ok = 0;
+ int score = 0;
+ int match = 0;
+ int mismatch = 0;
+ int seq = 0;
+ int pkey = -1;
+ int key = min_keycode;
+ int i;
+
+ for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
+ for (i = 0; i < syms; i++) {
+ uint keysym = XKeycodeToKeysym (display, keyc, i);
+
+ if ((keysym < 0x800) && (keysym != ' ')) {
+ ckey [i] = (sbyte) (keysym & 0xFF);
+ } else {
+ ckey [i] = (sbyte) MapDeadKeySym ((int) keysym);
+ }
+ }
+ if (ckey [0] != 0) {
+ for (key = 0; key < current.Keys.Length; key++) {
+ int ml = Math.Min (syms, current.Keys [key].Length);
+ for (ok = 0, i = 0; (ok >= 0) && (i < ml); i++) {
+ sbyte ck = (sbyte) current.Keys [key][i];
+ if (ck != 0 && ck == ckey[i])
+ ok++;
+ if (ck != 0 && ck != ckey[i])
+ ok = -1;
+ }
+ if (ok > 0) {
+ score += ok;
+ break;
+ }
+ }
+ if (ok > 0) {
+ match++;
+ /* and how much the keycode order matches */
+ if (key > pkey)
+ seq++;
+ pkey = key;
+ } else {
+ /* print spaces instead of \0's */
+ mismatch++;
+ score -= syms;
+ }
+ }
+ }
+
+ if ((score > max_score) || ((score == max_score) && (seq > max_seq))) {
+ // best match so far
+ layout = current;
+ max_score = score;
+ max_seq = seq;
+ }
+ }
+
+ if (layout != null) {
+ return layout;
+ } else {
+ Console.WriteLine ("Keyboard layout not recognized, using default layout: " +
+ layouts.Layouts [0].Name);
+ }
+
+ return layouts.Layouts [0];
+ }
+
+ // TODO
+ private int MapDeadKeySym (int val)
+ {
+ switch (val) {
+ case (int) DeadKeys.XK_dead_tilde :
+ case 0x1000FE7E : // Xfree's Dtilde
+ return '~';
+ case (int) DeadKeys.XK_dead_acute :
+ case 0x1000FE27 : // Xfree's XK_Dacute_accent
+ return 0xb4;
+ case (int) DeadKeys.XK_dead_circumflex:
+ case 0x1000FE5E : // Xfree's XK_.Dcircumflex_accent
+ return '^';
+ case (int) DeadKeys.XK_dead_grave :
+ case 0x1000FE60 : // Xfree's XK_.Dgrave_accent
+ return '`';
+ case (int) DeadKeys.XK_dead_diaeresis :
+ case 0x1000FE22 : // Xfree's XK_.Ddiaeresis
+ return 0xa8;
+ case (int) DeadKeys.XK_dead_cedilla :
+ return 0xb8;
+ case (int) DeadKeys.XK_dead_macron :
+ return '-';
+ case (int) DeadKeys.XK_dead_breve :
+ return 0xa2;
+ case (int) DeadKeys.XK_dead_abovedot :
+ return 0xff;
+ case (int) DeadKeys.XK_dead_abovering :
+ return '0';
+ case (int) DeadKeys.XK_dead_doubleacute :
+ return 0xbd;
+ case (int) DeadKeys.XK_dead_caron :
+ return 0xb7;
+ case (int) DeadKeys.XK_dead_ogonek :
+ return 0xb2;
+ }
+
+ return 0;
+ }
+
+ private XIMProperties [] GetSupportedInputStyles (IntPtr xim)
+ {
+ IntPtr stylesPtr;
+ string ret = XGetIMValues (xim, XNames.XNQueryInputStyle, out stylesPtr, IntPtr.Zero);
+ if (ret != null || stylesPtr == IntPtr.Zero)
+ return new XIMProperties [0];
+ XIMStyles styles = (XIMStyles) Marshal.PtrToStructure (stylesPtr, typeof (XIMStyles));
+ XIMProperties [] supportedStyles = new XIMProperties [styles.count_styles];
+ for (int i = 0; i < styles.count_styles; i++)
+ supportedStyles [i] = (XIMProperties) Marshal.PtrToStructure (new IntPtr ((long) styles.supported_styles + i * Marshal.SizeOf (typeof (IntPtr))), typeof (XIMProperties));
+ lock (XlibLock) {
+ XplatUIX11.XFree (stylesPtr);
+ }
+ return supportedStyles;
+ }
+
+ const XIMProperties styleRoot = XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing;
+ const XIMProperties styleOverTheSpot = XIMProperties.XIMPreeditPosition | XIMProperties.XIMStatusNothing;
+ const XIMProperties styleOnTheSpot = XIMProperties.XIMPreeditCallbacks | XIMProperties.XIMStatusNothing;
+ const string ENV_NAME_XIM_STYLE = "MONO_WINFORMS_XIM_STYLE";
+
+ private XIMProperties [] GetPreferredStyles ()
+ {
+ string env = Environment.GetEnvironmentVariable (ENV_NAME_XIM_STYLE);
+ if (env == null)
+ env = "over-the-spot";
+ string [] list = env.Split (' ');
+ XIMProperties [] ret = new XIMProperties [list.Length];
+ for (int i = 0; i < list.Length; i++) {
+ string s = list [i];
+ switch (s) {
+ case "over-the-spot":
+ ret [i] = styleOverTheSpot;
+ break;
+ case "on-the-spot":
+ ret [i] = styleOnTheSpot;
+ break;
+ case "root":
+ ret [i] = styleRoot;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ private IEnumerable GetMatchingStylesInPreferredOrder (IntPtr xim)
+ {
+ XIMProperties [] supportedStyles = GetSupportedInputStyles (xim);
+ foreach (XIMProperties p in GetPreferredStyles ())
+ if (Array.IndexOf (supportedStyles, p) >= 0)
+ yield return p;
+ }
+
+ private IntPtr CreateXic (IntPtr window, IntPtr xim)
+ {
+ IntPtr xic = IntPtr.Zero;
+ foreach (XIMProperties targetStyle in GetMatchingStylesInPreferredOrder (xim)) {
+ ximStyle = targetStyle;
+ // FIXME: use __arglist when it gets working. See bug #321686
+ switch (targetStyle) {
+ case styleOverTheSpot:
+ xic = CreateOverTheSpotXic (window, xim);
+ if (xic != IntPtr.Zero)
+ break;
+ //Console.WriteLine ("failed to create XIC in over-the-spot mode.");
+ continue;
+ case styleOnTheSpot:
+ // Since .NET/Winforms seems to support only over-the-spot mode,,
+ // I'm not likely to continue on-the-spot implementation. But in
+ // case we need it, this code will be still useful.
+ xic = CreateOnTheSpotXic (window, xim);
+ if (xic != IntPtr.Zero)
+ break;
+ //Console.WriteLine ("failed to create XIC in on-the-spot mode.");
+ continue;
+ case styleRoot:
+ xic = XCreateIC (xim,
+ XNames.XNInputStyle, styleRoot,
+ XNames.XNClientWindow, window,
+ IntPtr.Zero);
+ break;
+ }
+ }
+ // fall back to root mode if all modes failed
+ if (xic == IntPtr.Zero) {
+ ximStyle = styleRoot;
+ xic = XCreateIC (xim,
+ XNames.XNInputStyle, styleRoot,
+ XNames.XNClientWindow, window,
+ XNames.XNFocusWindow, window,
+ IntPtr.Zero);
+ }
+ return xic;
+ }
+
+ private IntPtr CreateOverTheSpotXic (IntPtr window, IntPtr xim)
+ {
+ IntPtr list;
+ int count;
+ Widget c = Widget.FromHandle (window);
+ string xlfd = String.Format ("-*-*-*-*-*-*-{0}-*-*-*-*-*-*-*", (int) c.Font.Size);
+ IntPtr fontSet = XCreateFontSet (display, xlfd, out list, out count, IntPtr.Zero);
+ XPoint spot = new XPoint ();
+ spot.X = 0;
+ spot.Y = 0;
+ IntPtr pSL = IntPtr.Zero, pFS = IntPtr.Zero;
+ try {
+ pSL = Marshal.StringToHGlobalAnsi (XNames.XNSpotLocation);
+ pFS = Marshal.StringToHGlobalAnsi (XNames.XNFontSet);
+ IntPtr preedit = XVaCreateNestedList (0,
+ pSL, spot,
+ pFS, fontSet,
+ IntPtr.Zero);
+ return XCreateIC (xim,
+ XNames.XNInputStyle, styleOverTheSpot,
+ XNames.XNClientWindow, window,
+ XNames.XNPreeditAttributes, preedit,
+ IntPtr.Zero);
+ } finally {
+ if (pSL != IntPtr.Zero)
+ Marshal.FreeHGlobal (pSL);
+ if (pFS != IntPtr.Zero)
+ Marshal.FreeHGlobal (pFS);
+ XFreeStringList (list);
+ //XplatUIX11.XFree (preedit);
+ //XFreeFontSet (fontSet);
+ }
+ }
+
+ private IntPtr CreateOnTheSpotXic (IntPtr window, IntPtr xim)
+ {
+ callbackContext = new XIMCallbackContext (window);
+ return callbackContext.CreateXic (window, xim);
+ }
+
+ class XIMCallbackContext
+ {
+ XIMCallback startCB, doneCB, drawCB, caretCB;
+ IntPtr pStartCB = IntPtr.Zero, pDoneCB = IntPtr.Zero, pDrawCB = IntPtr.Zero, pCaretCB = IntPtr.Zero;
+ IntPtr pStartCBN = IntPtr.Zero, pDoneCBN = IntPtr.Zero, pDrawCBN = IntPtr.Zero, pCaretCBN = IntPtr.Zero;
+
+ public XIMCallbackContext (IntPtr clientWindow)
+ {
+ startCB = new XIMCallback (clientWindow, DoPreeditStart);
+ doneCB = new XIMCallback (clientWindow, DoPreeditDone);
+ drawCB = new XIMCallback (clientWindow, DoPreeditDraw);
+ caretCB = new XIMCallback (clientWindow, DoPreeditCaret);
+ pStartCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback)));
+ pDoneCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback)));
+ pDrawCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback)));
+ pCaretCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback)));
+ pStartCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditStartCallback);
+ pDoneCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditDoneCallback);
+ pDrawCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditDrawCallback);
+ pCaretCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditCaretCallback);
+ }
+
+ ~XIMCallbackContext ()
+ {
+ if (pStartCBN != IntPtr.Zero)
+ Marshal.FreeHGlobal (pStartCBN);
+ if (pDoneCBN != IntPtr.Zero)
+ Marshal.FreeHGlobal (pDoneCBN);
+ if (pDrawCBN != IntPtr.Zero)
+ Marshal.FreeHGlobal (pDrawCBN);
+ if (pCaretCBN != IntPtr.Zero)
+ Marshal.FreeHGlobal (pCaretCBN);
+
+ if (pStartCB != IntPtr.Zero)
+ Marshal.FreeHGlobal (pStartCB);
+ if (pDoneCB != IntPtr.Zero)
+ Marshal.FreeHGlobal (pDoneCB);
+ if (pDrawCB != IntPtr.Zero)
+ Marshal.FreeHGlobal (pDrawCB);
+ if (pCaretCB != IntPtr.Zero)
+ Marshal.FreeHGlobal (pCaretCB);
+ }
+
+ int DoPreeditStart (IntPtr xic, IntPtr clientData, IntPtr callData)
+ {
+ Debug.WriteLine ("DoPreeditStart");
+ XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITSTART, clientData, callData);
+ return 100;
+ }
+
+ int DoPreeditDone (IntPtr xic, IntPtr clientData, IntPtr callData)
+ {
+ Debug.WriteLine ("DoPreeditDone");
+ XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITDONE, clientData, callData);
+ return 0;
+ }
+
+ int DoPreeditDraw (IntPtr xic, IntPtr clientData, IntPtr callData)
+ {
+ Debug.WriteLine ("DoPreeditDraw");
+ XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITDRAW, clientData, callData);
+ return 0;
+ }
+
+ int DoPreeditCaret (IntPtr xic, IntPtr clientData, IntPtr callData)
+ {
+ Debug.WriteLine ("DoPreeditCaret");
+ XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITCARET, clientData, callData);
+ return 0;
+ }
+
+ public IntPtr CreateXic (IntPtr window, IntPtr xim)
+ {
+ Marshal.StructureToPtr (startCB, pStartCB, false);
+ Marshal.StructureToPtr (doneCB, pDoneCB, false);
+ Marshal.StructureToPtr (drawCB, pDrawCB, false);
+ Marshal.StructureToPtr (caretCB, pCaretCB, false);
+ IntPtr preedit = XVaCreateNestedList (0,
+ pStartCBN, pStartCB,
+ pDoneCBN, pDoneCB,
+ pDrawCBN, pDrawCB,
+ pCaretCBN, pCaretCB,
+ IntPtr.Zero);
+ return XCreateIC (xim,
+ XNames.XNInputStyle, styleOnTheSpot,
+ XNames.XNClientWindow, window,
+ XNames.XNPreeditAttributes, preedit,
+ IntPtr.Zero);
+ }
+ }
+
+ class XIMPositionContext
+ {
+ public CaretStruct Caret;
+ public int X;
+ public int Y;
+ }
+
+ internal void SetCaretPos (CaretStruct caret, IntPtr handle, int x, int y)
+ {
+ if (ximStyle != styleOverTheSpot)
+ return;
+
+ if (positionContext == null)
+ this.positionContext = new XIMPositionContext ();
+
+ positionContext.Caret = caret;
+ positionContext.X = x;
+ positionContext.Y = y + caret.Height;
+
+ MoveCurrentCaretPos ();
+ }
+
+ internal void MoveCurrentCaretPos ()
+ {
+ if (positionContext == null || ximStyle != styleOverTheSpot || client_window == IntPtr.Zero)
+ return;
+
+ int x = positionContext.X;
+ int y = positionContext.Y;
+ CaretStruct caret = positionContext.Caret;
+ IntPtr xic = GetXic (client_window);
+ if (xic == IntPtr.Zero)
+ return;
+ Widget Widget = Widget.FromHandle (client_window);
+ if (Widget == null || !Widget.IsHandleCreated)
+ return;
+ Widget = Widget.FromHandle (caret.Hwnd);
+ if (Widget == null || !Widget.IsHandleCreated)
+ return;
+ Hwnd hwnd = Hwnd.ObjectFromHandle (client_window);
+ if (!hwnd.mapped)
+ return;
+
+ int dx, dy;
+ IntPtr child;
+ lock (XlibLock) {
+ XplatUIX11.XTranslateCoordinates (display, client_window, client_window, x, y, out dx, out dy, out child);
+ }
+
+ XPoint spot = new XPoint ();
+ spot.X = (short) dx;
+ spot.Y = (short) dy;
+
+ IntPtr pSL = IntPtr.Zero;
+ try {
+ pSL = Marshal.StringToHGlobalAnsi (XNames.XNSpotLocation);
+ IntPtr preedit = XVaCreateNestedList (0, pSL, spot, IntPtr.Zero);
+ XSetICValues (xic, XNames.XNPreeditAttributes, preedit, IntPtr.Zero);
+ } finally {
+ if (pSL != IntPtr.Zero)
+ Marshal.FreeHGlobal (pSL);
+ }
+ }
+
+ private bool have_Xutf8LookupString = true;
+
+ private int LookupString (ref XEvent xevent, int len, out XKeySym keysym, out XLookupStatus status)
+ {
+ IntPtr keysym_res;
+ int res;
+
+ status = XLookupStatus.XLookupNone;
+ IntPtr xic = GetXic (client_window);
+ if (xic != IntPtr.Zero && have_Xutf8LookupString && xevent.type == XEventName.KeyPress) {
+ do {
+ try {
+ res = Xutf8LookupString (xic, ref xevent, lookup_byte_buffer, 100, out keysym_res, out status);
+ } catch (EntryPointNotFoundException) {
+ have_Xutf8LookupString = false;
+
+ // call again, this time we'll go through the non-xic clause
+ return LookupString (ref xevent, len, out keysym, out status);
+ }
+ if (status != XLookupStatus.XBufferOverflow)
+ break;
+ lookup_byte_buffer = new byte [lookup_byte_buffer.Length << 1];
+ } while (true);
+ lookup_buffer.Length = 0;
+ string s = Encoding.UTF8.GetString (lookup_byte_buffer, 0, res);
+ lookup_buffer.Append (s);
+ keysym = (XKeySym) keysym_res.ToInt32 ();
+ return s.Length;
+ } else {
+ IntPtr statusPtr = IntPtr.Zero;
+ lookup_buffer.Length = 0;
+ res = XLookupString (ref xevent, lookup_buffer, len, out keysym_res, out statusPtr);
+ keysym = (XKeySym) keysym_res.ToInt32 ();
+ return res;
+ }
+ }
+
+ [DllImport ("libX11")]
+ private static extern IntPtr XOpenIM (IntPtr display, IntPtr rdb, IntPtr res_name, IntPtr res_class);
+
+ [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, IntPtr terminator);
+ [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, string name3, IntPtr value3, IntPtr terminator);
+// [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)]
+// private static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, string name3, IntPtr value3, string name4, IntPtr value4, IntPtr terminator);
+
+ [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr XVaCreateNestedList (int dummy, IntPtr name0, XPoint value0, IntPtr terminator);
+ [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr XVaCreateNestedList (int dummy, IntPtr name0, XPoint value0, IntPtr name1, IntPtr value1, IntPtr terminator);
+ [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr XVaCreateNestedList (int dummy, IntPtr name0, IntPtr value0, IntPtr name1, IntPtr value1, IntPtr name2, IntPtr value2, IntPtr name3, IntPtr value3, IntPtr terminator);
+
+ [DllImport ("libX11")]
+ private static extern IntPtr XCreateFontSet (IntPtr display, string name, out IntPtr list, out int count, IntPtr terminator);
+
+ [DllImport ("libX11")]
+ internal extern static void XFreeFontSet (IntPtr data);
+
+ [DllImport ("libX11")]
+ private static extern void XFreeStringList (IntPtr ptr);
+
+ //[DllImport ("libX11")]
+ //private static extern IntPtr XIMOfIC (IntPtr xic);
+
+ [DllImport ("libX11")]
+ private static extern void XCloseIM (IntPtr xim);
+
+ [DllImport ("libX11")]
+ private static extern void XDestroyIC (IntPtr xic);
+
+ [DllImport ("libX11")]
+ private static extern string XGetIMValues (IntPtr xim, string name, out IntPtr value, IntPtr terminator);
+
+ [DllImport ("libX11")]
+ private static extern string XGetICValues (IntPtr xic, string name, out EventMask value, IntPtr terminator);
+
+ [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void XSetICValues (IntPtr xic, string name, IntPtr value, IntPtr terminator);
+
+ [DllImport ("libX11")]
+ private static extern void XSetICFocus (IntPtr xic);
+
+ [DllImport ("libX11")]
+ private static extern void XUnsetICFocus (IntPtr xic);
+
+ [DllImport ("libX11")]
+ private static extern string Xutf8ResetIC (IntPtr xic);
+
+ [DllImport ("libX11")]
+ private static extern bool XSupportsLocale ();
+
+ [DllImport ("libX11")]
+ private static extern bool XSetLocaleModifiers (string mods);
+
+ [DllImport ("libX11")]
+ internal extern static int XLookupString(ref XEvent xevent, StringBuilder buffer, int num_bytes, out IntPtr keysym, out IntPtr status);
+ [DllImport ("libX11")]
+ internal extern static int Xutf8LookupString(IntPtr xic, ref XEvent xevent, byte [] buffer, int num_bytes, out IntPtr keysym, out XLookupStatus status);
+
+ [DllImport ("libX11")]
+ private static extern IntPtr XGetKeyboardMapping (IntPtr display, byte first_keycode, int keycode_count,
+ out int keysyms_per_keycode_return);
+
+ [DllImport ("libX11")]
+ private static extern void XDisplayKeycodes (IntPtr display, out int min, out int max);
+
+ [DllImport ("libX11", EntryPoint="XKeycodeToKeysym")]
+ private static extern uint XKeycodeToKeysym (IntPtr display, int keycode, int index);
+
+ [DllImport ("libX11")]
+ private static extern int XKeysymToKeycode (IntPtr display, IntPtr keysym);
+ private static int XKeysymToKeycode (IntPtr display, int keysym) {
+ return XKeysymToKeycode(display, (IntPtr)keysym);
+ }
+
+ [DllImport ("libX11")]
+ internal extern static IntPtr XGetModifierMapping (IntPtr display);
+
+ [DllImport ("libX11")]
+ internal extern static int XFreeModifiermap (IntPtr modmap);
+
+
+ private readonly static int [] nonchar_key_vkey = new int []
+ {
+ /* unused */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
+ /* special keys */
+ (int) VirtualKeys.VK_BACK, (int) VirtualKeys.VK_TAB, 0, (int) VirtualKeys.VK_CLEAR, 0, (int) VirtualKeys.VK_RETURN, 0, 0, /* FF08 */
+ 0, 0, 0, (int) VirtualKeys.VK_PAUSE, (int) VirtualKeys.VK_SCROLL, 0, 0, 0, /* FF10 */
+ 0, 0, 0, (int) VirtualKeys.VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
+ 0, 0, (int) VirtualKeys.VK_NONCONVERT, (int) VirtualKeys.VK_CONVERT, 0, 0, 0, 0, /* FF20 */
+ 0, 0, (int) VirtualKeys.VK_OEM_AUTO, 0, 0, 0, 0, 0, /* FF28 */
+ /* unused */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
+ /* cursor keys */
+ (int) VirtualKeys.VK_HOME, (int) VirtualKeys.VK_LEFT, (int) VirtualKeys.VK_UP, (int) VirtualKeys.VK_RIGHT, /* FF50 */
+ (int) VirtualKeys.VK_DOWN, (int) VirtualKeys.VK_PRIOR, (int) VirtualKeys.VK_NEXT, (int) VirtualKeys.VK_END,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
+ /* misc keys */
+ (int) VirtualKeys.VK_SELECT, (int) VirtualKeys.VK_SNAPSHOT, (int) VirtualKeys.VK_EXECUTE, (int) VirtualKeys.VK_INSERT, 0, 0, 0, 0, /* FF60 */
+ (int) VirtualKeys.VK_CANCEL, (int) VirtualKeys.VK_HELP, (int) VirtualKeys.VK_CANCEL, (int) VirtualKeys.VK_CANCEL, 0, 0, 0, 0, /* FF68 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
+ /* keypad keys */
+ 0, 0, 0, 0, 0, 0, 0, (int) VirtualKeys.VK_NUMLOCK, /* FF78 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
+ 0, 0, 0, 0, 0, (int) VirtualKeys.VK_RETURN, 0, 0, /* FF88 */
+ 0, 0, 0, 0, 0, (int) VirtualKeys.VK_HOME, (int) VirtualKeys.VK_LEFT, (int) VirtualKeys.VK_UP, /* FF90 */
+ (int) VirtualKeys.VK_RIGHT, (int) VirtualKeys.VK_DOWN, (int) VirtualKeys.VK_PRIOR, (int) VirtualKeys.VK_NEXT, /* FF98 */
+ (int) VirtualKeys.VK_END, 0, (int) VirtualKeys.VK_INSERT, (int) VirtualKeys.VK_DELETE,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
+ 0, 0, (int) VirtualKeys.VK_MULTIPLY, (int) VirtualKeys.VK_ADD, /* FFA8 */
+ (int) VirtualKeys.VK_SEPARATOR, (int) VirtualKeys.VK_SUBTRACT, (int) VirtualKeys.VK_DECIMAL, (int) VirtualKeys.VK_DIVIDE,
+ (int) VirtualKeys.VK_NUMPAD0, (int) VirtualKeys.VK_NUMPAD1, (int) VirtualKeys.VK_NUMPAD2, (int) VirtualKeys.VK_NUMPAD3, /* FFB0 */
+ (int) VirtualKeys.VK_NUMPAD4, (int) VirtualKeys.VK_NUMPAD5, (int) VirtualKeys.VK_NUMPAD6, (int) VirtualKeys.VK_NUMPAD7,
+ (int) VirtualKeys.VK_NUMPAD8, (int) VirtualKeys.VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
+ /* function keys */
+ (int) VirtualKeys.VK_F1, (int) VirtualKeys.VK_F2,
+ (int) VirtualKeys.VK_F3, (int) VirtualKeys.VK_F4, (int) VirtualKeys.VK_F5, (int) VirtualKeys.VK_F6, (int) VirtualKeys.VK_F7, (int) VirtualKeys.VK_F8, (int) VirtualKeys.VK_F9, (int) VirtualKeys.VK_F10, /* FFC0 */
+ (int) VirtualKeys.VK_F11, (int) VirtualKeys.VK_F12, (int) VirtualKeys.VK_F13, (int) VirtualKeys.VK_F14, (int) VirtualKeys.VK_F15, (int) VirtualKeys.VK_F16, 0, 0, /* FFC8 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
+ /* modifier keys */
+ 0, (int) VirtualKeys.VK_SHIFT, (int) VirtualKeys.VK_SHIFT, (int) VirtualKeys.VK_CONTROL, /* FFE0 */
+ (int) VirtualKeys.VK_CONTROL, (int) VirtualKeys.VK_CAPITAL, 0, (int) VirtualKeys.VK_MENU,
+ (int) VirtualKeys.VK_MENU, (int) VirtualKeys.VK_MENU, (int) VirtualKeys.VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
+ 0, 0, 0, 0, 0, 0, 0, (int) VirtualKeys.VK_DELETE /* FFF8 */
+ };
+
+ private static readonly int [] nonchar_key_scan = new int []
+ {
+ /* unused */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
+ /* special keys */
+ 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
+ 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
+ /* unused */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
+ /* cursor keys */
+ 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
+ /* misc keys */
+ /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
+ /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
+ /* keypad keys */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
+ 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
+ 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
+ 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
+ 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
+ /* function keys */
+ 0x3B, 0x3C,
+ 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
+ 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
+ /* modifier keys */
+ 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
+ 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
+ };
+
+ private readonly static int [] nonchar_vkey_key = new int []
+ {
+ 0, 0, 0, 0, 0, /* 00-04 */
+ 0, 0, 0, (int)XKeySym.XK_BackSpace, (int)XKeySym.XK_Tab, /* 05-09 */
+ 0, 0, (int)XKeySym.XK_Clear, (int)XKeySym.XK_Return, 0, 0, /* 0A-0F */
+ (int)XKeySym.XK_Shift_L, (int)XKeySym.XK_Control_L, (int)XKeySym.XK_Menu, 0, (int)XKeySym.XK_Caps_Lock, /* 10-14 */
+ 0, 0, 0, 0, 0, /* 15-19 */
+ 0, 0, 0, 0, 0, 0, /* 1A-1F */
+ 0, 0, 0, (int)XKeySym.XK_End, (int)XKeySym.XK_Home, /* 20-24 */
+ (int)XKeySym.XK_Left, (int)XKeySym.XK_Up, (int)XKeySym.XK_Right, (int)XKeySym.XK_Down, 0, /* 25-29 */
+ 0, 0, 0, 0, 0, 0, /* 2A-2F */
+ 0, 0, 0, 0, 0, /* 30-34 */
+ 0, 0, 0, 0, 0, /* 35-39 */
+ 0, 0, 0, 0, 0, 0, /* 3A-3F */
+ 0, 0, 0, 0, 0, /* 40-44 */
+ 0, 0, 0, 0, 0, /* 45-49 */
+ 0, 0, 0, 0, 0, 0, /* 4A-4F */
+ 0, 0, 0, 0, 0, /* 50-54 */
+ 0, 0, 0, 0, 0, /* 55-59 */
+ 0, (int)XKeySym.XK_Meta_L, (int)XKeySym.XK_Meta_R, 0, 0, 0, /* 5A-5F */
+ 0, 0, 0, 0, 0, /* 60-64 */
+ 0, 0, 0, 0, 0, /* 65-69 */
+ 0, 0, 0, 0, 0, 0, /* 6A-6F */
+ 0, 0, 0, 0, 0, /* 70-74 */
+ 0, 0, 0, 0, 0, /* 75-79 */
+ 0, 0, 0, 0, 0, 0, /* 7A-7F */
+ 0, 0, 0, 0, 0, /* 80-84 */
+ 0, 0, 0, 0, 0, /* 85-89 */
+ 0, 0, 0, 0, 0, 0, /* 8A-8F */
+ 0, 0, 0, 0, 0, /* 90-94 */
+ 0, 0, 0, 0, 0, /* 95-99 */
+ 0, 0, 0, 0, 0, 0, /* 9A-9F */
+ (int)XKeySym.XK_Shift_L, (int)XKeySym.XK_Shift_R, (int)XKeySym.XK_Control_L, (int)XKeySym.XK_Control_R, (int)XKeySym.XK_Alt_L, /* A0-A4 */
+ (int)XKeySym.XK_Alt_R, 0, 0, 0, 0, /* A5-A9 */
+ 0, 0, 0, 0, 0, 0, /* AA-AF */
+ 0, 0, 0, 0, 0, /* B0-B4 */
+ 0, 0, 0, 0, 0, /* B5-B9 */
+ 0, 0, 0, 0, 0, 0, /* BA-BF */
+ 0, 0, 0, 0, 0, /* C0-C4 */
+ 0, 0, 0, 0, 0, /* C5-C9 */
+ 0, 0, 0, 0, 0, 0, /* CA-CF */
+ 0, 0, 0, 0, 0, /* D0-D4 */
+ 0, 0, 0, 0, 0, /* D5-D9 */
+ 0, 0, 0, 0, 0, 0, /* DA-DF */
+ 0, 0, 0, 0, 0, /* E0-E4 */
+ 0, 0, 0, 0, 0, /* E5-E9 */
+ 0, 0, 0, 0, 0, 0, /* EA-EF */
+ 0, 0, 0, 0, 0, /* F0-F4 */
+ 0, 0, 0, 0, 0, /* F5-F9 */
+ 0, 0, 0, 0, 0, 0 /* FA-FF */
+ };
+
+ }
+
+}
+
diff --git a/source/ShiftUI/Internal/X11RootHwnd.cs b/source/ShiftUI/Internal/X11RootHwnd.cs
new file mode 100644
index 0000000..45a7bee
--- /dev/null
+++ b/source/ShiftUI/Internal/X11RootHwnd.cs
@@ -0,0 +1,87 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+//
+
+using System;
+using System.Runtime.InteropServices;
+using ShiftUI;
+
+namespace ShiftUI.X11Internal {
+
+ internal class X11RootHwnd : X11Hwnd
+ {
+ public X11RootHwnd (X11Display display, IntPtr window_handle) : base (display)
+ {
+ WholeWindow = ClientWindow = window_handle;
+
+ Xlib.XSelectInput(display.Handle, WholeWindow, new IntPtr ((int)EventMask.PropertyChangeMask));
+ }
+
+ public override void CreateWindow (CreateParams cp)
+ {
+ // we don't do anything here
+ }
+
+ public override void PropertyChanged (XEvent xevent)
+ {
+ if (xevent.PropertyEvent.atom == Display.Atoms._NET_ACTIVE_WINDOW) {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Xlib.XGetWindowProperty (Display.Handle, WholeWindow,
+ Display.Atoms._NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false,
+ Display.Atoms.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
+ // FIXME - is this 64 bit clean?
+ Display.SetActiveWindow ((X11Hwnd)Hwnd.ObjectFromHandle((IntPtr)Marshal.ReadInt32(prop)));
+ Xlib.XFree(prop);
+ }
+ }
+ else if (xevent.PropertyEvent.atom == Display.Atoms._NET_SUPPORTED) {
+ // we'll need to refetch the supported protocols list
+ refetch_net_supported = true;
+ _net_supported = null;
+ }
+ else
+ base.PropertyChanged (xevent);
+ }
+
+ bool refetch_net_supported = true;
+ IntPtr[] _net_supported;
+ public IntPtr[] _NET_SUPPORTED {
+ get {
+ if (refetch_net_supported) {
+ _net_supported = GetAtomListProperty (Display.Atoms._NET_SUPPORTED);
+ refetch_net_supported = false;
+ }
+
+ return _net_supported;
+ }
+ }
+ }
+
+}
+
diff --git a/source/ShiftUI/Internal/X11Structs.cs b/source/ShiftUI/Internal/X11Structs.cs
new file mode 100644
index 0000000..52bd880
--- /dev/null
+++ b/source/ShiftUI/Internal/X11Structs.cs
@@ -0,0 +1,1824 @@
+// 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 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+
+
+// NOT COMPLETE
+
+using System;
+using System.ComponentModel;
+using System.Collections;
+using System.Drawing;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+/// X11 Version
+using System.Reflection;
+
+
+namespace ShiftUI {
+ //
+ // In the structures below, fields of type long are mapped to IntPtr.
+ // This will work on all platforms where sizeof(long)==sizeof(void*), which
+ // is almost all platforms except WIN64.
+ //
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XAnyEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XKeyEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal int state;
+ internal int keycode;
+ internal bool same_screen;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XButtonEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal int state;
+ internal int button;
+ internal bool same_screen;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMotionEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal int state;
+ internal byte is_hint;
+ internal bool same_screen;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCrossingEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal NotifyMode mode;
+ internal NotifyDetail detail;
+ internal bool same_screen;
+ internal bool focus;
+ internal int state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XFocusChangeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int mode;
+ internal NotifyDetail detail;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XKeymapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal byte key_vector0;
+ internal byte key_vector1;
+ internal byte key_vector2;
+ internal byte key_vector3;
+ internal byte key_vector4;
+ internal byte key_vector5;
+ internal byte key_vector6;
+ internal byte key_vector7;
+ internal byte key_vector8;
+ internal byte key_vector9;
+ internal byte key_vector10;
+ internal byte key_vector11;
+ internal byte key_vector12;
+ internal byte key_vector13;
+ internal byte key_vector14;
+ internal byte key_vector15;
+ internal byte key_vector16;
+ internal byte key_vector17;
+ internal byte key_vector18;
+ internal byte key_vector19;
+ internal byte key_vector20;
+ internal byte key_vector21;
+ internal byte key_vector22;
+ internal byte key_vector23;
+ internal byte key_vector24;
+ internal byte key_vector25;
+ internal byte key_vector26;
+ internal byte key_vector27;
+ internal byte key_vector28;
+ internal byte key_vector29;
+ internal byte key_vector30;
+ internal byte key_vector31;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XExposeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int count;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XGraphicsExposeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr drawable;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int count;
+ internal int major_code;
+ internal int minor_code;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XNoExposeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr drawable;
+ internal int major_code;
+ internal int minor_code;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XVisibilityEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCreateWindowEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XDestroyWindowEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XUnmapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal bool from_configure;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMapRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XReparentEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal IntPtr parent;
+ internal int x;
+ internal int y;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XConfigureEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal IntPtr above;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XGravityEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XResizeRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int width;
+ internal int height;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XConfigureRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal IntPtr above;
+ internal int detail;
+ internal IntPtr value_mask;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCirculateEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal int place;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCirculateRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ internal int place;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XPropertyEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr atom;
+ internal IntPtr time;
+ internal int state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSelectionClearEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr selection;
+ internal IntPtr time;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSelectionRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr owner;
+ internal IntPtr requestor;
+ internal IntPtr selection;
+ internal IntPtr target;
+ internal IntPtr property;
+ internal IntPtr time;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSelectionEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr requestor;
+ internal IntPtr selection;
+ internal IntPtr target;
+ internal IntPtr property;
+ internal IntPtr time;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XColormapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr colormap;
+ internal bool c_new;
+ internal int state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XClientMessageEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr message_type;
+ internal int format;
+ internal IntPtr ptr1;
+ internal IntPtr ptr2;
+ internal IntPtr ptr3;
+ internal IntPtr ptr4;
+ internal IntPtr ptr5;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMappingEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int request;
+ internal int first_keycode;
+ internal int count;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XErrorEvent {
+ internal XEventName type;
+ internal IntPtr display;
+ internal IntPtr resourceid;
+ internal IntPtr serial;
+ internal byte error_code;
+ internal XRequest request_code;
+ internal byte minor_code;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XEventPad {
+ internal IntPtr pad0;
+ internal IntPtr pad1;
+ internal IntPtr pad2;
+ internal IntPtr pad3;
+ internal IntPtr pad4;
+ internal IntPtr pad5;
+ internal IntPtr pad6;
+ internal IntPtr pad7;
+ internal IntPtr pad8;
+ internal IntPtr pad9;
+ internal IntPtr pad10;
+ internal IntPtr pad11;
+ internal IntPtr pad12;
+ internal IntPtr pad13;
+ internal IntPtr pad14;
+ internal IntPtr pad15;
+ internal IntPtr pad16;
+ internal IntPtr pad17;
+ internal IntPtr pad18;
+ internal IntPtr pad19;
+ internal IntPtr pad20;
+ internal IntPtr pad21;
+ internal IntPtr pad22;
+ internal IntPtr pad23;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct XEvent {
+ [ FieldOffset(0) ] internal XEventName type;
+ [ FieldOffset(0) ] internal XAnyEvent AnyEvent;
+ [ FieldOffset(0) ] internal XKeyEvent KeyEvent;
+ [ FieldOffset(0) ] internal XButtonEvent ButtonEvent;
+ [ FieldOffset(0) ] internal XMotionEvent MotionEvent;
+ [ FieldOffset(0) ] internal XCrossingEvent CrossingEvent;
+ [ FieldOffset(0) ] internal XFocusChangeEvent FocusChangeEvent;
+ [ FieldOffset(0) ] internal XExposeEvent ExposeEvent;
+ [ FieldOffset(0) ] internal XGraphicsExposeEvent GraphicsExposeEvent;
+ [ FieldOffset(0) ] internal XNoExposeEvent NoExposeEvent;
+ [ FieldOffset(0) ] internal XVisibilityEvent VisibilityEvent;
+ [ FieldOffset(0) ] internal XCreateWindowEvent CreateWindowEvent;
+ [ FieldOffset(0) ] internal XDestroyWindowEvent DestroyWindowEvent;
+ [ FieldOffset(0) ] internal XUnmapEvent UnmapEvent;
+ [ FieldOffset(0) ] internal XMapEvent MapEvent;
+ [ FieldOffset(0) ] internal XMapRequestEvent MapRequestEvent;
+ [ FieldOffset(0) ] internal XReparentEvent ReparentEvent;
+ [ FieldOffset(0) ] internal XConfigureEvent ConfigureEvent;
+ [ FieldOffset(0) ] internal XGravityEvent GravityEvent;
+ [ FieldOffset(0) ] internal XResizeRequestEvent ResizeRequestEvent;
+ [ FieldOffset(0) ] internal XConfigureRequestEvent ConfigureRequestEvent;
+ [ FieldOffset(0) ] internal XCirculateEvent CirculateEvent;
+ [ FieldOffset(0) ] internal XCirculateRequestEvent CirculateRequestEvent;
+ [ FieldOffset(0) ] internal XPropertyEvent PropertyEvent;
+ [ FieldOffset(0) ] internal XSelectionClearEvent SelectionClearEvent;
+ [ FieldOffset(0) ] internal XSelectionRequestEvent SelectionRequestEvent;
+ [ FieldOffset(0) ] internal XSelectionEvent SelectionEvent;
+ [ FieldOffset(0) ] internal XColormapEvent ColormapEvent;
+ [ FieldOffset(0) ] internal XClientMessageEvent ClientMessageEvent;
+ [ FieldOffset(0) ] internal XMappingEvent MappingEvent;
+ [ FieldOffset(0) ] internal XErrorEvent ErrorEvent;
+ [ FieldOffset(0) ] internal XKeymapEvent KeymapEvent;
+
+ //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=24)]
+ //[ FieldOffset(0) ] internal int[] pad;
+ [ FieldOffset(0) ] internal XEventPad Pad;
+ public override string ToString() {
+ switch (type)
+ {
+ case XEventName.ButtonPress:
+ case XEventName.ButtonRelease:
+ return ToString (ButtonEvent);
+ case XEventName.CirculateNotify:
+ case XEventName.CirculateRequest:
+ return ToString (CirculateEvent);
+ case XEventName.ClientMessage:
+ return ToString (ClientMessageEvent);
+ case XEventName.ColormapNotify:
+ return ToString (ColormapEvent);
+ case XEventName.ConfigureNotify:
+ return ToString (ConfigureEvent);
+ case XEventName.ConfigureRequest:
+ return ToString (ConfigureRequestEvent);
+ case XEventName.CreateNotify:
+ return ToString (CreateWindowEvent);
+ case XEventName.DestroyNotify:
+ return ToString (DestroyWindowEvent);
+ case XEventName.Expose:
+ return ToString (ExposeEvent);
+ case XEventName.FocusIn:
+ case XEventName.FocusOut:
+ return ToString (FocusChangeEvent);
+ case XEventName.GraphicsExpose:
+ return ToString (GraphicsExposeEvent);
+ case XEventName.GravityNotify:
+ return ToString (GravityEvent);
+ case XEventName.KeymapNotify:
+ return ToString (KeymapEvent);
+ case XEventName.MapNotify:
+ return ToString (MapEvent);
+ case XEventName.MappingNotify:
+ return ToString (MappingEvent);
+ case XEventName.MapRequest:
+ return ToString (MapRequestEvent);
+ case XEventName.MotionNotify:
+ return ToString (MotionEvent);
+ case XEventName.NoExpose:
+ return ToString (NoExposeEvent);
+ case XEventName.PropertyNotify:
+ return ToString (PropertyEvent);
+ case XEventName.ReparentNotify:
+ return ToString (ReparentEvent);
+ case XEventName.ResizeRequest:
+ return ToString (ResizeRequestEvent);
+ case XEventName.SelectionClear:
+ return ToString (SelectionClearEvent);
+ case XEventName.SelectionNotify:
+ return ToString (SelectionEvent);
+ case XEventName.SelectionRequest:
+ return ToString (SelectionRequestEvent);
+ case XEventName.UnmapNotify:
+ return ToString (UnmapEvent);
+ case XEventName.VisibilityNotify:
+ return ToString (VisibilityEvent);
+ case XEventName.EnterNotify:
+ case XEventName.LeaveNotify:
+ return ToString (CrossingEvent);
+ default:
+ return type.ToString ();
+ }
+ }
+
+ public static string ToString (object ev)
+ {
+ string result = string.Empty;
+ Type type = ev.GetType ();
+ FieldInfo [] fields = type.GetFields (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance);
+ for (int i = 0; i < fields.Length; i++) {
+ if (result != string.Empty) {
+ result += ", ";
+ }
+ object value = fields [i].GetValue (ev);
+ result += fields [i].Name + "=" + (value == null ? "<null>" : value.ToString ());
+ }
+ return type.Name + " (" + result + ")";
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSetWindowAttributes {
+ internal IntPtr background_pixmap;
+ internal IntPtr background_pixel;
+ internal IntPtr border_pixmap;
+ internal IntPtr border_pixel;
+ internal Gravity bit_gravity;
+ internal Gravity win_gravity;
+ internal int backing_store;
+ internal IntPtr backing_planes;
+ internal IntPtr backing_pixel;
+ internal bool save_under;
+ internal IntPtr event_mask;
+ internal IntPtr do_not_propagate_mask;
+ internal bool override_redirect;
+ internal IntPtr colormap;
+ internal IntPtr cursor;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XWindowAttributes {
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal int depth;
+ internal IntPtr visual;
+ internal IntPtr root;
+ internal int c_class;
+ internal Gravity bit_gravity;
+ internal Gravity win_gravity;
+ internal int backing_store;
+ internal IntPtr backing_planes;
+ internal IntPtr backing_pixel;
+ internal bool save_under;
+ internal IntPtr colormap;
+ internal bool map_installed;
+ internal MapState map_state;
+ internal IntPtr all_event_masks;
+ internal IntPtr your_event_mask;
+ internal IntPtr do_not_propagate_mask;
+ internal bool override_direct;
+ internal IntPtr screen;
+
+ public override string ToString ()
+ {
+ return XEvent.ToString (this);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XTextProperty {
+ internal string value;
+ internal IntPtr encoding;
+ internal int format;
+ internal IntPtr nitems;
+ }
+
+ internal enum XWindowClass {
+ InputOutput = 1,
+ InputOnly = 2
+ }
+
+ internal enum XEventName {
+ KeyPress = 2,
+ KeyRelease = 3,
+ ButtonPress = 4,
+ ButtonRelease = 5,
+ MotionNotify = 6,
+ EnterNotify = 7,
+ LeaveNotify = 8,
+ FocusIn = 9,
+ FocusOut = 10,
+ KeymapNotify = 11,
+ Expose = 12,
+ GraphicsExpose = 13,
+ NoExpose = 14,
+ VisibilityNotify = 15,
+ CreateNotify = 16,
+ DestroyNotify = 17,
+ UnmapNotify = 18,
+ MapNotify = 19,
+ MapRequest = 20,
+ ReparentNotify = 21,
+ ConfigureNotify = 22,
+ ConfigureRequest = 23,
+ GravityNotify = 24,
+ ResizeRequest = 25,
+ CirculateNotify = 26,
+ CirculateRequest = 27,
+ PropertyNotify = 28,
+ SelectionClear = 29,
+ SelectionRequest = 30,
+ SelectionNotify = 31,
+ ColormapNotify = 32,
+ ClientMessage = 33,
+ MappingNotify = 34,
+
+ LASTEvent
+ }
+
+ [Flags]
+ internal enum SetWindowValuemask {
+ Nothing = 0,
+ BackPixmap = 1,
+ BackPixel = 2,
+ BorderPixmap = 4,
+ BorderPixel = 8,
+ BitGravity = 16,
+ WinGravity = 32,
+ BackingStore = 64,
+ BackingPlanes = 128,
+ BackingPixel = 256,
+ OverrideRedirect = 512,
+ SaveUnder = 1024,
+ EventMask = 2048,
+ DontPropagate = 4096,
+ ColorMap = 8192,
+ Cursor = 16384
+ }
+
+ internal enum SendEventValues {
+ PointerWindow = 0,
+ InputFocus = 1
+ }
+
+ internal enum CreateWindowArgs {
+ CopyFromParent = 0,
+ ParentRelative = 1,
+ InputOutput = 1,
+ InputOnly = 2
+ }
+
+ internal enum Gravity {
+ ForgetGravity = 0,
+ NorthWestGravity= 1,
+ NorthGravity = 2,
+ NorthEastGravity= 3,
+ WestGravity = 4,
+ CenterGravity = 5,
+ EastGravity = 6,
+ SouthWestGravity= 7,
+ SouthGravity = 8,
+ SouthEastGravity= 9,
+ StaticGravity = 10
+ }
+
+ internal enum XKeySym : uint {
+ XK_BackSpace = 0xFF08,
+ XK_Tab = 0xFF09,
+ XK_Clear = 0xFF0B,
+ XK_Return = 0xFF0D,
+ XK_Home = 0xFF50,
+ XK_Left = 0xFF51,
+ XK_Up = 0xFF52,
+ XK_Right = 0xFF53,
+ XK_Down = 0xFF54,
+ XK_Page_Up = 0xFF55,
+ XK_Page_Down = 0xFF56,
+ XK_End = 0xFF57,
+ XK_Begin = 0xFF58,
+ XK_Menu = 0xFF67,
+ XK_Shift_L = 0xFFE1,
+ XK_Shift_R = 0xFFE2,
+ XK_Control_L = 0xFFE3,
+ XK_Control_R = 0xFFE4,
+ XK_Caps_Lock = 0xFFE5,
+ XK_Shift_Lock = 0xFFE6,
+ XK_Meta_L = 0xFFE7,
+ XK_Meta_R = 0xFFE8,
+ XK_Alt_L = 0xFFE9,
+ XK_Alt_R = 0xFFEA,
+ XK_Super_L = 0xFFEB,
+ XK_Super_R = 0xFFEC,
+ XK_Hyper_L = 0xFFED,
+ XK_Hyper_R = 0xFFEE,
+ }
+
+ [Flags]
+ internal enum EventMask {
+ NoEventMask = 0,
+ KeyPressMask = 1<<0,
+ KeyReleaseMask = 1<<1,
+ ButtonPressMask = 1<<2,
+ ButtonReleaseMask = 1<<3,
+ EnterWindowMask = 1<<4,
+ LeaveWindowMask = 1<<5,
+ PointerMotionMask = 1<<6,
+ PointerMotionHintMask = 1<<7,
+ Button1MotionMask = 1<<8,
+ Button2MotionMask = 1<<9,
+ Button3MotionMask = 1<<10,
+ Button4MotionMask = 1<<11,
+ Button5MotionMask = 1<<12,
+ ButtonMotionMask = 1<<13,
+ KeymapStateMask = 1<<14,
+ ExposureMask = 1<<15,
+ VisibilityChangeMask = 1<<16,
+ StructureNotifyMask = 1<<17,
+ ResizeRedirectMask = 1<<18,
+ SubstructureNotifyMask = 1<<19,
+ SubstructureRedirectMask= 1<<20,
+ FocusChangeMask = 1<<21,
+ PropertyChangeMask = 1<<22,
+ ColormapChangeMask = 1<<23,
+ OwnerGrabButtonMask = 1<<24
+ }
+
+ internal enum GrabMode {
+ GrabModeSync = 0,
+ GrabModeAsync = 1
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XStandardColormap {
+ internal IntPtr colormap;
+ internal IntPtr red_max;
+ internal IntPtr red_mult;
+ internal IntPtr green_max;
+ internal IntPtr green_mult;
+ internal IntPtr blue_max;
+ internal IntPtr blue_mult;
+ internal IntPtr base_pixel;
+ internal IntPtr visualid;
+ internal IntPtr killid;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack=2)]
+ internal struct XColor {
+ internal IntPtr pixel;
+ internal ushort red;
+ internal ushort green;
+ internal ushort blue;
+ internal byte flags;
+ internal byte pad;
+ }
+
+ internal enum Atom {
+ AnyPropertyType = 0,
+ XA_PRIMARY = 1,
+ XA_SECONDARY = 2,
+ XA_ARC = 3,
+ XA_ATOM = 4,
+ XA_BITMAP = 5,
+ XA_CARDINAL = 6,
+ XA_COLORMAP = 7,
+ XA_CURSOR = 8,
+ XA_CUT_BUFFER0 = 9,
+ XA_CUT_BUFFER1 = 10,
+ XA_CUT_BUFFER2 = 11,
+ XA_CUT_BUFFER3 = 12,
+ XA_CUT_BUFFER4 = 13,
+ XA_CUT_BUFFER5 = 14,
+ XA_CUT_BUFFER6 = 15,
+ XA_CUT_BUFFER7 = 16,
+ XA_DRAWABLE = 17,
+ XA_FONT = 18,
+ XA_INTEGER = 19,
+ XA_PIXMAP = 20,
+ XA_POINT = 21,
+ XA_RECTANGLE = 22,
+ XA_RESOURCE_MANAGER = 23,
+ XA_RGB_COLOR_MAP = 24,
+ XA_RGB_BEST_MAP = 25,
+ XA_RGB_BLUE_MAP = 26,
+ XA_RGB_DEFAULT_MAP = 27,
+ XA_RGB_GRAY_MAP = 28,
+ XA_RGB_GREEN_MAP = 29,
+ XA_RGB_RED_MAP = 30,
+ XA_STRING = 31,
+ XA_VISUALID = 32,
+ XA_WINDOW = 33,
+ XA_WM_COMMAND = 34,
+ XA_WM_HINTS = 35,
+ XA_WM_CLIENT_MACHINE = 36,
+ XA_WM_ICON_NAME = 37,
+ XA_WM_ICON_SIZE = 38,
+ XA_WM_NAME = 39,
+ XA_WM_NORMAL_HINTS = 40,
+ XA_WM_SIZE_HINTS = 41,
+ XA_WM_ZOOM_HINTS = 42,
+ XA_MIN_SPACE = 43,
+ XA_NORM_SPACE = 44,
+ XA_MAX_SPACE = 45,
+ XA_END_SPACE = 46,
+ XA_SUPERSCRIPT_X = 47,
+ XA_SUPERSCRIPT_Y = 48,
+ XA_SUBSCRIPT_X = 49,
+ XA_SUBSCRIPT_Y = 50,
+ XA_UNDERLINE_POSITION = 51,
+ XA_UNDERLINE_THICKNESS = 52,
+ XA_STRIKEOUT_ASCENT = 53,
+ XA_STRIKEOUT_DESCENT = 54,
+ XA_ITALIC_ANGLE = 55,
+ XA_X_HEIGHT = 56,
+ XA_QUAD_WIDTH = 57,
+ XA_WEIGHT = 58,
+ XA_POINT_SIZE = 59,
+ XA_RESOLUTION = 60,
+ XA_COPYRIGHT = 61,
+ XA_NOTICE = 62,
+ XA_FONT_NAME = 63,
+ XA_FAMILY_NAME = 64,
+ XA_FULL_NAME = 65,
+ XA_CAP_HEIGHT = 66,
+ XA_WM_CLASS = 67,
+ XA_WM_TRANSIENT_FOR = 68,
+
+ XA_LAST_PREDEFINED = 68
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XScreen {
+ internal IntPtr ext_data;
+ internal IntPtr display;
+ internal IntPtr root;
+ internal int width;
+ internal int height;
+ internal int mwidth;
+ internal int mheight;
+ internal int ndepths;
+ internal IntPtr depths;
+ internal int root_depth;
+ internal IntPtr root_visual;
+ internal IntPtr default_gc;
+ internal IntPtr cmap;
+ internal IntPtr white_pixel;
+ internal IntPtr black_pixel;
+ internal int max_maps;
+ internal int min_maps;
+ internal int backing_store;
+ internal bool save_unders;
+ internal IntPtr root_input_mask;
+ }
+
+ [Flags]
+ internal enum ChangeWindowFlags {
+ CWX = 1<<0,
+ CWY = 1<<1,
+ CWWidth = 1<<2,
+ CWHeight = 1<<3,
+ CWBorderWidth = 1<<4,
+ CWSibling = 1<<5,
+ CWStackMode = 1<<6
+ }
+
+ internal enum StackMode {
+ Above = 0,
+ Below = 1,
+ TopIf = 2,
+ BottomIf = 3,
+ Opposite = 4
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XWindowChanges {
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal IntPtr sibling;
+ internal StackMode stack_mode;
+ }
+
+ [Flags]
+ internal enum ColorFlags {
+ DoRed = 1<<0,
+ DoGreen = 1<<1,
+ DoBlue = 1<<2
+ }
+
+ internal enum NotifyMode {
+ NotifyNormal = 0,
+ NotifyGrab = 1,
+ NotifyUngrab = 2
+ }
+
+ internal enum NotifyDetail {
+ NotifyAncestor = 0,
+ NotifyVirtual = 1,
+ NotifyInferior = 2,
+ NotifyNonlinear = 3,
+ NotifyNonlinearVirtual = 4,
+ NotifyPointer = 5,
+ NotifyPointerRoot = 6,
+ NotifyDetailNone = 7
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MotifWmHints {
+ internal IntPtr flags;
+ internal IntPtr functions;
+ internal IntPtr decorations;
+ internal IntPtr input_mode;
+ internal IntPtr status;
+
+ public override string ToString ()
+ {
+ return string.Format("MotifWmHints <flags={0}, functions={1}, decorations={2}, input_mode={3}, status={4}", (MotifFlags) flags.ToInt32 (), (MotifFunctions) functions.ToInt32 (), (MotifDecorations) decorations.ToInt32 (), (MotifInputMode) input_mode.ToInt32 (), status.ToInt32 ());
+ }
+ }
+
+ [Flags]
+ internal enum MotifFlags {
+ Functions = 1,
+ Decorations = 2,
+ InputMode = 4,
+ Status = 8
+ }
+
+ [Flags]
+ internal enum MotifFunctions {
+ All = 0x01,
+ Resize = 0x02,
+ Move = 0x04,
+ Minimize = 0x08,
+ Maximize = 0x10,
+ Close = 0x20
+ }
+
+ [Flags]
+ internal enum MotifDecorations {
+ All = 0x01,
+ Border = 0x02,
+ ResizeH = 0x04,
+ Title = 0x08,
+ Menu = 0x10,
+ Minimize = 0x20,
+ Maximize = 0x40,
+
+ }
+
+ [Flags]
+ internal enum MotifInputMode {
+ Modeless = 0,
+ ApplicationModal = 1,
+ SystemModal = 2,
+ FullApplicationModal = 3
+ }
+
+ [Flags]
+ internal enum KeyMasks {
+ ShiftMask = (1 << 0),
+ LockMask = (1 << 1),
+ ControlMask = (1 << 2),
+ Mod1Mask = (1 << 3),
+ Mod2Mask = (1 << 4),
+ Mod3Mask = (1 << 5),
+ Mod4Mask = (1 << 6),
+ Mod5Mask = (1 << 7),
+
+ ModMasks = Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask
+ }
+
+ [Flags]
+ internal enum MouseKeyMasks {
+ Button1Mask = (1 << 8),
+ Button2Mask = (1 << 9),
+ Button3Mask = (1 << 10),
+ Button4Mask = (1 << 11),
+ Button5Mask = (1 << 12),
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct XModifierKeymap {
+ public int max_keypermod;
+ public IntPtr modifiermap;
+ }
+
+ internal enum PropertyMode {
+ Replace = 0,
+ Prepend = 1,
+ Append = 2
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct XKeyBoardState {
+ public int key_click_percent;
+ public int bell_percent;
+ public uint bell_pitch, bell_duration;
+ public IntPtr led_mask;
+ public int global_auto_repeat;
+ public AutoRepeats auto_repeats;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct AutoRepeats {
+ [FieldOffset (0)]
+ public byte first;
+
+ [FieldOffset (31)]
+ public byte last;
+ }
+ }
+
+ [Flags]
+ internal enum GCFunction {
+ GCFunction = 1<<0,
+ GCPlaneMask = 1<<1,
+ GCForeground = 1<<2,
+ GCBackground = 1<<3,
+ GCLineWidth = 1<<4,
+ GCLineStyle = 1<<5,
+ GCCapStyle = 1<<6,
+ GCJoinStyle = 1<<7,
+ GCFillStyle = 1<<8,
+ GCFillRule = 1<<9,
+ GCTile = 1<<10,
+ GCStipple = 1<<11,
+ GCTileStipXOrigin = 1<<12,
+ GCTileStipYOrigin = 1<<13,
+ GCFont = 1<<14,
+ GCSubwindowMode = 1<<15,
+ GCGraphicsExposures = 1<<16,
+ GCClipXOrigin = 1<<17,
+ GCClipYOrigin = 1<<18,
+ GCClipMask = 1<<19,
+ GCDashOffset = 1<<20,
+ GCDashList = 1<<21,
+ GCArcMode = 1<<22
+ }
+
+ internal enum GCJoinStyle {
+ JoinMiter = 0,
+ JoinRound = 1,
+ JoinBevel = 2
+ }
+
+ internal enum GCLineStyle {
+ LineSolid = 0,
+ LineOnOffDash = 1,
+ LineDoubleDash = 2
+ }
+
+ internal enum GCCapStyle {
+ CapNotLast = 0,
+ CapButt = 1,
+ CapRound = 2,
+ CapProjecting = 3
+ }
+
+ internal enum GCFillStyle {
+ FillSolid = 0,
+ FillTiled = 1,
+ FillStippled = 2,
+ FillOpaqueStppled = 3
+ }
+
+ internal enum GCFillRule {
+ EvenOddRule = 0,
+ WindingRule = 1
+ }
+
+ internal enum GCArcMode {
+ ArcChord = 0,
+ ArcPieSlice = 1
+ }
+
+ internal enum GCSubwindowMode {
+ ClipByChildren = 0,
+ IncludeInferiors = 1
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct XGCValues {
+ internal GXFunction function;
+ internal IntPtr plane_mask;
+ internal IntPtr foreground;
+ internal IntPtr background;
+ internal int line_width;
+ internal GCLineStyle line_style;
+ internal GCCapStyle cap_style;
+ internal GCJoinStyle join_style;
+ internal GCFillStyle fill_style;
+ internal GCFillRule fill_rule;
+ internal GCArcMode arc_mode;
+ internal IntPtr tile;
+ internal IntPtr stipple;
+ internal int ts_x_origin;
+ internal int ts_y_origin;
+ internal IntPtr font;
+ internal GCSubwindowMode subwindow_mode;
+ internal bool graphics_exposures;
+ internal int clip_x_origin;
+ internal int clib_y_origin;
+ internal IntPtr clip_mask;
+ internal int dash_offset;
+ internal byte dashes;
+ }
+
+ internal enum GXFunction {
+ GXclear = 0x0, /* 0 */
+ GXand = 0x1, /* src AND dst */
+ GXandReverse = 0x2, /* src AND NOT dst */
+ GXcopy = 0x3, /* src */
+ GXandInverted = 0x4, /* NOT src AND dst */
+ GXnoop = 0x5, /* dst */
+ GXxor = 0x6, /* src XOR dst */
+ GXor = 0x7, /* src OR dst */
+ GXnor = 0x8, /* NOT src AND NOT dst */
+ GXequiv = 0x9, /* NOT src XOR dst */
+ GXinvert = 0xa, /* NOT dst */
+ GXorReverse = 0xb, /* src OR NOT dst */
+ GXcopyInverted = 0xc, /* NOT src */
+ GXorInverted = 0xd, /* NOT src OR dst */
+ GXnand = 0xe, /* NOT src OR NOT dst */
+ GXset = 0xf /* 1 */
+ }
+
+ internal enum NetWindowManagerState {
+ Remove = 0,
+ Add = 1,
+ Toggle = 2
+ }
+
+ internal enum RevertTo {
+ None = 0,
+ PointerRoot = 1,
+ Parent = 2
+ }
+
+ internal enum MapState {
+ IsUnmapped = 0,
+ IsUnviewable = 1,
+ IsViewable = 2
+ }
+
+ internal enum CursorFontShape {
+ XC_X_cursor = 0,
+ XC_arrow = 2,
+ XC_based_arrow_down = 4,
+ XC_based_arrow_up = 6,
+ XC_boat = 8,
+ XC_bogosity = 10,
+ XC_bottom_left_corner = 12,
+ XC_bottom_right_corner = 14,
+ XC_bottom_side = 16,
+ XC_bottom_tee = 18,
+ XC_box_spiral = 20,
+ XC_center_ptr = 22,
+
+ XC_circle = 24,
+ XC_clock = 26,
+ XC_coffee_mug = 28,
+ XC_cross = 30,
+ XC_cross_reverse = 32,
+ XC_crosshair = 34,
+ XC_diamond_cross = 36,
+ XC_dot = 38,
+ XC_dotbox = 40,
+ XC_double_arrow = 42,
+ XC_draft_large = 44,
+ XC_draft_small = 46,
+
+ XC_draped_box = 48,
+ XC_exchange = 50,
+ XC_fleur = 52,
+ XC_gobbler = 54,
+ XC_gumby = 56,
+ XC_hand1 = 58,
+ XC_hand2 = 60,
+ XC_heart = 62,
+ XC_icon = 64,
+ XC_iron_cross = 66,
+ XC_left_ptr = 68,
+ XC_left_side = 70,
+
+ XC_left_tee = 72,
+ XC_left_button = 74,
+ XC_ll_angle = 76,
+ XC_lr_angle = 78,
+ XC_man = 80,
+ XC_middlebutton = 82,
+ XC_mouse = 84,
+ XC_pencil = 86,
+ XC_pirate = 88,
+ XC_plus = 90,
+ XC_question_arrow = 92,
+ XC_right_ptr = 94,
+
+ XC_right_side = 96,
+ XC_right_tee = 98,
+ XC_rightbutton = 100,
+ XC_rtl_logo = 102,
+ XC_sailboat = 104,
+ XC_sb_down_arrow = 106,
+ XC_sb_h_double_arrow = 108,
+ XC_sb_left_arrow = 110,
+ XC_sb_right_arrow = 112,
+ XC_sb_up_arrow = 114,
+ XC_sb_v_double_arrow = 116,
+ XC_sb_shuttle = 118,
+
+ XC_sizing = 120,
+ XC_spider = 122,
+ XC_spraycan = 124,
+ XC_star = 126,
+ XC_target = 128,
+ XC_tcross = 130,
+ XC_top_left_arrow = 132,
+ XC_top_left_corner = 134,
+ XC_top_right_corner = 136,
+ XC_top_side = 138,
+ XC_top_tee = 140,
+ XC_trek = 142,
+
+ XC_ul_angle = 144,
+ XC_umbrella = 146,
+ XC_ur_angle = 148,
+ XC_watch = 150,
+ XC_xterm = 152,
+ XC_num_glyphs = 154
+ }
+
+ internal enum SystrayRequest {
+ SYSTEM_TRAY_REQUEST_DOCK = 0,
+ SYSTEM_TRAY_BEGIN_MESSAGE = 1,
+ SYSTEM_TRAY_CANCEL_MESSAGE = 2
+ }
+
+ internal enum NetWmStateRequest {
+ _NET_WM_STATE_REMOVE = 0,
+ _NET_WM_STATE_ADD = 1,
+ _NET_WM_STATE_TOGGLE = 2
+ }
+
+ internal enum NetWmMoveResize {
+ _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0,
+ _NET_WM_MOVERESIZE_SIZE_TOP = 1,
+ _NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2,
+ _NET_WM_MOVERESIZE_SIZE_RIGHT = 3,
+ _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4,
+ _NET_WM_MOVERESIZE_SIZE_BOTTOM = 5,
+ _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6,
+ _NET_WM_MOVERESIZE_SIZE_LEFT = 7,
+ _NET_WM_MOVERESIZE_MOVE = 8,
+ _NET_WM_MOVERESIZE_SIZE_KEYBOARD = 9,
+ _NET_WM_MOVERESIZE_MOVE_KEYBOARD = 10,
+ _NET_WM_MOVERESIZE_CANCEL = 11
+ }
+
+ [Flags]
+ internal enum XSizeHintsFlags {
+ USPosition = (1 << 0),
+ USSize = (1 << 1),
+ PPosition = (1 << 2),
+ PSize = (1 << 3),
+ PMinSize = (1 << 4),
+ PMaxSize = (1 << 5),
+ PResizeInc = (1 << 6),
+ PAspect = (1 << 7),
+ PAllHints = (PPosition | PSize | PMinSize | PMaxSize | PResizeInc | PAspect),
+ PBaseSize = (1 << 8),
+ PWinGravity = (1 << 9),
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSizeHints {
+ internal IntPtr flags;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int min_width;
+ internal int min_height;
+ internal int max_width;
+ internal int max_height;
+ internal int width_inc;
+ internal int height_inc;
+ internal int min_aspect_x;
+ internal int min_aspect_y;
+ internal int max_aspect_x;
+ internal int max_aspect_y;
+ internal int base_width;
+ internal int base_height;
+ internal int win_gravity;
+ }
+
+ [Flags]
+ internal enum XWMHintsFlags {
+ InputHint = (1 << 0),
+ StateHint = (1 << 1),
+ IconPixmapHint = (1 << 2),
+ IconWindowHint = (1 << 3),
+ IconPositionHint = (1 << 4),
+ IconMaskHint = (1 << 5),
+ WindowGroupHint = (1 << 6),
+ AllHints = (InputHint | StateHint | IconPixmapHint | IconWindowHint | IconPositionHint | IconMaskHint | WindowGroupHint)
+ }
+
+ internal enum XInitialState {
+ DontCareState = 0,
+ NormalState = 1,
+ ZoomState = 2,
+ IconicState = 3,
+ InactiveState = 4
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XWMHints {
+ internal IntPtr flags;
+ internal bool input;
+ internal XInitialState initial_state;
+ internal IntPtr icon_pixmap;
+ internal IntPtr icon_window;
+ internal int icon_x;
+ internal int icon_y;
+ internal IntPtr icon_mask;
+ internal IntPtr window_group;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XIconSize {
+ internal int min_width;
+ internal int min_height;
+ internal int max_width;
+ internal int max_height;
+ internal int width_inc;
+ internal int height_inc;
+ }
+
+ internal struct CaretStruct {
+ internal Timer Timer; // Blink interval
+ internal IntPtr Hwnd; // Window owning the caret
+ internal IntPtr Window; // Actual X11 handle of the window
+ internal int X; // X position of the caret
+ internal int Y; // Y position of the caret
+ internal int Width; // Width of the caret; if no image used
+ internal int Height; // Height of the caret, if no image used
+ internal bool Visible; // Is caret visible?
+ internal bool On; // Caret blink display state: On/Off
+ internal IntPtr gc; // Graphics context
+ internal bool Paused; // Don't update right now
+ }
+
+ internal struct HoverStruct {
+ internal Timer Timer; // for hovering
+ internal IntPtr Window; // Last window we entered; used to generate WM_MOUSEHOVER (handle is X11 handle)
+ internal int X; // Last MouseMove X coordinate; used to generate WM_MOUSEHOVER
+ internal int Y; // Last MouseMove Y coordinate; used to generate WM_MOUSEHOVER
+ internal Size Size; // Size of the rectangle the mouse has to stay in to generate hover
+ internal int Interval; // in milliseconds, how long to hold before hover is generated
+ internal IntPtr Atom; // X Atom
+ }
+
+ internal struct ClickStruct {
+ internal IntPtr Hwnd; //
+ internal Msg Message; //
+ internal IntPtr wParam; //
+ internal IntPtr lParam; //
+ internal long Time; // Last time we received a mouse click
+ internal bool Pending; // True if we haven't sent the last mouse click
+ }
+
+ internal struct GrabStruct {
+ internal bool Confined; // Is the current grab (if any) confined to grab_area?
+ internal IntPtr Hwnd; // The window that is grabbed
+ internal Rectangle Area; // The area the current grab is confined to
+ }
+
+ internal delegate int XErrorHandler(IntPtr DisplayHandle, ref XErrorEvent error_event);
+
+ internal enum XRequest : byte {
+ X_CreateWindow = 1,
+ X_ChangeWindowAttributes = 2,
+ X_GetWindowAttributes = 3,
+ X_DestroyWindow = 4,
+ X_DestroySubwindows = 5,
+ X_ChangeSaveSet = 6,
+ X_ReparentWindow = 7,
+ X_MapWindow = 8,
+ X_MapSubwindows = 9,
+ X_UnmapWindow = 10,
+ X_UnmapSubwindows = 11,
+ X_ConfigureWindow = 12,
+ X_CirculateWindow = 13,
+ X_GetGeometry = 14,
+ X_QueryTree = 15,
+ X_InternAtom = 16,
+ X_GetAtomName = 17,
+ X_ChangeProperty = 18,
+ X_DeleteProperty = 19,
+ X_GetProperty = 20,
+ X_ListProperties = 21,
+ X_SetSelectionOwner = 22,
+ X_GetSelectionOwner = 23,
+ X_ConvertSelection = 24,
+ X_SendEvent = 25,
+ X_GrabPointer = 26,
+ X_UngrabPointer = 27,
+ X_GrabButton = 28,
+ X_UngrabButton = 29,
+ X_ChangeActivePointerGrab = 30,
+ X_GrabKeyboard = 31,
+ X_UngrabKeyboard = 32,
+ X_GrabKey = 33,
+ X_UngrabKey = 34,
+ X_AllowEvents = 35,
+ X_GrabServer = 36,
+ X_UngrabServer = 37,
+ X_QueryPointer = 38,
+ X_GetMotionEvents = 39,
+ X_TranslateCoords = 40,
+ X_WarpPointer = 41,
+ X_SetInputFocus = 42,
+ X_GetInputFocus = 43,
+ X_QueryKeymap = 44,
+ X_OpenFont = 45,
+ X_CloseFont = 46,
+ X_QueryFont = 47,
+ X_QueryTextExtents = 48,
+ X_ListFonts = 49,
+ X_ListFontsWithInfo = 50,
+ X_SetFontPath = 51,
+ X_GetFontPath = 52,
+ X_CreatePixmap = 53,
+ X_FreePixmap = 54,
+ X_CreateGC = 55,
+ X_ChangeGC = 56,
+ X_CopyGC = 57,
+ X_SetDashes = 58,
+ X_SetClipRectangles = 59,
+ X_FreeGC = 60,
+ X_ClearArea = 61,
+ X_CopyArea = 62,
+ X_CopyPlane = 63,
+ X_PolyPoint = 64,
+ X_PolyLine = 65,
+ X_PolySegment = 66,
+ X_PolyRectangle = 67,
+ X_PolyArc = 68,
+ X_FillPoly = 69,
+ X_PolyFillRectangle = 70,
+ X_PolyFillArc = 71,
+ X_PutImage = 72,
+ X_GetImage = 73,
+ X_PolyText8 = 74,
+ X_PolyText16 = 75,
+ X_ImageText8 = 76,
+ X_ImageText16 = 77,
+ X_CreateColormap = 78,
+ X_FreeColormap = 79,
+ X_CopyColormapAndFree = 80,
+ X_InstallColormap = 81,
+ X_UninstallColormap = 82,
+ X_ListInstalledColormaps = 83,
+ X_AllocColor = 84,
+ X_AllocNamedColor = 85,
+ X_AllocColorCells = 86,
+ X_AllocColorPlanes = 87,
+ X_FreeColors = 88,
+ X_StoreColors = 89,
+ X_StoreNamedColor = 90,
+ X_QueryColors = 91,
+ X_LookupColor = 92,
+ X_CreateCursor = 93,
+ X_CreateGlyphCursor = 94,
+ X_FreeCursor = 95,
+ X_RecolorCursor = 96,
+ X_QueryBestSize = 97,
+ X_QueryExtension = 98,
+ X_ListExtensions = 99,
+ X_ChangeKeyboardMapping = 100,
+ X_GetKeyboardMapping = 101,
+ X_ChangeKeyboardWidget = 102,
+ X_GetKeyboardWidget = 103,
+ X_Bell = 104,
+ X_ChangePointerWidget = 105,
+ X_GetPointerWidget = 106,
+ X_SetScreenSaver = 107,
+ X_GetScreenSaver = 108,
+ X_ChangeHosts = 109,
+ X_ListHosts = 110,
+ X_SetAccessWidget = 111,
+ X_SetCloseDownMode = 112,
+ X_KillClient = 113,
+ X_RotateProperties = 114,
+ X_ForceScreenSaver = 115,
+ X_SetPointerMapping = 116,
+ X_GetPointerMapping = 117,
+ X_SetModifierMapping = 118,
+ X_GetModifierMapping = 119,
+ X_NoOperation = 127
+ }
+
+ [Flags]
+ internal enum XIMProperties {
+ XIMPreeditArea = 0x0001,
+ XIMPreeditCallbacks = 0x0002,
+ XIMPreeditPosition = 0x0004,
+ XIMPreeditNothing = 0x0008,
+ XIMPreeditNone = 0x0010,
+ XIMStatusArea = 0x0100,
+ XIMStatusCallbacks = 0x0200,
+ XIMStatusNothing = 0x0400,
+ XIMStatusNone = 0x0800,
+ }
+
+ [Flags]
+ internal enum WindowType {
+ Client = 1,
+ Whole = 2,
+ Both = 3
+ }
+
+ internal enum XEmbedMessage {
+ EmbeddedNotify = 0,
+ WindowActivate = 1,
+ WindowDeactivate = 2,
+ RequestFocus = 3,
+ FocusIn = 4,
+ FocusOut = 5,
+ FocusNext = 6,
+ FocusPrev = 7,
+ /* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
+ ModalityOn = 10,
+ ModalityOff = 11,
+ RegisterAccelerator = 12,
+ UnregisterAccelerator = 13,
+ ActivateAccelerator = 14
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct XcursorImage
+ {
+ private int version;
+ public int size; /* nominal size for matching */
+ public int width; /* actual width */
+ public int height; /* actual height */
+ public int xhot; /* hot spot x (must be inside image) */
+ public int yhot; /* hot spot y (must be inside image) */
+ public int delay; /* hot spot y (must be inside image) */
+ public IntPtr pixels; /* pointer to pixels */
+
+ public override string ToString ()
+ {
+ return string.Format ("XCursorImage (version: {0}, size: {1}, width: {2}, height: {3}, xhot: {4}, yhot: {5}, delay: {6}, pixels: {7}",
+ version, size, width, height, xhot, yhot, delay, pixels);
+ }
+ } ;
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct XcursorImages
+ {
+ public int nimage; /* number of images */
+ public IntPtr images; /* array of XcursorImage pointers */
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct XIMStyles
+ {
+ public ushort count_styles;
+ public IntPtr supported_styles;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ [Serializable]
+ internal class XPoint
+ {
+ public short X;
+ public short Y;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ [Serializable]
+ internal class XIMCallback
+ {
+ public IntPtr client_data;
+ public XIMProc callback;
+ [NonSerialized]
+ GCHandle gch;
+
+ public XIMCallback (IntPtr clientData, XIMProc proc)
+ {
+ this.client_data = clientData;
+ this.gch = GCHandle.Alloc (proc);
+ this.callback = proc;
+ }
+
+ ~XIMCallback ()
+ {
+ gch.Free ();
+ }
+ }
+
+ internal enum XIMFeedback
+ {
+ Reverse = 1,
+ Underline = 2,
+ Highlight = 4,
+ Primary = 32,
+ Secondary = 64,
+ Tertiary = 128,
+ }
+
+ internal struct XIMFeedbackStruct
+ {
+ public byte FeedbackMask; // one or more of XIMFeedback enum
+ }
+
+ internal struct XIMText
+ {
+ public ushort Length;
+ public IntPtr Feedback; // to XIMFeedbackStruct
+ public bool EncodingIsWChar;
+ public IntPtr String; // it could be either char* or wchar_t*
+ }
+
+ internal struct XIMPreeditDrawCallbackStruct
+ {
+ public int Caret;
+ public int ChangeFirst;
+ public int ChangeLength;
+ public IntPtr Text; // to XIMText
+ }
+
+ internal enum XIMCaretDirection
+ {
+ XIMForwardChar,
+ XIMBackwardChar,
+ XIMForwardWord,
+ XIMBackwardWord,
+ XIMCaretUp,
+ XIMCaretDown,
+ XIMNextLine,
+ XIMPreviousLine,
+ XIMLineStart,
+ XIMLineEnd,
+ XIMAbsolutePosition,
+ XIMDontChange
+ }
+
+ internal enum XIMCaretStyle
+ {
+ IsInvisible,
+ IsPrimary,
+ IsSecondary
+ }
+
+ internal struct XIMPreeditCaretCallbackStruct
+ {
+ public int Position;
+ public XIMCaretDirection Direction;
+ public XIMCaretStyle Style;
+ }
+
+ // only PreeditStartCallback requires return value though.
+ internal delegate int XIMProc (IntPtr xim, IntPtr clientData, IntPtr callData);
+
+ internal static class XNames
+ {
+ public const string XNVaNestedList = "XNVaNestedList";
+ public const string XNQueryInputStyle = "queryInputStyle";
+ public const string XNClientWindow = "clientWindow";
+ public const string XNInputStyle = "inputStyle";
+ public const string XNFocusWindow = "focusWindow";
+
+ // XIMPreeditCallbacks delegate names.
+ public const string XNPreeditStartCallback = "preeditStartCallback";
+ public const string XNPreeditDoneCallback = "preeditDoneCallback";
+ public const string XNPreeditDrawCallback = "preeditDrawCallback";
+ public const string XNPreeditCaretCallback = "preeditCaretCallback";
+ public const string XNPreeditStateNotifyCallback = "preeditStateNotifyCallback";
+ public const string XNPreeditAttributes = "preeditAttributes";
+ // XIMStatusCallbacks delegate names.
+ public const string XNStatusStartCallback = "statusStartCallback";
+ public const string XNStatusDoneCallback = "statusDoneCallback";
+ public const string XNStatusDrawCallback = "statusDrawCallback";
+ public const string XNStatusAttributes = "statusAttributes";
+
+ public const string XNArea = "area";
+ public const string XNAreaNeeded = "areaNeeded";
+ public const string XNSpotLocation = "spotLocation";
+ public const string XNFontSet = "fontSet";
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct XineramaScreenInfo
+ {
+ public int screen_number;
+ public short x_org;
+ public short y_org;
+ public short width;
+ public short height;
+ }
+}
diff --git a/source/ShiftUI/Internal/X11ThreadQueue.cs b/source/ShiftUI/Internal/X11ThreadQueue.cs
new file mode 100644
index 0000000..b68d74c
--- /dev/null
+++ b/source/ShiftUI/Internal/X11ThreadQueue.cs
@@ -0,0 +1,502 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+// Peter Dennis Bartok ([email protected])
+// Chris Toshok ([email protected])
+//
+
+using System;
+using System.Threading;
+using System.Collections;
+
+namespace ShiftUI.X11Internal {
+
+ internal class X11ThreadQueue {
+
+ XEventQueue xqueue;
+ PaintQueue paint_queue;
+ ConfigureQueue configure_queue;
+ ArrayList timer_list;
+ Thread thread;
+ bool quit_posted;
+ bool dispatch_idle;
+ bool need_dispatch_idle = true;
+ object lockobj = new object ();
+
+ static readonly int InitialXEventQueueSize = 128;
+ static readonly int InitialHwndQueueSize = 50;
+
+ public X11ThreadQueue (Thread thread)
+ {
+ xqueue = new XEventQueue (InitialXEventQueueSize);
+ paint_queue = new PaintQueue (InitialHwndQueueSize);
+ configure_queue = new ConfigureQueue (InitialHwndQueueSize);
+ timer_list = new ArrayList ();
+ this.thread = thread;
+ this.quit_posted = false;
+ this.dispatch_idle = true;
+ }
+
+ public int CountUnlocked {
+ get { return xqueue.Count + paint_queue.Count; }
+ }
+
+ public Thread Thread {
+ get { return thread; }
+ }
+
+ public void EnqueueUnlocked (XEvent xevent)
+ {
+ switch (xevent.type) {
+ case XEventName.KeyPress:
+ case XEventName.KeyRelease:
+ case XEventName.ButtonPress:
+ case XEventName.ButtonRelease:
+ NeedDispatchIdle = true;
+ break;
+ case XEventName.MotionNotify:
+ if (xqueue.Count > 0) {
+ XEvent peek = xqueue.Peek ();
+ if (peek.AnyEvent.type == XEventName.MotionNotify)
+ return; // we've already got a pending motion notify.
+ }
+
+ // otherwise fall through and enqueue
+ // the event.
+ break;
+ }
+
+ xqueue.Enqueue (xevent);
+ // wake up any thread blocking in DequeueUnlocked
+ Monitor.PulseAll (lockobj);
+ }
+
+ public void Enqueue (XEvent xevent)
+ {
+ lock (lockobj) {
+ EnqueueUnlocked (xevent);
+ }
+ }
+
+ public bool Dequeue (out XEvent xevent)
+ {
+ StartOver:
+ bool got_xevent = false;
+
+ lock (lockobj) {
+ if (xqueue.Count > 0) {
+ got_xevent = true;
+ xevent = xqueue.Dequeue ();
+ }
+ else
+ xevent = new XEvent (); /* not strictly needed, but mcs complains */
+ }
+
+ if (got_xevent) {
+ if (xevent.AnyEvent.type == XEventName.Expose) {
+#if spew
+ Console.Write ("E");
+ Console.Out.Flush ();
+#endif
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
+ hwnd.AddExpose (xevent.AnyEvent.window == hwnd.ClientWindow,
+ xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+ xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ goto StartOver;
+ }
+ else if (xevent.AnyEvent.type == XEventName.ConfigureNotify) {
+#if spew
+ Console.Write ("C");
+ Console.Out.Flush ();
+#endif
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
+ hwnd.AddConfigureNotify (xevent);
+ goto StartOver;
+ }
+ else {
+#if spew
+ Console.Write ("X");
+ Console.Out.Flush ();
+#endif
+ /* it was an event we can deal with directly, return it */
+ return true;
+ }
+ }
+ else {
+ if (paint_queue.Count > 0) {
+ xevent = paint_queue.Dequeue ();
+#if spew
+ Console.Write ("e");
+ Console.Out.Flush ();
+#endif
+ return true;
+ }
+ else if (configure_queue.Count > 0) {
+ xevent = configure_queue.Dequeue ();
+#if spew
+ Console.Write ("c");
+ Console.Out.Flush ();
+#endif
+ return true;
+ }
+ }
+
+ if (dispatch_idle && need_dispatch_idle) {
+ OnIdle (EventArgs.Empty);
+ need_dispatch_idle = false;
+ }
+
+ lock (lockobj) {
+ if (CountUnlocked > 0)
+ goto StartOver;
+
+ if (Monitor.Wait (lockobj, NextTimeout (), true)) {
+ // the lock was reaquired before the
+ // timeout. meaning an event was
+ // enqueued by X11Display.XEventThread.
+ goto StartOver;
+ }
+ else {
+ CheckTimers ();
+ return false;
+ }
+ }
+ }
+
+ public void RemovePaint (Hwnd hwnd)
+ {
+ paint_queue.Remove (hwnd);
+ }
+
+ public void AddPaint (Hwnd hwnd)
+ {
+ paint_queue.Enqueue (hwnd);
+ }
+
+ public void AddConfigure (Hwnd hwnd)
+ {
+ configure_queue.Enqueue (hwnd);
+ }
+
+ public ConfigureQueue Configure {
+ get { return configure_queue; }
+ }
+
+ public PaintQueue Paint {
+ get { return paint_queue; }
+ }
+
+ public void Lock ()
+ {
+ Monitor.Enter (lockobj);
+ }
+
+ public void Unlock ()
+ {
+ Monitor.Exit (lockobj);
+ }
+
+ private int NextTimeout ()
+ {
+ int timeout = Int32.MaxValue;
+ DateTime now = DateTime.UtcNow;
+
+ foreach (Timer timer in timer_list) {
+ int next = (int) (timer.Expires - now).TotalMilliseconds;
+ if (next < 0)
+ return 0; // Have a timer that has already expired
+
+ if (next < timeout)
+ timeout = next;
+ }
+
+ if (timeout < Timer.Minimum) {
+ timeout = Timer.Minimum;
+ }
+
+ if (timeout == Int32.MaxValue)
+ timeout = Timeout.Infinite;
+
+ return timeout;
+ }
+
+ public void CheckTimers ()
+ {
+ int count;
+ DateTime now = DateTime.UtcNow;
+
+ count = timer_list.Count;
+
+ if (count == 0)
+ return;
+
+ for (int i = 0; i < timer_list.Count; i++) {
+ Timer timer;
+
+ timer = (Timer) timer_list [i];
+
+ if (timer.Enabled && timer.Expires <= now) {
+ timer.Update (now);
+ timer.FireTick ();
+ }
+ }
+ }
+
+ public void SetTimer (Timer timer)
+ {
+ lock (lockobj) {
+ timer_list.Add (timer);
+
+ // we need to wake up any thread waiting in DequeueUnlocked,
+ // since it might need to wait for a different amount of time.
+ Monitor.PulseAll (lockobj);
+ }
+
+ }
+
+ public void KillTimer (Timer timer)
+ {
+ lock (lockobj) {
+ timer_list.Remove (timer);
+
+ // we need to wake up any thread waiting in DequeueUnlocked,
+ // since it might need to wait for a different amount of time.
+ Monitor.PulseAll (lockobj);
+ }
+ }
+
+ public event EventHandler Idle;
+ public void OnIdle (EventArgs e)
+ {
+ if (Idle != null)
+ Idle (thread, e);
+ }
+
+ public bool NeedDispatchIdle {
+ get { return need_dispatch_idle; }
+ set { need_dispatch_idle = value; }
+ }
+
+ public bool DispatchIdle {
+ get { return dispatch_idle; }
+ set { dispatch_idle = value; }
+ }
+
+ public bool PostQuitState {
+ get { return quit_posted; }
+ set { quit_posted = value; }
+ }
+
+ public abstract class HwndEventQueue {
+ protected ArrayList hwnds;
+#if DebugHwndEventQueue
+ protected ArrayList stacks;
+#endif
+ public HwndEventQueue (int size)
+ {
+ hwnds = new ArrayList (size);
+#if DebugHwndEventQueue
+ stacks = new ArrayList (size);
+#endif
+ }
+
+ public int Count {
+ get { return hwnds.Count; }
+ }
+
+ public void Enqueue (Hwnd hwnd)
+ {
+ if (hwnds.Contains (hwnd)) {
+#if DebugHwndEventQueue
+ Console.WriteLine ("hwnds can only appear in the queue once.");
+ Console.WriteLine (Environment.StackTrace);
+ Console.WriteLine ("originally added here:");
+ Console.WriteLine (stacks[hwnds.IndexOf (hwnd)]);
+#endif
+
+ return;
+ }
+ hwnds.Add(hwnd);
+#if DebugHwndEventQueue
+ stacks.Add(Environment.StackTrace);
+#endif
+ }
+
+ public void Remove(Hwnd hwnd)
+ {
+#if DebugHwndEventQueue
+ int index = hwnds.IndexOf(hwnd);
+ if (index != -1)
+ stacks.RemoveAt(index);
+#endif
+ hwnds.Remove(hwnd);
+ }
+
+ protected abstract XEvent Peek ();
+
+ public virtual XEvent Dequeue ()
+ {
+ if (hwnds.Count == 0)
+ throw new Exception ("Attempt to dequeue empty queue.");
+
+ return Peek ();
+ }
+ }
+
+
+ public class ConfigureQueue : HwndEventQueue
+ {
+ public ConfigureQueue (int size) : base (size)
+ {
+ }
+
+ protected override XEvent Peek ()
+ {
+ X11Hwnd hwnd = (X11Hwnd)hwnds[0];
+
+ XEvent xevent = new XEvent ();
+ xevent.AnyEvent.type = XEventName.ConfigureNotify;
+
+ xevent.ConfigureEvent.window = hwnd.ClientWindow;
+ xevent.ConfigureEvent.x = hwnd.X;
+ xevent.ConfigureEvent.y = hwnd.Y;
+ xevent.ConfigureEvent.width = hwnd.Width;
+ xevent.ConfigureEvent.height = hwnd.Height;
+
+ return xevent;
+ }
+
+ public override XEvent Dequeue ()
+ {
+ XEvent xev = base.Dequeue ();
+
+
+ hwnds.RemoveAt(0);
+#if DebugHwndEventQueue
+ stacks.RemoveAt(0);
+#endif
+
+ return xev;
+ }
+ }
+
+ public class PaintQueue : HwndEventQueue
+ {
+ public PaintQueue (int size) : base (size)
+ {
+ }
+
+ protected override XEvent Peek ()
+ {
+ X11Hwnd hwnd = (X11Hwnd)hwnds[0];
+
+ XEvent xevent = new XEvent ();
+
+ xevent.AnyEvent.type = XEventName.Expose;
+
+ if (hwnd.PendingExpose) {
+ xevent.ExposeEvent.window = hwnd.ClientWindow;
+ } else {
+ xevent.ExposeEvent.window = hwnd.WholeWindow;
+ xevent.ExposeEvent.x = hwnd.nc_invalid.X;
+ xevent.ExposeEvent.y = hwnd.nc_invalid.Y;
+ xevent.ExposeEvent.width = hwnd.nc_invalid.Width;
+ xevent.ExposeEvent.height = hwnd.nc_invalid.Height;
+ }
+
+ return xevent;
+ }
+
+ // don't override Dequeue like ConfigureQueue does.
+ }
+
+ /* a circular queue for holding X events for processing by GetMessage */
+ private class XEventQueue {
+
+ XEvent[] xevents;
+ int head;
+ int tail;
+ int size;
+
+ public XEventQueue (int initial_size)
+ {
+ if (initial_size % 2 != 0)
+ throw new Exception ("XEventQueue must be a power of 2 size");
+
+ xevents = new XEvent [initial_size];
+ }
+
+ public int Count {
+ get { return size; }
+ }
+
+ public void Enqueue (XEvent xevent)
+ {
+ if (size == xevents.Length)
+ Grow ();
+
+ xevents [tail] = xevent;
+ tail = (tail + 1) & (xevents.Length - 1);
+ size++;
+ }
+
+ public XEvent Dequeue ()
+ {
+ if (size < 1)
+ throw new Exception ("Attempt to dequeue empty queue.");
+
+ XEvent res = xevents [head];
+ head = (head + 1) & (xevents.Length - 1);
+ size--;
+ return res;
+ }
+
+ public XEvent Peek()
+ {
+ if (size < 1)
+ throw new Exception ("Attempt to peek at empty queue.");
+
+ return xevents[head];
+ }
+
+ private void Grow ()
+ {
+ int newcap = (xevents.Length * 2);
+ XEvent [] na = new XEvent [newcap];
+
+ if (head + size > xevents.Length) {
+ Array.Copy (xevents, head, na, 0, xevents.Length - head);
+ Array.Copy (xevents, 0, na, xevents.Length - head, head + size - xevents.Length);
+ }
+ else {
+ Array.Copy (xevents, head, na, 0, size);
+ }
+
+ xevents = na;
+ head = 0;
+ tail = head + size;
+ }
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/XEventQueue.cs b/source/ShiftUI/Internal/XEventQueue.cs
new file mode 100644
index 0000000..526c14c
--- /dev/null
+++ b/source/ShiftUI/Internal/XEventQueue.cs
@@ -0,0 +1,261 @@
+// 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-2006 Novell, Inc.
+//
+// ShiftUI.XEventQueue
+//
+// Authors:
+// Jackson Harper ([email protected])
+// Peter Dennis Bartok ([email protected])
+//
+
+using System;
+using System.Threading;
+using System.Collections;
+
+namespace ShiftUI {
+
+ internal class XEventQueue {
+
+ private XQueue xqueue;
+ private XQueue lqueue; // Events inserted from threads other then the main X thread
+ private PaintQueue paint; // Paint-only queue
+ internal ArrayList timer_list;
+ private Thread thread;
+ private bool dispatch_idle;
+
+ private static readonly int InitialXEventSize = 100;
+ private static readonly int InitialLXEventSize = 10;
+ private static readonly int InitialPaintSize = 50;
+
+ public XEventQueue (Thread thread) {
+ xqueue = new XQueue (InitialXEventSize);
+ lqueue = new XQueue (InitialLXEventSize);
+ paint = new PaintQueue(InitialPaintSize);
+ timer_list = new ArrayList ();
+ this.thread = thread;
+ this.dispatch_idle = true;
+ }
+
+ public int Count {
+ get {
+ lock (lqueue) {
+ return xqueue.Count + lqueue.Count;
+ }
+ }
+ }
+
+ public PaintQueue Paint {
+ get {
+ return paint;
+ }
+ }
+
+ public Thread Thread {
+ get {
+ return thread;
+ }
+ }
+
+ public void Enqueue (XEvent xevent)
+ {
+ if (Thread.CurrentThread != thread) {
+ Console.WriteLine ("Hwnd.Queue.Enqueue called from a different thread without locking.");
+ Console.WriteLine (Environment.StackTrace);
+ }
+
+ xqueue.Enqueue (xevent);
+ }
+
+ public void EnqueueLocked (XEvent xevent)
+ {
+ lock (lqueue) {
+ lqueue.Enqueue (xevent);
+ }
+ }
+
+ public XEvent Dequeue ()
+ {
+ if (Thread.CurrentThread != thread) {
+ Console.WriteLine ("Hwnd.Queue.Dequeue called from a different thread without locking.");
+ Console.WriteLine (Environment.StackTrace);
+ }
+
+ if (xqueue.Count == 0) {
+ lock (lqueue) {
+ return lqueue.Dequeue ();
+ }
+ }
+ return xqueue.Dequeue ();
+ }
+
+ public XEvent Peek()
+ {
+ if (Thread.CurrentThread != thread) {
+ Console.WriteLine ("Hwnd.Queue.Peek called from a different thread without locking.");
+ Console.WriteLine (Environment.StackTrace);
+ }
+
+ if (xqueue.Count == 0) {
+ lock (lqueue) {
+ return lqueue.Peek ();
+ }
+ }
+ return xqueue.Peek ();
+ }
+
+ public bool DispatchIdle {
+ get {
+ return dispatch_idle;
+ }
+ set {
+ dispatch_idle = value;
+ }
+ }
+
+ public class PaintQueue {
+
+ private ArrayList hwnds;
+ private XEvent xevent;
+
+ public PaintQueue (int size) {
+ hwnds = new ArrayList (size);
+ xevent = new XEvent ();
+ xevent.AnyEvent.type = XEventName.Expose;
+ }
+
+ public int Count {
+ get {
+ lock (hwnds) {
+ return hwnds.Count;
+ }
+ }
+ }
+
+ public void Enqueue (Hwnd hwnd) {
+ lock (hwnds) {
+ hwnds.Add (hwnd);
+ }
+ }
+
+ public void Remove(Hwnd hwnd) {
+ if (!hwnd.expose_pending && !hwnd.nc_expose_pending) {
+ lock (hwnds) {
+ hwnds.Remove (hwnd);
+ }
+ }
+ }
+
+ public XEvent Dequeue () {
+ Hwnd hwnd;
+ IEnumerator next;
+
+ lock (hwnds) {
+ if (hwnds.Count == 0) {
+ xevent.ExposeEvent.window = IntPtr.Zero;
+ return xevent;
+ }
+
+ next = hwnds.GetEnumerator ();
+ next.MoveNext ();
+ hwnd = (Hwnd)next.Current;
+
+ // We only remove the event from the queue if we have one expose left since
+ // a single 'entry in our queue may be for both NC and Client exposed
+ if (!(hwnd.nc_expose_pending && hwnd.expose_pending)) {
+ hwnds.Remove (hwnd);
+ }
+ if (hwnd.expose_pending) {
+ xevent.ExposeEvent.window = hwnd.client_window;
+#if not
+ xevent.ExposeEvent.x = hwnd.invalid.X;
+ xevent.ExposeEvent.y = hwnd.invalid.Y;
+ xevent.ExposeEvent.width = hwnd.invalid.Width;
+ xevent.ExposeEvent.height = hwnd.invalid.Height;
+#endif
+ return xevent;
+ } else {
+ xevent.ExposeEvent.window = hwnd.whole_window;
+ xevent.ExposeEvent.x = hwnd.nc_invalid.X;
+ xevent.ExposeEvent.y = hwnd.nc_invalid.Y;
+ xevent.ExposeEvent.width = hwnd.nc_invalid.Width;
+ xevent.ExposeEvent.height = hwnd.nc_invalid.Height;
+ return xevent;
+ }
+ }
+ }
+ }
+
+ private class XQueue {
+
+ private XEvent [] xevents;
+ private int head;
+ private int tail;
+ private int size;
+
+ public XQueue (int size)
+ {
+ xevents = new XEvent [size];
+ }
+
+ public int Count {
+ get { return size; }
+ }
+
+ public void Enqueue (XEvent xevent)
+ {
+ if (size == xevents.Length)
+ Grow ();
+
+ xevents [tail] = xevent;
+ tail = (tail + 1) % xevents.Length;
+ size++;
+ }
+
+ public XEvent Dequeue ()
+ {
+ if (size < 1)
+ throw new Exception ("Attempt to dequeue empty queue.");
+ XEvent res = xevents [head];
+ head = (head + 1) % xevents.Length;
+ size--;
+ return res;
+ }
+
+ public XEvent Peek() {
+ if (size < 1) {
+ throw new Exception ("Attempt to peek at empty queue");
+ }
+ return xevents[head];
+ }
+
+ private void Grow ()
+ {
+ int newcap = (xevents.Length * 2);
+ XEvent [] na = new XEvent [newcap];
+ xevents.CopyTo (na, 0);
+ xevents = na;
+ head = 0;
+ tail = head + size;
+ }
+ }
+ }
+}
+
diff --git a/source/ShiftUI/Internal/Xlib.cs b/source/ShiftUI/Internal/Xlib.cs
new file mode 100644
index 0000000..5eebd7e
--- /dev/null
+++ b/source/ShiftUI/Internal/Xlib.cs
@@ -0,0 +1,350 @@
+// 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) 2006 Novell, Inc. (http://www.novell.com)
+//
+//
+
+using System;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI.X11Internal {
+
+ internal class Xlib {
+ const string libX11 = "X11";
+
+ [DllImport (libX11)]
+ public extern static IntPtr XOpenDisplay(IntPtr display);
+
+ [DllImport (libX11)]
+ public extern static int XCloseDisplay(IntPtr display);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XSynchronize(IntPtr display, bool onoff);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
+
+ [DllImport (libX11)]
+ public extern static int XMapWindow(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static int XUnmapWindow(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static int XMapSubindows(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XRootWindow(IntPtr display, int screen_number);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
+
+ [DllImport (libX11)]
+ public extern static int XConnectionNumber (IntPtr diplay);
+
+ [DllImport (libX11)]
+ public extern static int XPending (IntPtr diplay);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
+
+ [DllImport (libX11)]
+ public extern static int XDestroyWindow(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
+
+ [DllImport (libX11)]
+ public extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+
+ [DllImport (libX11)]
+ public extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
+
+ [DllImport (libX11)]
+ public extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
+
+ [DllImport (libX11)]
+ public extern static int XFlush(IntPtr display);
+
+ [DllImport (libX11)]
+ public extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
+
+ [DllImport (libX11)]
+ public extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
+
+ [DllImport (libX11)]
+ public extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
+
+ [DllImport (libX11)]
+ public extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
+
+ [DllImport (libX11)]
+ public extern static int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return);
+
+ [DllImport (libX11)]
+ public extern static int XFree(IntPtr data);
+
+ [DllImport (libX11)]
+ public extern static int XRaiseWindow(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static uint XLowerWindow(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
+
+ [DllImport (libX11)]
+ public extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
+
+ [DllImport (libX11)]
+ public extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
+
+ [DllImport (libX11)]
+ public extern static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp);
+
+ [DllImport (libX11)]
+ public extern static int XUngrabPointer(IntPtr display, IntPtr timestamp);
+
+ [DllImport (libX11)]
+ public extern static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons);
+
+ [DllImport (libX11)]
+ public extern static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return);
+
+ [DllImport (libX11)]
+ public extern static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth);
+
+ [DllImport (libX11)]
+ public extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth);
+
+ [DllImport (libX11)]
+ public extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth);
+
+ [DllImport (libX11)]
+ public extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth);
+
+ [DllImport (libX11)]
+ public extern static uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y);
+
+ [DllImport (libX11)]
+ public extern static int XClearWindow(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
+
+ // Colormaps
+ [DllImport (libX11)]
+ public extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
+
+ [DllImport (libX11)]
+ public extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
+
+ [DllImport (libX11)]
+ public extern static uint XDefaultDepth(IntPtr display, int screen_number);
+
+ [DllImport (libX11)]
+ public extern static int XDefaultScreen(IntPtr display);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
+
+ [DllImport (libX11)]
+ public extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
+
+ [DllImport (libX11)]
+ public extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
+
+ [DllImport (libX11)]
+ public extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
+
+ [DllImport (libX11)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
+
+ [DllImport (libX11)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
+
+ [DllImport (libX11)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
+
+ [DllImport (libX11)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
+
+ [DllImport (libX11)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
+
+ [DllImport (libX11)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
+
+ [DllImport (libX11)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
+
+ [DllImport (libX11, CharSet=CharSet.Ansi)]
+ public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
+
+ [DllImport (libX11)]
+ public extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
+
+ // Drawing
+ [DllImport (libX11)]
+ public extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
+
+ [DllImport (libX11)]
+ public extern static int XFreeGC(IntPtr display, IntPtr gc);
+
+ [DllImport (libX11)]
+ public extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
+
+ [DllImport (libX11)]
+ internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
+
+ [DllImport (libX11)]
+ public extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
+
+ [DllImport (libX11)]
+ public extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
+
+ [DllImport (libX11)]
+ public extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
+
+ [DllImport (libX11)]
+ public extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
+
+ [DllImport (libX11)]
+ public extern static int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
+
+ [DllImport (libX11)]
+ public extern static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop);
+
+ [DllImport (libX11)]
+ public extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
+
+ [DllImport (libX11)]
+ public extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
+
+ [DllImport (libX11)]
+ public extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
+
+ [DllImport (libX11)]
+ public extern static int XUndefineCursor(IntPtr display, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static int XFreeCursor(IntPtr display, IntPtr cursor);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
+
+ [DllImport (libX11)]
+ public extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
+
+ [DllImport (libX11)]
+ public extern static void XGrabServer(IntPtr display);
+
+ [DllImport (libX11)]
+ public extern static void XUngrabServer(IntPtr display);
+
+ [DllImport (libX11)]
+ public extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
+
+ [DllImport (libX11)]
+ public extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport (libX11)]
+ public extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport (libX11)]
+ public extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
+
+ [DllImport (libX11)]
+ public extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
+
+ [DllImport (libX11)]
+ public extern static int XInitThreads();
+
+ [DllImport (libX11)]
+ public extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
+
+ [DllImport (libX11)]
+ public extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
+
+ [DllImport (libX11)]
+ public extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
+
+ [DllImport (libX11)]
+ public extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
+
+ [DllImport (libX11)]
+ public extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
+
+ [DllImport (libX11)]
+ public extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
+
+ [DllImport (libX11)]
+ public extern static int XBell(IntPtr display, int percent);
+
+ [DllImport (libX11)]
+ public extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
+
+ [DllImport (libX11)]
+ public extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
+
+ [DllImport (libX11)]
+ public extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
+
+ [DllImport (libX11)]
+ public extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
+ }
+}
diff --git a/source/ShiftUI/Internal/XplatUI.cs b/source/ShiftUI/Internal/XplatUI.cs
new file mode 100644
index 0000000..afa3ddb
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUI.cs
@@ -0,0 +1,1235 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+
+// NOT COMPLETE
+
+// define to log API calls to stdout
+#undef DriverDebug
+#undef DriverDebugPaint
+#undef DriverDebugCreate
+#undef DriverDebugDestroy
+#undef DriverDebugState
+
+using System;
+using System.Drawing;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace ShiftUI {
+ internal class XplatUI {
+ #region Local Variables
+ static XplatUIDriver driver;
+ //static String default_class_name;
+ internal static ArrayList key_filters = new ArrayList ();
+ #endregion // Local Variables
+
+ public static string DefaultClassName {
+ get { return GetDefaultClassName(); }
+ }
+
+ #region Private Methods
+ internal static string Window (IntPtr handle)
+ {
+ return String.Format ("'{0}' ({1:X})", Widget.FromHandle (handle), handle.ToInt32 ());
+ }
+
+ [Conditional ("DriverDebug")]
+ static void DriverDebug (string format, params object [] args)
+ {
+ Console.WriteLine (String.Format (format, args));
+ }
+
+ #endregion // Private Methods
+
+ #region Subclasses
+ public class State {
+ static public Keys ModifierKeys {
+ get {
+ return driver.ModifierKeys;
+ }
+ }
+
+ static public MouseButtons MouseButtons {
+ get {
+ return driver.MouseButtons;
+ }
+ }
+
+ static public Point MousePosition {
+ get {
+ return driver.MousePosition;
+ }
+ }
+
+ }
+ #endregion // Subclasses
+
+ #region Constructor & Destructor
+ static XplatUI ()
+ {
+ // Compose name with current domain id because on Win32 we register class name
+ // and name must be unique to process. If we load MWF into multiple appdomains
+ // and try to register same class name we fail.
+ //default_class_name = "SWFClass" + System.Threading.Thread.GetDomainID ().ToString ();
+ try {
+ if (RunningOnUnix) {
+ //if (Environment.GetEnvironmentVariable ("not_supported_MONO_MWF_USE_NEW_X11_BACKEND") != null) {
+ // driver=XplatUIX11_new.GetInstance ();
+ //} else
+ if (Environment.GetEnvironmentVariable ("MONO_MWF_MAC_FORCE_X11") != null) {
+ driver = XplatUIX11.GetInstance ();
+ } else {
+ IntPtr buf = Marshal.AllocHGlobal (8192);
+ // This is a hacktastic way of getting sysname from uname ()
+ if (uname (buf) != 0) {
+ // WTF: We cannot run uname
+ driver=XplatUIX11.GetInstance ();
+ } else {
+ string os = Marshal.PtrToStringAnsi (buf);
+ if (os == "Darwin")
+ driver=XplatUICarbon.GetInstance ();
+ else
+ driver=XplatUIX11.GetInstance ();
+ }
+ Marshal.FreeHGlobal (buf);
+ }
+ } else {
+ driver=XplatUIWin32.GetInstance ();
+ }
+
+ driver.InitializeDriver ();
+
+ // Initialize things that need to be done after the driver is ready
+ DataFormats.GetFormat (0);
+
+ // Signal that the Application loop can be run.
+ // This allows UIA to initialize a11y support for MWF
+ // before the main loop begins.
+ Application.FirePreRun ();
+ }
+ catch (Exception ex) {
+ Console.WriteLine ("[ShiftUI/XplatUI] Driver init error: {0}", ex.Message);
+ }
+ }
+ #endregion // Constructor & Destructor
+
+ #region Public Static Properties
+
+ public static bool RunningOnUnix {
+ get {
+ int p = (int) Environment.OSVersion.Platform;
+
+ return (p == 4 || p == 6 || p == 128);
+ }
+ }
+
+ public static int ActiveWindowTrackingDelay {
+ get { return driver.ActiveWindowTrackingDelay; }
+ }
+
+ // Compose name with current domain id because on Win32 we register class name
+ // and name must be unique to process. If we load MWF into multiple appdomains
+ // and try to register same class name we fail.
+ internal static string GetDefaultClassName (Type type)
+ {
+ return "SWFClass" + Thread.GetDomainID ().ToString () + "." + type.ToString ();
+ }
+
+ // Generate a class name using current domain and a random number.
+ internal static string GetDefaultClassName ()
+ {
+ return "SWFClass" + Thread.GetDomainID ().ToString () + "." + new Random().Next(0, 9999999).ToString();
+ }
+
+
+ static public Size Border3DSize {
+ get {
+ return driver.Border3DSize;
+ }
+ }
+
+ static public Size BorderSize {
+ get {
+ return driver.BorderSize;
+ }
+ }
+
+ static public Size CaptionButtonSize {
+ get {
+ return driver.CaptionButtonSize;
+ }
+ }
+
+ static public int CaptionHeight {
+ get {
+ return driver.CaptionHeight;
+ }
+ }
+
+ public static int CaretBlinkTime { get { return driver.CaretBlinkTime; } }
+ public static int CaretWidth { get { return driver.CaretWidth; } }
+
+ static public Size CursorSize {
+ get {
+ return driver.CursorSize;
+ }
+ }
+
+ static public Size DoubleClickSize {
+ get {
+ return driver.DoubleClickSize;
+ }
+ }
+
+ static public int DoubleClickTime {
+ get {
+ return driver.DoubleClickTime;
+ }
+ }
+
+ static public bool DragFullWindows {
+ get {
+ return driver.DragFullWindows;
+ }
+ }
+
+ static public Size DragSize {
+ get {
+ return driver.DragSize;
+ }
+ }
+
+ static public Size FixedFrameBorderSize {
+ get {
+ return driver.FixedFrameBorderSize;
+ }
+ }
+
+ public static int FontSmoothingContrast { get { return driver.FontSmoothingContrast; } }
+ public static int FontSmoothingType { get { return driver.FontSmoothingType; } }
+
+ public static Size FrameBorderSize {
+ get {
+ return driver.FrameBorderSize;
+ }
+ }
+
+ public static int HorizontalResizeBorderThickness { get { return driver.HorizontalResizeBorderThickness; } }
+
+ static public int HorizontalScrollBarHeight {
+ get {
+ return driver.HorizontalScrollBarHeight;
+ }
+ }
+
+ static public Size IconSize {
+ get {
+ return driver.IconSize;
+ }
+ }
+
+ public static bool IsActiveWindowTrackingEnabled { get { return driver.IsActiveWindowTrackingEnabled; } }
+ public static bool IsComboBoxAnimationEnabled { get { return driver.IsComboBoxAnimationEnabled; } }
+ public static bool IsDropShadowEnabled { get { return driver.IsDropShadowEnabled; } }
+ public static bool IsFontSmoothingEnabled { get { return driver.IsFontSmoothingEnabled; } }
+ public static bool IsHotTrackingEnabled { get { return driver.IsHotTrackingEnabled; } }
+ public static bool IsIconTitleWrappingEnabled { get { return driver.IsIconTitleWrappingEnabled; } }
+ public static bool IsKeyboardPreferred { get { return driver.IsKeyboardPreferred; } }
+ public static bool IsListBoxSmoothScrollingEnabled { get { return driver.IsListBoxSmoothScrollingEnabled; } }
+ public static bool IsMenuAnimationEnabled { get { return driver.IsMenuAnimationEnabled; } }
+ public static bool IsMenuFadeEnabled { get { return driver.IsMenuFadeEnabled; } }
+ public static bool IsMinimizeRestoreAnimationEnabled { get { return driver.IsMinimizeRestoreAnimationEnabled; } }
+ public static bool IsSelectionFadeEnabled { get { return driver.IsSelectionFadeEnabled; } }
+ public static bool IsSnapToDefaultEnabled { get { return driver.IsSnapToDefaultEnabled; } }
+ public static bool IsTitleBarGradientEnabled { get { return driver.IsTitleBarGradientEnabled; } }
+ public static bool IsToolTipAnimationEnabled { get { return driver.IsToolTipAnimationEnabled; } }
+
+ static public int KeyboardSpeed {
+ get {
+ return driver.KeyboardSpeed;
+ }
+ }
+
+ static public int KeyboardDelay {
+ get {
+ return driver.KeyboardDelay;
+ }
+ }
+
+ static public Size MaxWindowTrackSize {
+ get {
+ return driver.MaxWindowTrackSize;
+ }
+ }
+
+ static public bool MenuAccessKeysUnderlined {
+ get {
+ return driver.MenuAccessKeysUnderlined;
+ }
+ }
+
+ static public Size MenuBarButtonSize { get { return driver.MenuBarButtonSize; } }
+
+ public static Size MenuButtonSize {
+ get {
+ return driver.MenuButtonSize;
+ }
+ }
+
+ static public int MenuShowDelay { get { return driver.MenuShowDelay; } }
+
+ static public Size MinimizedWindowSize {
+ get {
+ return driver.MinimizedWindowSize;
+ }
+ }
+
+ static public Size MinimizedWindowSpacingSize {
+ get {
+ return driver.MinimizedWindowSpacingSize;
+ }
+ }
+
+ static public Size MinimumWindowSize {
+ get {
+ return driver.MinimumWindowSize;
+ }
+ }
+
+ static public Size MinimumFixedToolWindowSize {
+ get { return driver.MinimumFixedToolWindowSize; }
+ }
+
+ static public Size MinimumSizeableToolWindowSize {
+ get { return driver.MinimumSizeableToolWindowSize; }
+ }
+
+ static public Size MinimumNoBorderWindowSize {
+ get { return driver.MinimumNoBorderWindowSize; }
+ }
+
+ static public Size MinWindowTrackSize {
+ get {
+ return driver.MinWindowTrackSize;
+ }
+ }
+
+ public static int MouseSpeed {
+ get { return driver.MouseSpeed; }
+ }
+
+ static public Size SmallIconSize {
+ get {
+ return driver.SmallIconSize;
+ }
+ }
+
+ static public int MenuHeight {
+ get {
+ return driver.MenuHeight;
+ }
+ }
+
+ static public int MouseButtonCount {
+ get {
+ return driver.MouseButtonCount;
+ }
+ }
+
+ static public bool MouseButtonsSwapped {
+ get {
+ return driver.MouseButtonsSwapped;
+ }
+ }
+
+ static public Size MouseHoverSize {
+ get {
+ return driver.MouseHoverSize;
+ }
+ }
+
+ static public int MouseHoverTime {
+ get {
+ return driver.MouseHoverTime;
+ }
+ }
+
+ static public int MouseWheelScrollDelta {
+ get {
+ return driver.MouseWheelScrollDelta;
+ }
+ }
+
+ static public bool MouseWheelPresent {
+ get {
+ return driver.MouseWheelPresent;
+ }
+ }
+
+ public static LeftRightAlignment PopupMenuAlignment {
+ get { return driver.PopupMenuAlignment; }
+ }
+
+ public static PowerStatus PowerStatus {
+ get { return driver.PowerStatus; }
+ }
+
+ public static bool RequiresPositiveClientAreaSize {
+ get {
+ return driver.RequiresPositiveClientAreaSize;
+ }
+ }
+
+ public static int SizingBorderWidth {
+ get { return driver.SizingBorderWidth; }
+ }
+
+ public static Size SmallCaptionButtonSize {
+ get { return driver.SmallCaptionButtonSize; }
+ }
+
+ public static bool UIEffectsEnabled {
+ get { return driver.UIEffectsEnabled; }
+ }
+
+ static public bool UserClipWontExposeParent {
+ get {
+ return driver.UserClipWontExposeParent;
+ }
+ }
+
+ public static int VerticalResizeBorderThickness { get { return driver.VerticalResizeBorderThickness; } }
+
+ static public int VerticalScrollBarWidth {
+ get {
+ return driver.VerticalScrollBarWidth;
+ }
+ }
+
+ static public Rectangle VirtualScreen {
+ get {
+ return driver.VirtualScreen;
+ }
+ }
+
+ static public Rectangle WorkingArea {
+ get {
+ return driver.WorkingArea;
+ }
+ }
+
+ public static Screen[] AllScreens {
+ get {
+ return driver.AllScreens;
+ }
+ }
+
+ public static bool ThemesEnabled {
+ get {
+ return XplatUI.driver.ThemesEnabled;
+ }
+ }
+
+ public static int ToolWindowCaptionHeight {
+ get {
+ return driver.ToolWindowCaptionHeight;
+ }
+ }
+
+ public static Size ToolWindowCaptionButtonSize {
+ get {
+ return driver.ToolWindowCaptionButtonSize;
+ }
+ }
+ #endregion // Public Static Properties
+
+ #region Events
+
+ internal static event EventHandler Idle {
+ add {
+ driver.Idle += value;
+ }
+ remove {
+ driver.Idle -= value;
+ }
+ }
+
+ #endregion // Events
+
+ #region Public Static Methods
+ internal static void Activate (IntPtr handle)
+ {
+ DriverDebug ("Activate ({0}): Called", Window (handle));
+ driver.Activate (handle);
+ }
+
+ internal static void AudibleAlert (AlertType alert)
+ {
+ DriverDebug ("AudibleAlert (): Called");
+ driver.AudibleAlert (alert);
+ }
+
+ internal static void BeginMoveResize (IntPtr handle)
+ {
+ driver.BeginMoveResize (handle);
+ }
+
+ internal static bool CalculateWindowRect (ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect)
+ {
+ DriverDebug ("CalculateWindowRect ({0}, {1}, {2}): Called", ClientRect, cp, menu);
+ return driver.CalculateWindowRect (ref ClientRect, cp, menu, out WindowRect);
+ }
+
+ internal static void CaretVisible (IntPtr handle, bool visible)
+ {
+ DriverDebug ("CaretVisible ({0:X}, {1}): Called", handle.ToInt32 (), visible);
+ driver.CaretVisible (handle, visible);
+ }
+
+ internal static void CreateCaret (IntPtr handle, int width, int height)
+ {
+ DriverDebug ("CreateCaret ({0:X}), {1}, {2}: Called", handle.ToInt32 (), width, height);
+ driver.CreateCaret (handle, width, height);
+ }
+
+ internal static IntPtr CreateWindow (CreateParams cp)
+ {
+ #if DriverDebug || DriverDebugCreate
+ IntPtr handle;
+
+ handle = driver.CreateWindow (cp);
+
+ Console.WriteLine ("CreateWindow (): Called, returning {0:X}", handle.ToInt32 ());
+ return handle;
+ #else
+ return driver.CreateWindow (cp);
+ #endif
+ }
+
+ internal static IntPtr CreateWindow (IntPtr Parent, int X, int Y, int Width, int Height)
+ {
+ #if DriverDebug || DriverDebugCreate
+ Console.WriteLine ("CreateWindow (): Called");
+ #endif
+ return driver.CreateWindow (Parent, X, Y, Width, Height);
+ }
+
+ internal static void ClientToScreen (IntPtr handle, ref int x, ref int y)
+ {
+ #if DriverDebug
+ Console.WriteLine ("ClientToScreen ({0}, {1}, {2}): Called", Window (handle), x, y);
+ #endif
+ driver.ClientToScreen (handle, ref x, ref y);
+ }
+
+ internal static int[] ClipboardAvailableFormats (IntPtr handle)
+ {
+ DriverDebug ("ClipboardAvailableTypes ({0:X}): Called", handle.ToInt32 ());
+ return driver.ClipboardAvailableFormats (handle);
+ }
+
+ internal static void ClipboardClose (IntPtr handle)
+ {
+ DriverDebug ("ClipboardClose ({0:X}): Called", handle.ToInt32 ());
+ driver.ClipboardClose (handle);
+ }
+
+ internal static int ClipboardGetID (IntPtr handle, string format)
+ {
+ DriverDebug ("ClipboardGetID ({0:X}, {1}): Called", handle.ToInt32 (), format);
+ return driver.ClipboardGetID (handle, format);
+ }
+
+ internal static IntPtr ClipboardOpen (bool primary_selection)
+ {
+ DriverDebug ("ClipboardOpen (): Called");
+ return driver.ClipboardOpen (primary_selection);
+ }
+
+ internal static void ClipboardStore (IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy)
+ {
+ DriverDebug ("ClipboardStore ({0:X}, {1}, {2}, {3}, {4}): Called", handle.ToInt32 (), obj, type, converter, copy);
+ driver.ClipboardStore (handle, obj, type, converter, copy);
+ }
+
+ internal static object ClipboardRetrieve (IntPtr handle, int type, XplatUI.ClipboardToObject converter)
+ {
+ DriverDebug ("ClipboardRetrieve ({0:X}, type, {1}): Called", handle.ToInt32 (), converter);
+ return driver.ClipboardRetrieve (handle, type, converter);
+ }
+
+ internal static IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
+ {
+ DriverDebug ("DefineCursor (...): Called");
+ return driver.DefineCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot);
+ }
+
+ internal static IntPtr DefineStdCursor (StdCursor id)
+ {
+ return driver.DefineStdCursor (id);
+ }
+
+ internal static Bitmap DefineStdCursorBitmap (StdCursor id)
+ {
+ return driver.DefineStdCursorBitmap (id);
+ }
+
+ internal static IntPtr DefWndProc (ref Message msg)
+ {
+ return driver.DefWndProc (ref msg);
+ }
+
+ internal static void DestroyCaret (IntPtr handle)
+ {
+ DriverDebug ("DestroyCaret ({0:X}): Called", handle.ToInt32 ());
+ driver.DestroyCaret (handle);
+ }
+
+ internal static void DestroyCursor (IntPtr cursor)
+ {
+ DriverDebug ("DestroyCursor ({0:X}): Called", cursor.ToInt32 ());
+ driver.DestroyCursor (cursor);
+ }
+
+ internal static void DestroyWindow (IntPtr handle)
+ {
+ DriverDebug ("DestroyWindow ({0}): Called", Window (handle));
+ driver.DestroyWindow (handle);
+ }
+
+ internal static IntPtr DispatchMessage (ref MSG msg)
+ {
+ return driver.DispatchMessage (ref msg);
+ }
+
+ internal static void DoEvents ()
+ {
+ driver.DoEvents ();
+ }
+
+ internal static void DrawReversibleRectangle (IntPtr handle, Rectangle rect, int line_width)
+ {
+ DriverDebug ("DrawReversibleRectangle ({0}, {1}, {2}): Called", Window (handle), rect, line_width);
+ driver.DrawReversibleRectangle (handle, rect, line_width);
+ }
+
+ internal static void FillReversibleRectangle (Rectangle rectangle, Color backColor)
+ {
+ DriverDebug ("FillReversibleRectangle ({0}, {1}): Called", rectangle, backColor);
+ driver.FillReversibleRectangle (rectangle, backColor);
+ }
+
+ internal static void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
+ {
+ DriverDebug ("DrawReversibleFrame ({0}, {1}, {2}): Called", rectangle, backColor, style);
+ driver.DrawReversibleFrame (rectangle, backColor, style);
+ }
+
+ internal static void DrawReversibleLine (Point start, Point end, Color backColor)
+ {
+ DriverDebug ("DrawReversibleLine ({0}, {1}, {2}): Called", start, end, backColor);
+ driver.DrawReversibleLine (start, end, backColor);
+ }
+
+ internal static void EnableThemes ()
+ {
+ driver.EnableThemes ();
+ }
+
+ internal static void EnableWindow (IntPtr handle, bool Enable)
+ {
+ DriverDebug ("EnableWindow ({0}, {1}): Called", Window (handle), Enable);
+ driver.EnableWindow (handle, Enable);
+ }
+
+ internal static void EndLoop (Thread thread)
+ {
+ DriverDebug ("EndLoop ({0:X}): Called", thread.GetHashCode ());
+ driver.EndLoop (thread);
+ }
+
+ internal static IntPtr GetActive ()
+ {
+ DriverDebug ("GetActive (): Called");
+ return driver.GetActive ();
+ }
+
+ internal static SizeF GetAutoScaleSize (Font font)
+ {
+ DriverDebug ("GetAutoScaleSize ({0}): Called", font);
+ return driver.GetAutoScaleSize (font);
+ }
+
+ internal static Region GetClipRegion (IntPtr handle)
+ {
+ DriverDebug ("GetClipRegion ({0}): Called", Window (handle));
+ return driver.GetClipRegion (handle);
+ }
+
+ internal static void GetCursorInfo (IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y)
+ {
+ DriverDebug ("GetCursorInfo ({0}): Called", cursor.ToInt32 ());
+ driver.GetCursorInfo (cursor, out width, out height, out hotspot_x, out hotspot_y);
+ }
+
+ internal static void GetCursorPos (IntPtr handle, out int x, out int y)
+ {
+ DriverDebug ("GetCursorPos ({0}): Called", Window (handle));
+ driver.GetCursorPos (handle, out x, out y);
+ }
+
+ internal static void GetDisplaySize (out Size size)
+ {
+ DriverDebug ("GetDisplaySize (): Called");
+ driver.GetDisplaySize (out size);
+ }
+
+ internal static IntPtr GetFocus ()
+ {
+ DriverDebug ("GetFocus (): Called, Result:{0}", Window (driver.GetFocus ()));
+ return driver.GetFocus ();
+ }
+
+ internal static bool GetFontMetrics (Graphics g, Font font, out int ascent, out int descent)
+ {
+ DriverDebug ("GetFontMetrics (): Called");
+ return driver.GetFontMetrics (g, font, out ascent, out descent);
+ }
+
+ internal static Point GetMenuOrigin (IntPtr handle)
+ {
+ DriverDebug ("GetMenuOrigin ({0}): Called", Window (handle));
+ return driver.GetMenuOrigin (handle);
+ }
+
+ internal static bool GetMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax)
+ {
+ return driver.GetMessage (queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
+ }
+
+ internal static IntPtr GetParent (IntPtr handle)
+ {
+ DriverDebug ("GetParent ({0}): Called", Window (handle));
+ return driver.GetParent (handle);
+ }
+
+ internal static IntPtr GetPreviousWindow (IntPtr handle)
+ {
+ return driver.GetPreviousWindow (handle);
+ }
+
+ internal static bool GetText (IntPtr handle, out string text)
+ {
+ DriverDebug ("GetText ({0}): Called", Window (handle));
+ return driver.GetText (handle, out text);
+ }
+
+ internal static 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)
+ {
+ DriverDebug ("GetWindowPos ({0}): Called", Window (handle));
+ driver.GetWindowPos (handle, is_toplevel, out x, out y, out width, out height, out client_width, out client_height);
+ }
+
+ /* this method can (and does, on X11) return
+ * (FormWindowState) (-1), when the state of the window
+ * cannot be determined (in the X11 case, when the
+ * window isn't mapped.) Checking for the additional
+ * return value is less expensive than
+ * throwing/catching an exception. */
+ internal static FormWindowState GetWindowState (IntPtr handle)
+ {
+ DriverDebug ("GetWindowState ({0}): Called", Window (handle));
+ return driver.GetWindowState (handle);
+ }
+
+ internal static void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea)
+ {
+ DriverDebug ("GrabInfo (): Called");
+ driver.GrabInfo (out handle, out GrabConfined, out GrabArea);
+ }
+
+ internal static void GrabWindow (IntPtr handle, IntPtr ConfineToHwnd)
+ {
+ DriverDebug ("GrabWindow ({0}, {1}): Called", Window (handle), Window (ConfineToHwnd));
+ driver.GrabWindow (handle, ConfineToHwnd);
+ }
+
+ internal static void HandleException (Exception e)
+ {
+ driver.HandleException (e);
+ }
+
+ internal static void Invalidate (IntPtr handle, Rectangle rc, bool clear)
+ {
+ DriverDebug ("Invalidate ({0}, {1}, {2}): Called", Window (handle), rc, clear);
+ driver.Invalidate (handle, rc, clear);
+ }
+
+ internal static void InvalidateNC (IntPtr handle)
+ {
+ DriverDebug ("InvalidateNC ({0}): Called", Window (handle));
+ driver.InvalidateNC (handle);
+ }
+
+
+ internal static bool IsEnabled (IntPtr handle)
+ {
+ #if DriverDebug || DriverDebugState
+ Console.WriteLine ("IsEnabled ({0}): Called, Result={1}", Window (handle), driver.IsEnabled (handle));
+ #endif
+ return driver.IsEnabled (handle);
+ }
+
+ internal static bool IsKeyLocked (VirtualKeys key)
+ {
+ #if DriverDebug || DriverDebugState
+ Console.WriteLine ("IsKeyLocked ({0}): Called, Result={1}", key, driver.IsKeyLocked (key));
+ #endif
+ return driver.IsKeyLocked (key);
+ }
+
+ internal static bool IsVisible (IntPtr handle)
+ {
+ #if DriverDebug || DriverDebugState
+ Console.WriteLine ("IsVisible ({0}): Called, Result={1}", Window (handle), driver.IsVisible (handle));
+ #endif
+ return driver.IsVisible (handle);
+ }
+
+ internal static void KillTimer (Timer timer)
+ {
+ DriverDebug ("KillTimer ({0}): Called", timer);
+ driver.KillTimer (timer);
+ }
+
+ internal static void MenuToScreen (IntPtr handle, ref int x, ref int y)
+ {
+ DriverDebug ("MenuToScreen ({0}, {1}, {2}): Called", Window (handle), x, y);
+ driver.MenuToScreen (handle, ref x, ref y);
+ }
+
+ internal static void OverrideCursor (IntPtr cursor)
+ {
+ DriverDebug ("OverrideCursor ({0:X}): Called", cursor.ToInt32 ());
+ driver.OverrideCursor (cursor);
+ }
+
+ internal static void PaintEventEnd (ref Message msg, IntPtr handle, bool client)
+ {
+ #if DriverDebug || DriverDebugPaint
+ Console.WriteLine ("PaintEventEnd ({0}, {1}, {2}): Called from thread {3}", msg, Window (handle), client, Thread.CurrentThread.GetHashCode ());
+ #endif
+ driver.PaintEventEnd (ref msg, handle, client);
+ }
+
+ internal static PaintEventArgs PaintEventStart (ref Message msg, IntPtr handle, bool client)
+ {
+ #if DriverDebug || DriverDebugPaint
+ Console.WriteLine ("PaintEventStart ({0}, {1}, {2}): Called from thread {3}", msg, Window (handle), client, Thread.CurrentThread.GetHashCode ());
+ #endif
+ return driver.PaintEventStart (ref msg, handle, client);
+ }
+
+ internal static bool PeekMessage (Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
+ {
+ return driver.PeekMessage (queue_id, ref msg, hWnd, wFilterMin, wFilterMax, flags);
+ }
+
+ internal static bool PostMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ DriverDebug ("PostMessage ({0}, {1}, {2:X}, {3:X}): Called", Window (hwnd), message, wParam.ToInt32 (), lParam.ToInt32 ());
+ return driver.PostMessage (hwnd, message, wParam, lParam);
+ }
+
+ internal static bool PostMessage (ref MSG msg)
+ {
+ DriverDebug ("PostMessage ({0}): Called", msg);
+ return driver.PostMessage (msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ }
+
+ internal static void PostQuitMessage (int exitCode)
+ {
+ DriverDebug ("PostQuitMessage ({0}): Called", exitCode);
+ driver.PostQuitMessage (exitCode);
+ }
+
+ internal static void RaiseIdle (EventArgs e)
+ {
+ DriverDebug ("RaiseIdle ({0}): Called", e.ToString ());
+
+ driver.RaiseIdle (e);
+ }
+
+ internal static void RequestAdditionalWM_NCMessages (IntPtr handle, bool hover, bool leave)
+ {
+ DriverDebug ("RequestAdditionalWM_NCMessages ({0}, {1}, {2}): Called", Window (handle), hover, leave);
+ driver.RequestAdditionalWM_NCMessages (handle, hover, leave);
+ }
+
+ internal static void RequestNCRecalc (IntPtr handle)
+ {
+ DriverDebug ("RequestNCRecalc ({0}): Called", Window (handle));
+ driver.RequestNCRecalc (handle);
+ }
+
+ internal static void ResetMouseHover (IntPtr handle)
+ {
+ DriverDebug ("ResetMouseHover ({0}): Called", Window (handle));
+ driver.ResetMouseHover (handle);
+ }
+
+ internal static void ScreenToClient (IntPtr handle, ref int x, ref int y)
+ {
+ DriverDebug ("ScreenToClient ({0}, {1}, {2}): Called", Window (handle), x, y);
+ driver.ScreenToClient (handle, ref x, ref y);
+ }
+
+ internal static void ScreenToMenu (IntPtr handle, ref int x, ref int y)
+ {
+ DriverDebug ("ScreenToMenu ({0}, {1}, {2}): Called", Window (handle), x, y);
+ driver.ScreenToMenu (handle, ref x, ref y);
+ }
+
+ internal static void ScrollWindow (IntPtr handle, Rectangle rectangle, int XAmount, int YAmount, bool with_children)
+ {
+ DriverDebug ("ScrollWindow ({0}, {1}, {2}, {3}, {4}): Called", Window (handle), rectangle, XAmount, YAmount, with_children);
+ driver.ScrollWindow (handle, rectangle, XAmount, YAmount, with_children);
+ }
+
+ internal static void ScrollWindow (IntPtr handle, int XAmount, int YAmount, bool with_children)
+ {
+ DriverDebug ("ScrollWindow ({0}, {1}, {2}, {3}): Called", Window (handle), XAmount, YAmount, with_children);
+ driver.ScrollWindow (handle, XAmount, YAmount, with_children);
+ }
+
+ internal static void SendAsyncMethod (AsyncMethodData data)
+ {
+ DriverDebug ("SendAsyncMethod ({0}): Called", data);
+ driver.SendAsyncMethod (data);
+ }
+
+ internal static int SendInput (IntPtr hwnd, Queue keys)
+ {
+ DriverDebug ("SendInput ({0}, {1}): Called", hwnd, keys);
+ return driver.SendInput (hwnd, keys);
+ }
+
+ internal static IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ DriverDebug ("SendMessage ({0}, {1}, {2:X}, {3:X}): Called", Window (handle), message, wParam.ToInt32 (), lParam.ToInt32 ());
+ return driver.SendMessage (handle, message, wParam, lParam);
+ }
+
+ internal static void SendMessage (ref Message m)
+ {
+ DriverDebug ("SendMessage ({0}): Called", m);
+ m.Result = driver.SendMessage (m.HWnd, (Msg)m.Msg, m.WParam, m.LParam);
+ }
+
+ internal static void SetAllowDrop (IntPtr handle, bool value)
+ {
+ DriverDebug ("SetAllowDrop ({0}, {1}): Called", handle, value);
+ driver.SetAllowDrop (handle, value);
+ }
+
+ internal static void SetBorderStyle (IntPtr handle, FormBorderStyle border_style)
+ {
+ DriverDebug ("SetBorderStyle ({0}, {1}): Called", Window (handle), border_style);
+ driver.SetBorderStyle (handle, border_style);
+ }
+
+ internal static void SetCaretPos (IntPtr handle, int x, int y)
+ {
+ DriverDebug ("SetCaretPos ({0}, {1}, {2}): Called", Window (handle), x, y);
+ driver.SetCaretPos (handle, x, y);
+ }
+
+ internal static void SetClipRegion (IntPtr handle, Region region)
+ {
+ DriverDebug ("SetClipRegion ({0}, {1}): Called", Window (handle), region);
+ driver.SetClipRegion (handle, region);
+ }
+
+ internal static void SetCursor (IntPtr handle, IntPtr cursor)
+ {
+ DriverDebug ("SetCursor ({0}, {1:X}): Called", Window (handle), cursor.ToInt32 ());
+ driver.SetCursor (handle, cursor);
+ }
+
+ internal static void SetCursorPos (IntPtr handle, int x, int y)
+ {
+ DriverDebug ("SetCursorPos ({0}, {1}, {2}): Called", Window (handle), x, y);
+ driver.SetCursorPos (handle, x, y);
+ }
+
+ internal static void SetFocus (IntPtr handle)
+ {
+ DriverDebug ("SetFocus ({0}): Called", Window (handle));
+ driver.SetFocus (handle);
+ }
+
+ internal static void SetForegroundWindow (IntPtr handle)
+ {
+ DriverDebug ("SetForegroundWindow ({0}): Called", Window (handle));
+ driver.SetForegroundWindow (handle);
+ }
+
+ internal static void SetIcon (IntPtr handle, Icon icon)
+ {
+ DriverDebug ("SetIcon ({0}, {1}): Called", Window (handle), icon);
+ driver.SetIcon (handle, icon);
+ }
+
+ internal static void SetMenu (IntPtr handle, Menu menu)
+ {
+ DriverDebug ("SetMenu ({0}, {1}): Called", Window (handle), menu);
+ driver.SetMenu (handle, menu);
+ }
+
+ internal static void SetModal (IntPtr handle, bool Modal)
+ {
+ DriverDebug ("SetModal ({0}, {1}): Called", Window (handle), Modal);
+ driver.SetModal (handle, Modal);
+ }
+
+ internal static IntPtr SetParent (IntPtr handle, IntPtr hParent)
+ {
+ DriverDebug ("SetParent ({0}, {1:X}): Called", Window (handle), Window (hParent));
+ return driver.SetParent (handle, hParent);
+ }
+
+ internal static void SetTimer (Timer timer)
+ {
+ DriverDebug ("SetTimer ({0}): Called", timer);
+ driver.SetTimer (timer);
+ }
+
+ internal static bool SetTopmost (IntPtr handle, bool Enabled)
+ {
+ DriverDebug ("SetTopMost ({0}, {1}): Called", Window (handle), Enabled);
+ return driver.SetTopmost (handle, Enabled);
+ }
+
+ internal static bool SetOwner (IntPtr handle, IntPtr hWndOwner)
+ {
+ DriverDebug ("SetOwner ({0}, {1}): Called", Window (handle), Window (hWndOwner));
+ return driver.SetOwner (handle, hWndOwner);
+ }
+
+ internal static bool SetVisible (IntPtr handle, bool visible, bool activate)
+ {
+ #if DriverDebug || DriverDebugState
+ Console.WriteLine ("SetVisible ({0}, {1}, {2}): Called", Window (handle), visible, activate);
+ #endif
+ return driver.SetVisible (handle, visible, activate);
+ }
+
+ internal static void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max)
+ {
+ #if DriverDebug || DriverDebugState
+ Console.WriteLine ("SetWindowMinMax ({0}, {1}, {2}, {3}): Called", Window (handle), maximized, min, max);
+ #endif
+ driver.SetWindowMinMax (handle, maximized, min, max);
+ }
+
+ internal static void SetWindowPos (IntPtr handle, int x, int y, int width, int height)
+ {
+ DriverDebug ("SetWindowPos ({0}, {1}, {2}, {3}, {4}): Called", Window (handle), x, y, width, height);
+ driver.SetWindowPos (handle, x, y, width, height);
+ }
+
+ internal static void SetWindowState (IntPtr handle, FormWindowState state)
+ {
+ #if DriverDebug || DriverDebugState
+ Console.WriteLine ("SetWindowState ({0} {1}): Called", Window (handle), state);
+ #endif
+ driver.SetWindowState (handle, state);
+ }
+
+ internal static void SetWindowStyle (IntPtr handle, CreateParams cp)
+ {
+ DriverDebug ("SetWindowStyle ({0}): Called", Window (handle));
+ driver.SetWindowStyle (handle, cp);
+ }
+
+ internal static double GetWindowTransparency (IntPtr handle)
+ {
+ DriverDebug ("SetWindowTransparency ({0}): Called", Window (handle));
+ return driver.GetWindowTransparency (handle);
+ }
+
+ internal static void SetWindowTransparency (IntPtr handle, double transparency, Color key)
+ {
+ DriverDebug ("SetWindowTransparency ({0}): Called", Window (handle));
+ driver.SetWindowTransparency (handle, transparency, key);
+ }
+
+ internal static bool SetZOrder (IntPtr handle, IntPtr AfterhWnd, bool Top, bool Bottom)
+ {
+ DriverDebug ("SetZOrder ({0}, {1:X}, {2}, {3}): Called", Window (handle), Window (AfterhWnd), Top, Bottom);
+ return driver.SetZOrder (handle, AfterhWnd, Top, Bottom);
+ }
+
+ internal static void ShowCursor (bool show)
+ {
+ DriverDebug ("ShowCursor ({0}): Called", show);
+ driver.ShowCursor (show);
+ }
+
+ internal static DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowedEffects)
+ {
+ DriverDebug ("StartDrag ({0}, {1}, {2}): Called", Window (handle), data, allowedEffects);
+ return driver.StartDrag (handle, data, allowedEffects);
+ }
+
+ internal static object StartLoop (Thread thread)
+ {
+ DriverDebug ("StartLoop ({0:X}): Called", thread.GetHashCode ());
+ return driver.StartLoop (thread);
+ }
+
+ internal static TransparencySupport SupportsTransparency ()
+ {
+ DriverDebug ("SupportsTransparency (): Called, result={0}", driver.SupportsTransparency ());
+ return driver.SupportsTransparency ();
+ }
+
+ internal static bool SystrayAdd (IntPtr handle, string tip, Icon icon, out ToolTip tt)
+ {
+ DriverDebug ("SystrayAdd ({0}, {1}): Called", Window (handle), tip);
+ return driver.SystrayAdd (handle, tip, icon, out tt);
+ }
+
+ internal static void SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt)
+ {
+ DriverDebug ("SystrayChange ({0}, {1}): Called", Window (handle), tip);
+ driver.SystrayChange (handle, tip, icon, ref tt);
+ }
+
+ internal static void SystrayRemove (IntPtr handle, ref ToolTip tt)
+ {
+ DriverDebug ("SystrayRemove ({0}): Called", Window (handle));
+ driver.SystrayRemove (handle, ref tt);
+ }
+
+ internal static void SystrayBalloon (IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
+ {
+ DriverDebug ("SystrayBalloon ({0}, {1}, {2}, {3}, {4}): Called", Window (handle), timeout, title, text, icon);
+ driver.SystrayBalloon (handle, timeout, title, text, icon);
+ }
+
+ internal static bool Text (IntPtr handle, string text)
+ {
+ DriverDebug ("Text ({0}, {1}): Called", Window (handle), text);
+ return driver.Text (handle, text);
+ }
+
+ internal static bool TranslateMessage (ref MSG msg)
+ {
+ return driver.TranslateMessage (ref msg);
+ }
+
+ internal static void UngrabWindow (IntPtr handle)
+ {
+ DriverDebug ("UngrabWindow ({0}): Called", Window (handle));
+ driver.UngrabWindow (handle);
+ }
+
+ internal static void UpdateWindow (IntPtr handle)
+ {
+ DriverDebug ("UpdateWindow ({0}): Called", Window (handle));
+ driver.UpdateWindow (handle);
+ }
+
+ // double buffering
+ internal static void CreateOffscreenDrawable (IntPtr handle,
+ int width, int height,
+ out object offscreen_drawable)
+ {
+ DriverDebug ("CreateOffscreenDrawable ({2}, {0},{1}): Called", width, height, Window (handle));
+ driver.CreateOffscreenDrawable (handle, width, height,
+ out offscreen_drawable);
+ }
+
+ internal static void DestroyOffscreenDrawable (object offscreen_drawable)
+ {
+ DriverDebug ("DestroyOffscreenDrawable (): Called");
+ driver.DestroyOffscreenDrawable (offscreen_drawable);
+ }
+
+ internal static Graphics GetOffscreenGraphics (object offscreen_drawable)
+ {
+ DriverDebug ("GetOffscreenGraphics (): Called");
+ return driver.GetOffscreenGraphics (offscreen_drawable);
+ }
+
+ internal static void BlitFromOffscreen (IntPtr dest_handle,
+ Graphics dest_dc,
+ object offscreen_drawable,
+ Graphics offscreen_dc,
+ Rectangle r)
+ {
+ DriverDebug ("BlitFromOffscreen ({0}): Called", Window (dest_handle));
+ driver.BlitFromOffscreen (dest_handle, dest_dc, offscreen_drawable, offscreen_dc, r);
+ }
+
+
+ // Santa's little helper
+ internal static void Version ()
+ {
+ Console.WriteLine ("Xplat version $Revision: $");
+ }
+
+ internal static void AddKeyFilter (IKeyFilter value)
+ {
+ lock (key_filters) {
+ key_filters.Add (value);
+ }
+ }
+
+ internal static bool FilterKey (KeyFilterData key)
+ {
+ lock (key_filters) {
+ for (int i = 0; i < key_filters.Count; i++) {
+ IKeyFilter filter = (IKeyFilter) key_filters[i];
+ if (filter.PreFilterKey (key))
+ return true;
+ }
+ }
+ return false;
+ }
+ #endregion // Public Static Methods
+
+ #region Delegates
+ public delegate bool ClipboardToObject (int type, IntPtr data, out object obj);
+ public delegate bool ObjectToClipboard (ref int type, object obj, out byte[] data);
+ #endregion // Delegates
+
+ [DllImport ("libc")]
+ static extern int uname (IntPtr buf);
+ }
+}
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
+ }
+}
diff --git a/source/ShiftUI/Internal/XplatUICosmos.cs b/source/ShiftUI/Internal/XplatUICosmos.cs
new file mode 100644
index 0000000..55f30df
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUICosmos.cs
@@ -0,0 +1,2916 @@
+/* Cosmos XplatUI driver
+ *
+ * Author: Michael VanOverbeek
+ * Based off: XplatUIWin32 driver (ShiftUI\Internal\XplatUIWin32.cs), copyright info can be found there.
+ *
+ * Cosmos is a C# open source managed operating system, capable of basic graphics using either
+ * VGA or VESA BIOS Extensions, it can do full console IO, has a working FAT driver, and is
+ * written entirely in C# and their homebrewed high-level assembly language, X#.
+ *
+ * ShiftUI cannot access Cosmos APIs directly, so to compensate, the CosmosInterface
+ * class exists. This is an interface between ShiftUI and Cosmos, and it is used
+ * to tell the operating system where to draw pixels, what colors to use, and when
+ * something happens, like a window opening or closing, or an error occurring.
+ *
+ * This makes it so that ShiftUI doesn't care what graphics driver you use, as long as it
+ * supports 32bit RGB and you are capable of converting RGB values thrown by ShiftUI
+ * to the values that your graphics driver wants.
+ *
+ * This also means that your OS can deal with actually drawing windows, much like how
+ * Win32 and X11 does it. It's sort of a "you be the puppet, ShiftUI'll pull the strings"
+ * situation.
+ *
+ * The Cosmos driver is UNFINISHED, and many Win32 code remains. So, if you can continue
+ * on, or you want to use Cosmos features when I'm done, simply uncomment this:
+ */
+
+ //#define COSMOS
+
+ /*
+ * and the C# compiler and Visual Studio will compile all of the Cosmos stuff.
+ *
+ * If you're planning on using ShiftUI for a Windows application or even Linux/Mac,
+ * DO NOT UNCOMMENT THAT #DEFINE. YOU WILL BREAK LOTS OF THINGS. There is a lot of
+ * platform-dependent stuff in Mono Winforms which is what ShiftUI is HEAVILY based
+ * off of, for example, when the app starts, it detects if you're on Windows, Mac or
+ * Linux, so that it knows whether to use Win32, X11, or Carbon. Cosmos can't really
+ * determine what OS it's running on because it IS an OS, so the COSMOS #define is
+ * used to bypass the platform-dependent stuff and make ShiftUI work specifically on
+ * Cosmos.
+ *
+ * Michael VanOverbeek out.
+ */
+
+#if COSMOS
+using ShiftUI;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ShiftUI.Internal
+{
+ public struct CosmosScreen
+ {
+ public int Width { get; set; }
+ public int Height { get; set; }
+ public CosmosGfxDriver Driver { get; set; }
+ }
+
+ public enum CosmosGfxDriver
+ {
+ VGA,
+ VESA,
+ VMware,
+ Dummy
+ }
+
+ public enum CosmosWindowState
+ {
+ Maximized,
+ Minimized,
+ Normal,
+ }
+
+ public enum CosmosWindowHint
+ {
+ MESSAGEBOX,
+ TOPLEVEL,
+ DEFAULT,
+ BORDERLESS,
+ DESKTOP,
+ TOOL,
+ }
+
+ public class CosmosWindow
+ {
+ public IntPtr Handle { get; set; }
+ public Hwnd Hwnd { get; set; }
+ public string Title { get; set; }
+ public CosmosWindowState WindowState { get; set; }
+ public CosmosWindowHint Style { get; set; }
+ }
+
+ /// <summary>
+ /// Because Cosmos cannot do dynamic loading and therefore
+ /// can't do P/Invokes, I'll let the operating system developer
+ /// use this interface as a backbone for letting XplatUI actually
+ /// interact with their operating system.
+ ///
+ /// ShiftOS won't use this, however Memphis will, and it's entire window manager
+ /// will reside in a class deriving from this class.
+ /// </summary>
+ public abstract class CosmosInterface
+ {
+ public abstract void SetPixel(int x, int y, Color col);
+ public abstract Color GetPixel(int x, int y);
+ public abstract CosmosScreen GetScreenInfo();
+ public abstract int MouseX { get; }
+ public abstract int MouseY { get; }
+ public abstract bool MouseWheelPressed { get; }
+ internal List<CosmosWindow> Windows = null;
+ public abstract void Redraw();
+
+
+
+ public bool IsWindow(IntPtr handle)
+ {
+ if(Windows == null)
+ {
+ Windows = new List<Hwnd>();
+ return false;
+ }
+ foreach(var win in Windows)
+ {
+ if (win.Handle == handle)
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Clears the screen with a specified color.
+ /// </summary>
+ /// <param name="c">The color to clear to.</param>
+ public void Clear(Color c) {
+ var scr = GetScreenInfo();
+ int w = scr.Width;
+ int h = scr.Height;
+ DrawRectangle(c, new Rectangle(0, 0, w, h));
+ }
+
+ /// <summary>
+ /// Draws a rectangle with the specified Rectangle and color.
+ /// </summary>
+ /// <param name="c">The color to use. (Note that depending on the graphics config of the current OS, color quality may be reduced.</param>
+ /// <param name="rect">The Rectangle struct containing the X and Y coordinates and the width and height.</param>
+ public void DrawRectangle(Color c, Rectangle rect)
+ {
+ int x = rect.X;
+ int y = rect.Y;
+ int max_width = rect.Width;
+ int max_height = rect.Height;
+ for(int i = x; i < max_width; i++)
+ {
+ for(int i2 = y; i2 < max_height; i2++)
+ {
+ if (GetPixel(i, i2) != c)
+ SetPixel(i, i2, c);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Draws an unfilled rectangle using the specified Rectangle, line width and color.
+ /// </summary>
+ public void DrawUnfilledRectangle(Rectangle rect, int width, Color c)
+ {
+ //top & bottom border
+ for(int x = rect.X; x < rect.Width; x++)
+ {
+ //top
+ for(int y = rect.Y; y < rect.Y + width; y++)
+ {
+ if (GetPixel(x, y) != c)
+ SetPixel(x, y, c);
+ }
+
+ //bottom
+ for(int y = rect.Height - width; y < rect.Height; y++)
+ {
+ if (GetPixel(x, y) != c)
+ SetPixel(x, y, c);
+ }
+ }
+
+ //In theory that code should work for left & right.
+ for (int y = rect.Y; y < rect.Height; y++)
+ {
+ //left
+ for (int x = rect.X; x < rect.X + width; x++)
+ {
+ if (GetPixel(x, y) != c)
+ SetPixel(x, y, c);
+ }
+
+ //right
+ for (int x = rect.Width - width; x < rect.Width; x++)
+ {
+ if (GetPixel(x, y) != c)
+ SetPixel(x, y, c);
+ }
+ }
+
+ }
+ }
+
+ public class DefaultCosmosInterface : CosmosInterface
+ {
+ public const string SUI_ERR_NODRIVER = "[ShiftUI] You cannot use ShiftUI yet. You still need to load in a proper CosmosInterface.";
+
+ public override bool MouseWheelPressed
+ {
+ get
+ {
+ Console.WriteLine(SUI_ERR_NODRIVER);
+ }
+ }
+
+ public override int MouseX
+ {
+ get
+ {
+ Console.WriteLine(SUI_ERR_NODRIVER);
+ }
+ }
+
+ public override int MouseY
+ {
+ get
+ {
+ Console.WriteLine(SUI_ERR_NODRIVER);
+ }
+ }
+
+ public override Color GetPixel(int x, int y)
+ {
+ Console.WriteLine(SUI_ERR_NODRIVER);
+ return Color.Empty;
+ }
+
+ public override CosmosScreen GetScreenInfo()
+ {
+ Console.WriteLine(SUI_ERR_NODRIVER);
+ var s = new CosmosScreen();
+ s.Driver = CosmosGfxDriver.Dummy;
+ s.Width = 0;
+ s.Height = 0;
+ return s;
+ }
+
+ public override void Redraw()
+ {
+ Console.WriteLine(SUI_ERR_NODRIVER);
+ }
+
+ public override void SetPixel(int x, int y, Color col)
+ {
+ Console.WriteLine(SUI_ERR_NODRIVER);
+ }
+ }
+
+ internal class XplatUICosmos : XplatUIDriver
+ {
+#region Local Variables
+ private CosmosInterface cosmos = new DefaultCosmosInterface();
+ private static XplatUICosmos instance;
+ private static int ref_count;
+ private static IntPtr FosterParentLast;
+
+ internal static MouseButtons mouse_state;
+ internal static Point mouse_position;
+ internal static bool grab_confined;
+ internal static IntPtr grab_hwnd;
+ internal static Rectangle grab_area;
+ internal static WndProc wnd_proc;
+ internal static IntPtr prev_mouse_hwnd;
+ internal static bool caret_visible;
+
+ internal static bool themes_enabled;
+ private Hashtable timer_list;
+ private static Queue message_queue;
+ 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 Rectangle clipped_cursor_rect;
+ private Hashtable registered_classes;
+ private Hwnd HwndCreating; // the Hwnd we are currently creating (see CreateWindow)
+
+#endregion // Local Variables
+
+#region Constructor & Destructor
+ private XplatUICosmos()
+ {
+ // Handle singleton stuff first
+ ref_count = 0;
+
+ mouse_state = MouseButtons.None;
+ mouse_position = Point.Empty;
+
+ grab_confined = false;
+ grab_area = Rectangle.Empty;
+
+ message_queue = new List<CosmosMessage>();
+
+ themes_enabled = true;
+
+ FosterParentLast = IntPtr.Zero;
+
+ scroll_height = 25;
+ scroll_width = 25;
+
+ timer_list = new Hashtable();
+ registered_classes = new Hashtable();
+ }
+#endregion // Constructor & Destructor
+
+#region Private Support Methods
+
+ private IntPtr GetFosterParent()
+ {
+ if (!cosmos.IsWindow(FosterParentLast))
+ {
+ FosterParentLast = cosmos.CreateWindow("Foster Parent", BorderStyle.None, 0, 0, 0, 0, IntPtr.Zero);
+
+ if (FosterParentLast == IntPtr.Zero)
+ {
+ MessageBox.Show("Could not create foster window, system error \"" + cosmos.GetLastError().ToString() = "\".", "Fatal error.");
+ }
+ }
+ return FosterParentLast;
+ }
+
+#region Static Properties
+ internal override int ActiveWindowTrackingDelay
+ {
+ get { return 0; }
+ }
+
+ internal override int CaretWidth
+ {
+ get
+ {
+ return Application.CurrentSkin.CaretWidth;
+ }
+ }
+
+ internal override int FontSmoothingContrast
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ internal override int FontSmoothingType
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ internal override int HorizontalResizeBorderThickness
+ {
+ get { return 5; }
+ }
+
+ internal override bool IsActiveWindowTrackingEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsComboBoxAnimationEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsDropShadowEnabled
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal override bool IsFontSmoothingEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsHotTrackingEnabled
+ {
+ get { return true; }
+ }
+
+ internal override bool IsIconTitleWrappingEnabled
+ {
+ get { return true; }
+ }
+
+ internal override bool IsKeyboardPreferred
+ {
+ get { return false; }
+ }
+
+ internal override bool IsListBoxSmoothScrollingEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsMenuAnimationEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsMenuFadeEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsMinimizeRestoreAnimationEnabled
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal override bool IsSelectionFadeEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsSnapToDefaultEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsTitleBarGradientEnabled
+ {
+ get { return false; }
+ }
+
+ internal override bool IsToolTipAnimationEnabled
+ {
+ get { return false; }
+ }
+
+ internal override Size MenuBarButtonSize
+ {
+ get
+ {
+ return new Size(32, 32);
+ }
+ }
+
+ public override Size MenuButtonSize
+ {
+ get
+ {
+ return new Size(32, 32);
+ }
+ }
+
+ internal override int MenuShowDelay
+ {
+ get { return 0; }
+ }
+
+ internal override int MouseSpeed
+ {
+ get { return Application.CurrentSkin.MouseSpeed; }
+ }
+
+ internal override LeftRightAlignment PopupMenuAlignment
+ {
+ get { return LeftRightAlignment.Left; }
+ }
+
+ internal override PowerStatus PowerStatus
+ {
+ get
+ {
+ //Cosmos doesn't have power management. Sadly.
+ return new PowerStatus(BatteryChargeStatus.Unknown, "No power status for you.".Length, 0.0, 0, PowerLineStatus.Unknown);
+ }
+ }
+
+ internal override int SizingBorderWidth
+ {
+ get { return Application.CurrentSkin.SizeBorderWidth; }
+ }
+
+ internal override Size SmallCaptionButtonSize
+ {
+ get
+ {
+ return new Size(32, 32);
+ }
+ }
+
+ internal override bool UIEffectsEnabled
+ {
+ get { return false; }
+ }
+
+ internal override int VerticalResizeBorderThickness
+ {
+ get { return 5; }
+ }
+
+ internal override void RaiseIdle(EventArgs e)
+ {
+ if (Idle != null)
+ Idle(this, e);
+ }
+
+ internal override Keys ModifierKeys
+ {
+ get
+ {
+ short state;
+ Keys key_state;
+
+ key_state = Keys.None;
+
+ return key_state;
+ }
+ }
+
+ internal override MouseButtons MouseButtons
+ {
+ get
+ {
+ return cosmos.MouseState;
+ }
+ }
+
+ internal override Point MousePosition
+ {
+ get
+ {
+ return new Point(cosmos.MouseX, cosmos.MouseY);
+ }
+ }
+
+ internal override Size MouseHoverSize
+ {
+ get
+ {
+ int width = 4;
+ int height = 4;
+ return new Size(width, height);
+ }
+ }
+
+ internal override int MouseHoverTime
+ {
+ get
+ {
+ int time = 500;
+ return time;
+ }
+ }
+
+ internal override int MouseWheelScrollDelta
+ {
+ get
+ {
+ int delta = 120;
+ return delta;
+ }
+ }
+
+ internal override int HorizontalScrollBarHeight
+ {
+ get
+ {
+ return scroll_height;
+ }
+ }
+
+ internal override bool UserClipWontExposeParent
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+
+ internal override int VerticalScrollBarWidth
+ {
+ get
+ {
+ return scroll_width;
+ }
+ }
+
+ internal override int MenuHeight
+ {
+ get
+ {
+ return 32;
+ }
+ }
+
+ internal override Size Border3DSize
+ {
+ get
+ {
+ return new Size(2, 2);
+ }
+ }
+
+ internal override Size BorderSize
+ {
+ get
+ {
+ return new Size(2, 2);
+ }
+ }
+
+ internal override bool DropTarget
+ {
+ get
+ {
+ return false;
+ }
+
+ set
+ {
+ if (value)
+ {
+ //throw new NotImplementedException("Need to figure out D'n'D for Win32");
+ }
+ }
+ }
+
+ internal override Size CaptionButtonSize
+ {
+ get
+ {
+ return new Size(64, 32);
+ }
+ }
+
+ internal override int CaptionHeight
+ {
+ get
+ {
+ return 35;
+ }
+ }
+
+ internal override Size CursorSize
+ {
+ get
+ {
+ return new Size(32, 32);
+ }
+ }
+
+ internal override bool DragFullWindows
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal override Size DragSize
+ {
+ get
+ {
+ return new Size(32, 32);
+ }
+ }
+
+ internal override Size DoubleClickSize
+ {
+ get
+ {
+ return new Size(36, 36); //thanks to @InternetUnexploder from the Cosmos Gitter chat, I know the raw value I need to put here :P
+ }
+ }
+
+ internal override int DoubleClickTime
+ {
+ get
+ {
+ return 1000;
+ }
+ }
+
+ internal override Size FixedFrameBorderSize
+ {
+ get
+ {
+ return new Size(2, 2);
+ }
+ }
+
+ internal override Size FrameBorderSize
+ {
+ get
+ {
+ return new Size(4, 4);
+ }
+ }
+
+ internal override Size IconSize
+ {
+ get
+ {
+ return new Size(16, 16);
+ }
+ }
+
+ internal override Size MaxWindowTrackSize
+ {
+ get
+ {
+ return new Size(59, 60);
+ }
+ }
+
+ internal override bool MenuAccessKeysUnderlined
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal override Size MinimizedWindowSize
+ {
+ get
+ {
+ return new Size(0, 0);
+ }
+ }
+
+ internal override Size MinimizedWindowSpacingSize
+ {
+ get
+ {
+ return new Size(0, 0);
+ }
+ }
+
+ internal override Size MinimumWindowSize
+ {
+ get
+ {
+ return new Size(50, 50);
+ }
+ }
+
+ internal override Size MinWindowTrackSize
+ {
+ get
+ {
+ return new Size(50, 50);
+ }
+ }
+
+ internal override Size SmallIconSize
+ {
+ get
+ {
+ return new Size(8, 8);
+ }
+ }
+
+ internal override int MouseButtonCount
+ {
+ get
+ {
+ return 3;
+ }
+ }
+
+ internal override bool MouseButtonsSwapped
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal override bool MouseWheelPresent
+ {
+ get
+ {
+ return cosmos.MouseWheelPressed;
+ }
+ }
+
+ internal override Rectangle VirtualScreen
+ {
+ get
+ {
+ var s = cosmos.GetScreenInfo();
+ return new Rectangle(s.X, s.Y, s.Width, s.Height);
+ }
+ }
+
+ internal override Rectangle WorkingArea
+ {
+ get
+ {
+ return VirtualScreen;
+ }
+ }
+
+ [MonoTODO]
+ internal override Screen[] AllScreens
+ {
+ get
+ {
+ // Can't use this sadly.
+ return null;
+ }
+ }
+
+ internal override bool ThemesEnabled
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ internal override bool RequiresPositiveClientAreaSize
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override int ToolWindowCaptionHeight
+ {
+ get
+ {
+ return 35; //Drawing will be done entirely by the developer itself. Do we really care about the tool window size?
+ }
+ }
+
+ public override Size ToolWindowCaptionButtonSize
+ {
+ get
+ {
+ return new Size(32, 32);
+ }
+ }
+#endregion // Static Properties
+
+#region Singleton Specific Code
+ public static XplatUICosmos GetInstance()
+ {
+ if (instance == null)
+ {
+ instance = new XplatUICosmos();
+ }
+ ref_count++;
+ return instance;
+ }
+
+ public int Reference
+ {
+ get
+ {
+ return ref_count;
+ }
+ }
+#endregion
+
+#region Public Static Methods
+ internal override IntPtr InitializeDriver()
+ {
+ cosmos.OnInit();
+ return IntPtr.Zero;
+ }
+
+ internal override void ShutdownDriver(IntPtr token)
+ {
+ Console.WriteLine("[ShiftUI] Stopping Cosmos driver...");
+ cosmos.OnShutdown();
+ }
+
+
+ internal void Version()
+ {
+ Console.WriteLine($"ShiftUI version {Application.ShiftUIVersionString}, running in the cosmos, on {cosmos.OSName} version {cosmos.OSVersionString}.");
+ }
+
+ string GetSoundAlias(AlertType alert)
+ {
+ return "";
+ }
+
+ internal override void AudibleAlert(AlertType alert)
+ {
+ //Cosmos cannot do audio.
+ }
+
+ internal override void BeginMoveResize(IntPtr handle)
+ {
+ //If the Mono devs that worked on the Win32 driver didn't know what this did, what
+ //makes you think I will?
+ }
+
+ internal override void GetDisplaySize(out Size size)
+ {
+ //get screen metrics from OS
+ var screen = cosmos.GetScreenInfo();
+ //push the data out.
+ size = new Size(screen.Width, screen.Height);
+ }
+
+ internal override void EnableThemes()
+ {
+ //Themes will forever be enabled.
+ }
+
+ //[MichaelComment(Message = "Yay. I just LOVE messing with Win32 stuff and porting it to Cosmos.")]
+ internal override IntPtr CreateWindow(CreateParams cp)
+ {
+ //I think I'll let this do it's thing it's own way but just change where the new Hwnd gets placed.
+ if (cosmos.Windows == null)
+ cosmos.Windows = new List<Hwnd>();
+ IntPtr WindowHandle;
+ IntPtr ParentHandle;
+ Hwnd hwnd;
+
+ hwnd = new Hwnd();
+
+ ParentHandle = cp.Parent;
+
+ if ((ParentHandle == IntPtr.Zero) && (cp.Style & (int)(WindowStyles.WS_CHILD)) != 0)
+ {
+ // We need to use our foster parent window until this poor child gets it's parent assigned
+ ParentHandle = GetFosterParent();
+ }
+
+ if (((cp.Style & (int)(WindowStyles.WS_CHILD | WindowStyles.WS_POPUP)) == 0) && ((cp.ExStyle & (int)WindowExStyles.WS_EX_APPWINDOW) == 0))
+ {
+ // If we want to be hidden from the taskbar we need to be 'owned' by
+ // something not on the taskbar. FosterParent is just that
+ ParentHandle = GetFosterParent();
+ }
+
+ Point location;
+ if (cp.HasWindowManager)
+ {
+ location = Hwnd.GetNextStackedFormLocation(cp, Hwnd.ObjectFromHandle(cp.Parent));
+ }
+ else
+ {
+ location = new Point(cp.X, cp.Y);
+ }
+
+ string class_name = RegisterWindowClass(cp.ClassStyle);
+ HwndCreating = hwnd;
+
+ // We cannot actually send the WS_EX_MDICHILD flag to Windows because we
+ // are faking MDI, not uses Windows' version.
+ if ((cp.WindowExStyle & WindowExStyles.WS_EX_MDICHILD) == WindowExStyles.WS_EX_MDICHILD)
+ cp.WindowExStyle ^= WindowExStyles.WS_EX_MDICHILD;
+
+ WindowHandle = cosmos.Windows.Count + 1;
+
+ HwndCreating = null;
+
+ if (WindowHandle == IntPtr.Zero)
+ {
+ MessageBox.Show("An error happened while showing a window... Fascinating.", "Fatal error.");
+ }
+
+ hwnd.ClientWindow = WindowHandle;
+ hwnd.Mapped = true;
+ cosmos.Windows.Add(hwnd);
+
+ return WindowHandle;
+ }
+
+ 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 void DestroyWindow(IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ foreach(var win in cosmos.Windows)
+ {
+ if (win.Handle == handle)
+ hwnd = win;
+ }
+ if (hwnd == null)
+ MessageBox.Show("An error occurred while destroying a window.", "Fatal error.");
+ cosmos.Windows.Remove(hwnd);
+ cosmos.OnDestroyWindow(hwnd); //tell the OS to redraw that area...
+ hwnd.Dispose();
+ return;
+ }
+
+ internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max)
+ {
+ // We do nothing, Form has to handle WM_GETMINMAXINFO
+ }
+
+
+ internal override FormWindowState GetWindowState(IntPtr handle)
+ {
+ CosmosWindowStyle style;
+
+ style = cosmos.GetWindowState(handle);
+ switch(style)
+ {
+ case CosmosWindowStyle.Maximized:
+ return FormWindowState.Maximized;
+ case CosmosWindowStyle.Minimized:
+ return FormWindowState.Minimized;
+ }
+ return FormWindowState.Normal;
+ }
+
+ internal override void SetWindowState(IntPtr hwnd, FormWindowState state)
+ {
+ switch (state)
+ {
+ case FormWindowState.Normal:
+ {
+ Win32ShowWindow(hwnd, WindowPlacementFlags.SW_RESTORE);
+ return;
+ }
+
+ case FormWindowState.Minimized:
+ {
+ Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MINIMIZE);
+ return;
+ }
+
+ case FormWindowState.Maximized:
+ {
+ Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MAXIMIZE);
+ return;
+ }
+ }
+ }
+
+ internal override void SetWindowStyle(IntPtr handle, CreateParams cp)
+ {
+
+ Win32SetWindowLong(handle, WindowLong.GWL_STYLE, (uint)cp.Style);
+ Win32SetWindowLong(handle, WindowLong.GWL_EXSTYLE, (uint)cp.ExStyle);
+
+ // From MSDN:
+ // Certain window data is cached, so changes you make using SetWindowLong
+ // will not take effect until you call the SetWindowPos function. Specifically,
+ // if you change any of the frame styles, you must call SetWindowPos with
+ // the SWP_FRAMECHANGED flag for the cache to be updated properly.
+ if (cp.control is Form)
+ XplatUI.RequestNCRecalc(handle);
+ }
+
+ 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);
+ COLORREF clrRef = new COLORREF();
+ if (key != Color.Empty)
+ {
+ clrRef.R = key.R;
+ clrRef.G = key.G;
+ clrRef.B = key.B;
+ lwa = (LayeredWindowAttributes)((int)lwa | (int)LayeredWindowAttributes.LWA_COLORKEY);
+ }
+ RECT rc;
+ rc.right = 1000;
+ rc.bottom = 1000;
+ Win32SetLayeredWindowAttributes(handle, clrRef, opacity, lwa);
+ }
+
+ 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)
+ {
+ Win32UpdateWindow(handle);
+ }
+
+ internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client)
+ {
+ IntPtr hdc;
+ PAINTSTRUCT ps;
+ PaintEventArgs paint_event;
+ RECT rect;
+ Rectangle clip_rect;
+ Hwnd hwnd;
+
+ clip_rect = new Rectangle();
+ rect = new RECT();
+ ps = new PAINTSTRUCT();
+
+ hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
+
+ if (client)
+ {
+ if (Win32GetUpdateRect(msg.HWnd, ref rect, false))
+ {
+ if (handle != msg.HWnd)
+ {
+ // We need to validate the window where the paint message
+ // was generated, otherwise we'll never stop getting paint
+ // messages.
+ Win32GetClientRect(msg.HWnd, out rect);
+ Win32ValidateRect(msg.HWnd, ref rect);
+ hdc = Win32GetDC(handle);
+ }
+ else
+ {
+ hdc = Win32BeginPaint(handle, ref ps);
+ rect = ps.rcPaint;
+ }
+ }
+ else
+ {
+ hdc = Win32GetDC(handle);
+ }
+ clip_rect = rect.ToRectangle();
+ }
+ else
+ {
+ hdc = Win32GetWindowDC(handle);
+
+ // HACK this in for now
+ Win32GetWindowRect(handle, out rect);
+ clip_rect = new Rectangle(0, 0, rect.Width, rect.Height);
+ }
+
+ // If we called BeginPaint, store the PAINTSTRUCT,
+ // otherwise store hdc, so that PaintEventEnd can know
+ // whether to call EndPaint or ReleaseDC.
+ if (ps.hdc != IntPtr.Zero)
+ {
+ hwnd.drawing_stack.Push(ps);
+ }
+ else
+ {
+ hwnd.drawing_stack.Push(hdc);
+ }
+
+ Graphics dc = Graphics.FromHdc(hdc);
+ hwnd.drawing_stack.Push(dc);
+
+ paint_event = new PaintEventArgs(dc, clip_rect);
+
+ return paint_event;
+ }
+
+ internal override void PaintEventEnd(ref Message m, IntPtr handle, bool client)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(m.HWnd);
+
+ Graphics dc = (Graphics)hwnd.drawing_stack.Pop();
+ dc.Dispose();
+
+ object o = hwnd.drawing_stack.Pop();
+ if (o is IntPtr)
+ {
+ IntPtr hdc = (IntPtr)o;
+ Win32ReleaseDC(handle, hdc);
+ }
+ else if (o is PAINTSTRUCT)
+ {
+ PAINTSTRUCT ps = (PAINTSTRUCT)o;
+ Win32EndPaint(handle, ref ps);
+ }
+ }
+
+
+ internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height)
+ {
+ Win32MoveWindow(handle, x, y, width, height, true);
+ return;
+ }
+
+ 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)
+ {
+ IntPtr parent;
+ RECT rect;
+ POINT pt;
+
+ Win32GetWindowRect(handle, out rect);
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+
+ pt.x = rect.left;
+ pt.y = rect.top;
+
+ parent = Win32GetAncestor(handle, AncestorType.GA_PARENT);
+ if (parent != IntPtr.Zero && parent != Win32GetDesktopWindow())
+ Win32ScreenToClient(parent, ref pt);
+
+ x = pt.x;
+ y = pt.y;
+
+ Win32GetClientRect(handle, out rect);
+ client_width = rect.right - rect.left;
+ client_height = rect.bottom - rect.top;
+ return;
+ }
+
+ internal override void Activate(IntPtr handle)
+ {
+ Win32SetActiveWindow(handle);
+ // delayed timer enabled
+ lock (timer_list)
+ {
+ foreach (Timer t in timer_list.Values)
+ {
+ if (t.Enabled && t.window == IntPtr.Zero)
+ {
+ t.window = handle;
+ int id = t.GetHashCode();
+ Win32SetTimer(handle, id, (uint)t.Interval, IntPtr.Zero);
+ }
+ }
+ }
+ }
+
+ internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear)
+ {
+ cosmos.Redraw(); //I don't want to make it too hard for devs to deal with this...
+ }
+
+
+ internal override void InvalidateNC(IntPtr handle)
+ {
+ cosmos.Redraw();
+ }
+
+ private IntPtr InternalWndProc(IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam)
+ {
+ if (HwndCreating != null && HwndCreating.ClientWindow == IntPtr.Zero)
+ HwndCreating.ClientWindow = hWnd;
+ return NativeWindow.WndProc(hWnd, msg, wParam, lParam);
+ }
+
+ internal override IntPtr DefWndProc(ref Message msg)
+ {
+ msg.Result = Win32DefWindowProc(msg.HWnd, (Msg)msg.Msg, msg.WParam, msg.LParam);
+ return msg.Result;
+ }
+
+ internal override void HandleException(Exception e)
+ {
+ StackTrace st = new StackTrace(e);
+ Win32MessageBox(IntPtr.Zero, e.Message + st.ToString(), "Exception", 0);
+ Console.WriteLine("{0}{1}", e.Message, st.ToString());
+ }
+
+ internal override void DoEvents()
+ {
+ MSG msg = new MSG();
+
+ while (GetMessage(ref msg, IntPtr.Zero, 0, 0, false))
+ {
+ Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
+
+ if (Application.FilterMessage(ref m))
+ continue;
+
+ XplatUI.TranslateMessage(ref msg);
+ XplatUI.DispatchMessage(ref msg);
+ }
+ }
+
+ internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
+ {
+ return Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, flags);
+ }
+
+ internal override void PostQuitMessage(int exitCode)
+ {
+ 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 | SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE);
+ }
+
+ internal override void ResetMouseHover(IntPtr handle)
+ {
+ TRACKMOUSEEVENT tme;
+
+ tme = new TRACKMOUSEEVENT();
+ tme.size = Marshal.SizeOf(tme);
+ tme.hWnd = handle;
+ tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER;
+ Win32TrackMouseEvent(ref tme);
+ }
+
+
+ internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax)
+ {
+ return GetMessage(ref msg, hWnd, wFilterMin, wFilterMax, true);
+ }
+
+ private bool GetMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, bool blocking)
+ {
+ bool result;
+
+ msg.refobject = 0;
+ if (RetrieveMessage(ref msg))
+ {
+ return true;
+ }
+
+ if (blocking)
+ {
+ result = Win32GetMessage(ref msg, hWnd, wFilterMin, wFilterMax);
+ }
+ else
+ {
+ result = Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, (uint)PeekMessageFlags.PM_REMOVE);
+ if (!result)
+ {
+ return false;
+ }
+ }
+
+ // We need to fake WM_MOUSE_ENTER
+ switch (msg.message)
+ {
+ case Msg.WM_LBUTTONDOWN:
+ {
+ mouse_state |= MouseButtons.Left;
+ break;
+ }
+
+ case Msg.WM_MBUTTONDOWN:
+ {
+ mouse_state |= MouseButtons.Middle;
+ break;
+ }
+
+ case Msg.WM_RBUTTONDOWN:
+ {
+ mouse_state |= MouseButtons.Right;
+ break;
+ }
+
+ case Msg.WM_LBUTTONUP:
+ {
+ mouse_state &= ~MouseButtons.Left;
+ break;
+ }
+
+ case Msg.WM_MBUTTONUP:
+ {
+ mouse_state &= ~MouseButtons.Middle;
+ break;
+ }
+
+ case Msg.WM_RBUTTONUP:
+ {
+ mouse_state &= ~MouseButtons.Right;
+ break;
+ }
+
+ case Msg.WM_ASYNC_MESSAGE:
+ {
+ XplatUIDriverSupport.ExecuteClientMessage((GCHandle)msg.lParam);
+ break;
+ }
+
+ case Msg.WM_MOUSEMOVE:
+ {
+ if (msg.hwnd != prev_mouse_hwnd)
+ {
+ TRACKMOUSEEVENT tme;
+
+ mouse_state = Widget.FromParamToMouseButtons((int)msg.lParam.ToInt32());
+
+ // The current message will be sent out next time around
+ StoreMessage(ref msg);
+
+ // This is the message we want to send at this point
+ msg.message = Msg.WM_MOUSE_ENTER;
+
+ prev_mouse_hwnd = msg.hwnd;
+
+ tme = new TRACKMOUSEEVENT();
+ tme.size = Marshal.SizeOf(tme);
+ tme.hWnd = msg.hwnd;
+ tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER;
+ Win32TrackMouseEvent(ref tme);
+ return result;
+ }
+ break;
+ }
+
+ case Msg.WM_NCMOUSEMOVE:
+ {
+ if (wm_nc_registered == null || !wm_nc_registered.Contains(msg.hwnd))
+ break;
+
+ mouse_state = Widget.FromParamToMouseButtons((int)msg.lParam.ToInt32());
+
+ 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);
+ }
+
+ case Msg.WM_MOUSELEAVE:
+ {
+ prev_mouse_hwnd = IntPtr.Zero;
+ break;
+ }
+
+ case Msg.WM_TIMER:
+ {
+ Timer timer = (Timer)timer_list[(int)msg.wParam];
+
+ if (timer != null)
+ {
+ timer.FireTick();
+ }
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ internal override bool TranslateMessage(ref MSG msg)
+ {
+ return Win32TranslateMessage(ref msg);
+ }
+
+ internal override IntPtr DispatchMessage(ref MSG msg)
+ {
+ return Win32DispatchMessage(ref msg);
+ }
+
+ internal override bool SetZOrder(IntPtr hWnd, IntPtr AfterhWnd, bool Top, bool Bottom)
+ {
+ if (Top)
+ {
+ Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOP, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ return true;
+ }
+ else if (!Bottom)
+ {
+ Win32SetWindowPos(hWnd, AfterhWnd, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ }
+ else
+ {
+ Win32SetWindowPos(hWnd, (IntPtr)SetWindowPosZOrder.HWND_BOTTOM, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ return true;
+ }
+ return false;
+ }
+
+ internal override bool SetTopmost(IntPtr hWnd, bool Enabled)
+ {
+ if (Enabled)
+ {
+ Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
+ return true;
+ }
+ else
+ {
+ Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_NOTOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
+ return true;
+ }
+ }
+
+ internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner)
+ {
+ Win32SetWindowLong(hWnd, WindowLong.GWL_HWNDPARENT, (uint)hWndOwner);
+ return true;
+ }
+
+ internal override bool Text(IntPtr handle, string text)
+ {
+ Win32SetWindowText(handle, text);
+ return true;
+ }
+
+ internal override bool GetText(IntPtr handle, out string text)
+ {
+ StringBuilder sb;
+
+ sb = new StringBuilder(256);
+ Win32GetWindowText(handle, sb, sb.Capacity);
+ text = sb.ToString();
+ return true;
+ }
+
+ internal override bool SetVisible(IntPtr handle, bool visible, bool activate)
+ {
+ if (visible)
+ {
+ Widget c = Widget.FromHandle(handle);
+ if (c is Form)
+ {
+ Form f;
+
+ f = (Form)Widget.FromHandle(handle);
+ WindowPlacementFlags flags = WindowPlacementFlags.SW_SHOWNORMAL;
+ switch (f.WindowState)
+ {
+ case FormWindowState.Normal: flags = WindowPlacementFlags.SW_SHOWNORMAL; break;
+ case FormWindowState.Minimized: flags = WindowPlacementFlags.SW_MINIMIZE; break;
+ case FormWindowState.Maximized: flags = WindowPlacementFlags.SW_MAXIMIZE; break;
+ }
+
+ if (!f.ActivateOnShow)
+ flags = WindowPlacementFlags.SW_SHOWNOACTIVATE;
+
+ Win32ShowWindow(handle, flags);
+ }
+ else
+ {
+ if (c.ActivateOnShow)
+ Win32ShowWindow(handle, WindowPlacementFlags.SW_SHOWNORMAL);
+ else
+ Win32ShowWindow(handle, WindowPlacementFlags.SW_SHOWNOACTIVATE);
+ }
+ }
+ else
+ {
+ Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE);
+ }
+ return true;
+ }
+
+ internal override bool IsEnabled(IntPtr handle)
+ {
+ return IsWindowEnabled(handle);
+ }
+
+ internal override bool IsKeyLocked(VirtualKeys key)
+ {
+ return (Win32GetKeyState(key) & 1) == 1;
+ }
+
+ internal override bool IsVisible(IntPtr handle)
+ {
+ return IsWindowVisible(handle);
+ }
+
+ internal override IntPtr SetParent(IntPtr handle, IntPtr parent)
+ {
+ Widget c = Widget.FromHandle(handle);
+ if (parent == IntPtr.Zero)
+ {
+ if (!(c is Form))
+ {
+ Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE);
+ }
+ }
+ else
+ {
+ if (!(c is Form))
+ {
+ SetVisible(handle, c.is_visible, true);
+ }
+ }
+ // The Win32SetParent is lame, it can very well move the window
+ // ref: http://groups.google.com/group/microsoft.public.vb.winapi/browse_thread/thread/1b82ccc54231ecee/afa82835bfc0422a%23afa82835bfc0422a
+ // Here we save the position before changing the parent, and if it has changed afterwards restore it.
+ // Another possibility would be to intercept WM_WINDOWPOSCHANGING and restore the coords there, but this would require plumbing in weird places
+ // (either inside Widget or add handling to InternalWndProc)
+ // We also need to remove WS_CHILD if making the window parent-less, and add it if we're parenting it.
+ RECT rect, rect2;
+ IntPtr result;
+ WindowStyles style, new_style;
+
+ Win32GetWindowRect(handle, out rect);
+ style = (WindowStyles)Win32GetWindowLong(handle, WindowLong.GWL_STYLE);
+
+ if (parent == IntPtr.Zero)
+ {
+ new_style = style & ~WindowStyles.WS_CHILD;
+ result = Win32SetParent(handle, GetFosterParent());
+ }
+ else
+ {
+ new_style = style | WindowStyles.WS_CHILD;
+ result = Win32SetParent(handle, parent);
+ }
+ if (style != new_style && c is Form)
+ {
+ Win32SetWindowLong(handle, WindowLong.GWL_STYLE, (uint)new_style);
+ }
+ Win32GetWindowRect(handle, out rect2);
+ if (rect.top != rect2.top && rect.left != rect2.left && c is Form)
+ {
+ Win32SetWindowPos(handle, IntPtr.Zero, rect.top, rect.left, rect.Width, rect.Height, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOENDSCHANGING | SetWindowPosFlags.SWP_NOACTIVATE);
+ }
+ return result;
+ }
+
+ // If we ever start using this, we should probably replace FosterParent with IntPtr.Zero
+ internal override IntPtr GetParent(IntPtr handle)
+ {
+ return Win32GetParent(handle);
+ }
+
+ // This is a nop on win32 and x11
+ internal override IntPtr GetPreviousWindow(IntPtr handle)
+ {
+ return handle;
+ }
+
+ internal override void GrabWindow(IntPtr hWnd, IntPtr ConfineToHwnd)
+ {
+ grab_hwnd = hWnd;
+ Win32SetCapture(hWnd);
+
+ if (ConfineToHwnd != IntPtr.Zero)
+ {
+ RECT window_rect;
+ Win32GetWindowRect(ConfineToHwnd, out window_rect);
+ Win32GetClipCursor(out clipped_cursor_rect);
+ Win32ClipCursor(ref window_rect);
+ }
+ }
+
+ internal override void GrabInfo(out IntPtr hWnd, out bool GrabConfined, out Rectangle GrabArea)
+ {
+ hWnd = grab_hwnd;
+ GrabConfined = grab_confined;
+ GrabArea = grab_area;
+ }
+
+ internal override void UngrabWindow(IntPtr hWnd)
+ {
+ if (!(clipped_cursor_rect.top == 0 && clipped_cursor_rect.bottom == 0 && clipped_cursor_rect.left == 0 && clipped_cursor_rect.right == 0))
+ {
+ Win32ClipCursor(ref clipped_cursor_rect);
+ clipped_cursor_rect = new RECT();
+ }
+
+ Win32ReleaseCapture();
+ grab_hwnd = IntPtr.Zero;
+ }
+
+ internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect)
+ {
+ RECT rect;
+
+ rect.left = ClientRect.Left;
+ rect.top = ClientRect.Top;
+ rect.right = ClientRect.Right;
+ rect.bottom = ClientRect.Bottom;
+
+ if (!Win32AdjustWindowRectEx(ref rect, cp.Style, menu != null, cp.ExStyle))
+ {
+ WindowRect = new Rectangle(ClientRect.Left, ClientRect.Top, ClientRect.Width, ClientRect.Height);
+ return false;
+ }
+
+ WindowRect = new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ return true;
+ }
+
+ internal override void SetCursor(IntPtr window, IntPtr cursor)
+ {
+ Win32SetCursor(cursor);
+ return;
+ }
+
+ internal override void ShowCursor(bool show)
+ {
+ Win32ShowCursor(show);
+ }
+
+ internal override void OverrideCursor(IntPtr cursor)
+ {
+ Win32SetCursor(cursor);
+ }
+
+ internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
+ {
+ IntPtr cursor;
+ Bitmap cursor_bitmap;
+ Bitmap cursor_mask;
+ Byte[] cursor_bits;
+ Byte[] mask_bits;
+ Color pixel;
+ int width;
+ int height;
+
+ // Win32 only allows creation cursors of a certain size
+ if ((bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)) || (bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)))
+ {
+ cursor_bitmap = new Bitmap(bitmap, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)));
+ cursor_mask = new Bitmap(mask, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)));
+ }
+ else
+ {
+ cursor_bitmap = bitmap;
+ cursor_mask = mask;
+ }
+
+ width = cursor_bitmap.Width;
+ height = cursor_bitmap.Height;
+
+ cursor_bits = new Byte[(width / 8) * height];
+ mask_bits = new Byte[(width / 8) * height];
+
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ pixel = cursor_bitmap.GetPixel(x, y);
+
+ if (pixel == cursor_pixel)
+ {
+ cursor_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8));
+ }
+
+ pixel = cursor_mask.GetPixel(x, y);
+
+ if (pixel == mask_pixel)
+ {
+ mask_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8));
+ }
+ }
+ }
+
+ cursor = Win32CreateCursor(IntPtr.Zero, xHotSpot, yHotSpot, width, height, mask_bits, cursor_bits);
+
+ return cursor;
+ }
+
+ internal override Bitmap DefineStdCursorBitmap(StdCursor id)
+ {
+ // We load the cursor, create a bitmap, draw the cursor onto the bitmap and return the bitmap.
+ IntPtr cursor = DefineStdCursor(id);
+ // Windows only have one possible cursor size!
+ int width = Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR);
+ int height = Win32GetSystemMetrics(SystemMetrics.SM_CYCURSOR);
+ Bitmap bmp = new Bitmap(width, height);
+ Graphics gc = Graphics.FromImage(bmp);
+ IntPtr hdc = gc.GetHdc();
+ Win32DrawIcon(hdc, 0, 0, cursor);
+ gc.ReleaseHdc(hdc);
+ gc.Dispose();
+ return bmp;
+ }
+
+ [MonoTODO("Define the missing cursors")]
+ internal override IntPtr DefineStdCursor(StdCursor id)
+ {
+ switch (id)
+ {
+ case StdCursor.AppStarting: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_APPSTARTING);
+ case StdCursor.Arrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW);
+ case StdCursor.Cross: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_CROSS);
+ case StdCursor.Default: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW);
+ case StdCursor.Hand: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HAND);
+ case StdCursor.Help: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HELP);
+ case StdCursor.HSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.IBeam: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_IBEAM);
+ case StdCursor.No: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_NO);
+ case StdCursor.NoMove2D: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.NoMoveHoriz: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.NoMoveVert: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanEast: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanNE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanNorth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanNW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanSouth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanSW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanWest: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.SizeAll: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEALL);
+ case StdCursor.SizeNESW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENESW);
+ case StdCursor.SizeNS: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENS);
+ case StdCursor.SizeNWSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENWSE);
+ case StdCursor.SizeWE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEWE);
+ case StdCursor.UpArrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_UPARROW);
+ case StdCursor.VSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.WaitCursor: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_WAIT);
+ }
+ throw new NotImplementedException();
+ }
+
+ internal override void DestroyCursor(IntPtr cursor)
+ {
+ if ((cursor.ToInt32() < (int)LoadCursorType.First) || (cursor.ToInt32() > (int)LoadCursorType.Last))
+ {
+ Win32DestroyCursor(cursor);
+ }
+ }
+
+ [MonoTODO]
+ internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y)
+ {
+ ICONINFO ii = new ICONINFO();
+
+ if (!Win32GetIconInfo(cursor, out ii))
+ throw new Win32Exception();
+
+ width = 20;
+ height = 20;
+ hotspot_x = ii.xHotspot;
+ hotspot_y = ii.yHotspot;
+ }
+
+ internal override void SetCursorPos(IntPtr handle, int x, int y)
+ {
+ Win32SetCursorPos(x, y);
+ }
+
+ internal override Region GetClipRegion(IntPtr hwnd)
+ {
+ Region region;
+
+ region = new Region();
+
+ Win32GetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd)));
+
+ return region;
+ }
+
+ internal override void SetClipRegion(IntPtr hwnd, Region region)
+ {
+ if (region == null)
+ Win32SetWindowRgn(hwnd, IntPtr.Zero, true);
+ else
+ Win32SetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd)), true);
+ }
+
+ internal override void EnableWindow(IntPtr handle, bool Enable)
+ {
+ Win32EnableWindow(handle, Enable);
+ }
+
+ internal override void EndLoop(System.Threading.Thread thread)
+ {
+ // Nothing to do
+ }
+
+ internal override object StartLoop(System.Threading.Thread thread)
+ {
+ return null;
+ }
+
+ internal override void SetModal(IntPtr handle, bool Modal)
+ {
+ // we do nothing on Win32
+ }
+
+ internal override void GetCursorPos(IntPtr handle, out int x, out int y)
+ {
+ POINT pt;
+
+ Win32GetCursorPos(out pt);
+
+ if (handle != IntPtr.Zero)
+ {
+ Win32ScreenToClient(handle, ref pt);
+ }
+
+ x = pt.x;
+ y = pt.y;
+ }
+
+ internal override void ScreenToClient(IntPtr handle, ref int x, ref int y)
+ {
+ POINT pnt = new POINT();
+
+ pnt.x = x;
+ pnt.y = y;
+ Win32ScreenToClient(handle, ref pnt);
+
+ x = pnt.x;
+ y = pnt.y;
+ }
+
+ internal override void ClientToScreen(IntPtr handle, ref int x, ref int y)
+ {
+ POINT pnt = new POINT();
+
+ pnt.x = x;
+ pnt.y = y;
+
+ Win32ClientToScreen(handle, ref pnt);
+
+ x = pnt.x;
+ y = pnt.y;
+ }
+
+ internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y)
+ {
+ RECT rect;
+
+ Win32GetWindowRect(handle, out rect);
+ x -= rect.left + SystemInformation.FrameBorderSize.Width;
+ y -= rect.top + SystemInformation.FrameBorderSize.Height;
+
+ WindowStyles style = (WindowStyles)Win32GetWindowLong(handle, WindowLong.GWL_STYLE);
+ if (CreateParams.IsSet(style, WindowStyles.WS_CAPTION))
+ {
+ y -= ThemeEngine.Current.CaptionHeight;
+ }
+ }
+
+ internal override void MenuToScreen(IntPtr handle, ref int x, ref int y)
+ {
+ RECT rect;
+
+ Win32GetWindowRect(handle, out rect);
+ x += rect.left + SystemInformation.FrameBorderSize.Width;
+ y += rect.top + SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight;
+ return;
+ }
+
+ internal override void SendAsyncMethod(AsyncMethodData method)
+ {
+ Win32PostMessage(GetFosterParent(), Msg.WM_ASYNC_MESSAGE, IntPtr.Zero, (IntPtr)GCHandle.Alloc(method));
+ }
+
+ internal override void SetTimer(Timer timer)
+ {
+ IntPtr FosterParent = GetFosterParent();
+ int index;
+
+ index = timer.GetHashCode();
+
+ lock (timer_list)
+ {
+ timer_list[index] = timer;
+ }
+
+ if (Win32SetTimer(FosterParent, index, (uint)timer.Interval, IntPtr.Zero) != IntPtr.Zero)
+ timer.window = FosterParent;
+ else
+ timer.window = IntPtr.Zero;
+ }
+
+ internal override void KillTimer(Timer timer)
+ {
+ int index;
+
+ index = timer.GetHashCode();
+
+ Win32KillTimer(timer.window, index);
+
+ lock (timer_list)
+ {
+ timer_list.Remove(index);
+ }
+ }
+
+ internal override void CreateCaret(IntPtr hwnd, int width, int height)
+ {
+ Win32CreateCaret(hwnd, IntPtr.Zero, width, height);
+ caret_visible = false;
+ }
+
+ internal override void DestroyCaret(IntPtr hwnd)
+ {
+ Win32DestroyCaret();
+ }
+
+ internal override void SetCaretPos(IntPtr hwnd, int x, int y)
+ {
+ Win32SetCaretPos(x, y);
+ }
+
+ internal override void CaretVisible(IntPtr hwnd, bool visible)
+ {
+ if (visible)
+ {
+ if (!caret_visible)
+ {
+ Win32ShowCaret(hwnd);
+ caret_visible = true;
+ }
+ }
+ else
+ {
+ if (caret_visible)
+ {
+ Win32HideCaret(hwnd);
+ caret_visible = false;
+ }
+ }
+ }
+
+ internal override IntPtr GetFocus()
+ {
+ return Win32GetFocus();
+ }
+
+ internal override void SetFocus(IntPtr hwnd)
+ {
+ Win32SetFocus(hwnd);
+ }
+
+ internal override IntPtr GetActive()
+ {
+ return Win32GetActiveWindow();
+ }
+
+ internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent)
+ {
+ IntPtr dc;
+ IntPtr prevobj;
+ TEXTMETRIC tm;
+
+ tm = new TEXTMETRIC();
+
+ dc = Win32GetDC(IntPtr.Zero);
+ prevobj = Win32SelectObject(dc, font.ToHfont());
+
+ if (Win32GetTextMetrics(dc, ref tm) == false)
+ {
+ prevobj = Win32SelectObject(dc, prevobj);
+ Win32DeleteObject(prevobj);
+ Win32ReleaseDC(IntPtr.Zero, dc);
+ ascent = 0;
+ descent = 0;
+ return false;
+ }
+ prevobj = Win32SelectObject(dc, prevobj);
+ Win32DeleteObject(prevobj);
+ Win32ReleaseDC(IntPtr.Zero, dc);
+
+ ascent = tm.tmAscent;
+ descent = tm.tmDescent;
+
+ return true;
+ }
+
+ internal override void ScrollWindow(IntPtr hwnd, Rectangle rectangle, int XAmount, int YAmount, bool with_children)
+ {
+ RECT rect;
+
+ rect = new RECT();
+ rect.left = rectangle.X;
+ rect.top = rectangle.Y;
+ rect.right = rectangle.Right;
+ rect.bottom = rectangle.Bottom;
+
+ Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, ref rect, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE));
+ Win32UpdateWindow(hwnd);
+ }
+
+ internal override void ScrollWindow(IntPtr hwnd, int XAmount, int YAmount, bool with_children)
+ {
+ Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE));
+ }
+
+ internal override bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt)
+ {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uCallbackMessage = (uint)Msg.WM_USER;
+ nid.uFlags = NotifyIconFlags.NIF_MESSAGE;
+
+ if (tip != null)
+ {
+ nid.szTip = tip;
+ nid.uFlags |= NotifyIconFlags.NIF_TIP;
+ }
+
+ if (icon != null)
+ {
+ nid.hIcon = icon.Handle;
+ nid.uFlags |= NotifyIconFlags.NIF_ICON;
+ }
+
+ tt = null;
+
+ return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_ADD, ref nid);
+ }
+
+ internal override bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt)
+ {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hIcon = icon.Handle;
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uCallbackMessage = (uint)Msg.WM_USER;
+ nid.uFlags = NotifyIconFlags.NIF_MESSAGE;
+
+ if (tip != null)
+ {
+ nid.szTip = tip;
+ nid.uFlags |= NotifyIconFlags.NIF_TIP;
+ }
+
+ if (icon != null)
+ {
+ nid.hIcon = icon.Handle;
+ nid.uFlags |= NotifyIconFlags.NIF_ICON;
+ }
+
+ return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid);
+ }
+
+ internal override void SystrayRemove(IntPtr hwnd, ref ToolTip tt)
+ {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uFlags = 0;
+
+ Win32Shell_NotifyIcon(NotifyIconMessage.NIM_DELETE, ref nid);
+ }
+
+ internal override void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon)
+ {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uFlags = NotifyIconFlags.NIF_INFO;
+ nid.uTimeoutOrVersion = timeout;
+ nid.szInfoTitle = title;
+ nid.szInfo = text;
+ nid.dwInfoFlags = icon;
+
+ Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid);
+ }
+
+ internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style)
+ {
+ // Nothing to do on Win32
+ }
+
+ internal override void SetMenu(IntPtr handle, Menu menu)
+ {
+ // Trigger WM_NCCALC
+ Win32SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ }
+
+ internal override Point GetMenuOrigin(IntPtr handle)
+ {
+ Form form = Widget.FromHandle(handle) as Form;
+
+ if (form != null)
+ {
+ if (form.FormBorderStyle == FormBorderStyle.None)
+ return Point.Empty;
+
+ int bordersize = (form.Width - form.ClientSize.Width) / 2;
+
+ if (form.FormBorderStyle == FormBorderStyle.FixedToolWindow || form.FormBorderStyle == FormBorderStyle.SizableToolWindow)
+ return new Point(bordersize, bordersize + SystemInformation.ToolWindowCaptionHeight);
+ else
+ return new Point(bordersize, bordersize + SystemInformation.CaptionHeight);
+ }
+
+ return new Point(SystemInformation.FrameBorderSize.Width, SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight);
+ }
+
+ internal override void SetIcon(IntPtr hwnd, Icon icon)
+ {
+ Win32SendMessage(hwnd, Msg.WM_SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : icon.Handle); // 1 = large icon (0 would be small)
+ }
+
+ internal override void ClipboardClose(IntPtr handle)
+ {
+ if (handle != clip_magic)
+ {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+ Win32CloseClipboard();
+ }
+
+ internal override int ClipboardGetID(IntPtr handle, string format)
+ {
+ if (handle != clip_magic)
+ {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+ if (format == "Text") return 1;
+ else if (format == "Bitmap") return 2;
+ else if (format == "MetaFilePict") return 3;
+ else if (format == "SymbolicLink") return 4;
+ else if (format == "DataInterchangeFormat") return 5;
+ else if (format == "Tiff") return 6;
+ else if (format == "OEMText") return 7;
+ else if (format == "DeviceIndependentBitmap") return 8;
+ else if (format == "Palette") return 9;
+ else if (format == "PenData") return 10;
+ else if (format == "RiffAudio") return 11;
+ else if (format == "WaveAudio") return 12;
+ else if (format == "UnicodeText") return 13;
+ else if (format == "EnhancedMetafile") return 14;
+ else if (format == "FileDrop") return 15;
+ else if (format == "Locale") return 16;
+
+ return (int)Win32RegisterClipboardFormat(format);
+ }
+
+ internal override IntPtr ClipboardOpen(bool primary_selection)
+ {
+ // Win32 does not have primary selection
+ Win32OpenClipboard(GetFosterParent());
+ return clip_magic;
+ }
+
+ internal override int[] ClipboardAvailableFormats(IntPtr handle)
+ {
+ uint format;
+ int[] result;
+ int count;
+
+ if (handle != clip_magic)
+ {
+ return null;
+ }
+
+ // Count first
+ count = 0;
+ format = 0;
+ do
+ {
+ format = Win32EnumClipboardFormats(format);
+ if (format != 0)
+ {
+ count++;
+ }
+ } while (format != 0);
+
+ // Now assign
+ result = new int[count];
+ count = 0;
+ format = 0;
+ do
+ {
+ format = Win32EnumClipboardFormats(format);
+ if (format != 0)
+ {
+ result[count++] = (int)format;
+ }
+ } while (format != 0);
+
+ return result;
+ }
+
+
+ internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter)
+ {
+ IntPtr hmem;
+ IntPtr data;
+ object obj;
+
+ if (handle != clip_magic)
+ {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+
+ hmem = Win32GetClipboardData((uint)type);
+ if (hmem == IntPtr.Zero)
+ {
+ return null;
+ }
+
+ data = Win32GlobalLock(hmem);
+ if (data == IntPtr.Zero)
+ {
+ uint error = Win32GetLastError();
+ Console.WriteLine("Error: {0}", error);
+ return null;
+ }
+
+ obj = null;
+
+ if (type == DataFormats.GetFormat(DataFormats.Rtf).Id)
+ {
+ obj = AnsiToString(data);
+ }
+ else switch ((ClipboardFormats)type)
+ {
+ case ClipboardFormats.CF_TEXT:
+ {
+ obj = AnsiToString(data);
+ break;
+ }
+
+ case ClipboardFormats.CF_DIB:
+ {
+ obj = DIBtoImage(data);
+ break;
+ }
+
+ case ClipboardFormats.CF_UNICODETEXT:
+ {
+ obj = UnicodeToString(data);
+ break;
+ }
+
+ default:
+ {
+ if (converter != null && !converter(type, data, out obj))
+ {
+ obj = null;
+ }
+ break;
+ }
+ }
+ Win32GlobalUnlock(hmem);
+
+ return obj;
+
+ }
+
+ internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy)
+ {
+ byte[] data = null;
+
+ if (handle != clip_magic)
+ {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+
+ if (obj == null)
+ {
+ // Just clear it
+ if (!Win32EmptyClipboard())
+ throw new ExternalException("Win32EmptyClipboard");
+ return;
+ }
+
+ if (type == -1)
+ {
+ if (obj is string)
+ {
+ type = (int)ClipboardFormats.CF_UNICODETEXT;
+ }
+ else if (obj is Image)
+ {
+ type = (int)ClipboardFormats.CF_DIB;
+ }
+ }
+
+ if (type == DataFormats.GetFormat(DataFormats.Rtf).Id)
+ {
+ data = StringToAnsi((string)obj);
+ }
+ else switch ((ClipboardFormats)type)
+ {
+ case ClipboardFormats.CF_UNICODETEXT:
+ {
+ data = StringToUnicode((string)obj);
+ break;
+ }
+
+ case ClipboardFormats.CF_TEXT:
+ {
+ data = StringToAnsi((string)obj);
+ break;
+ }
+
+ case ClipboardFormats.CF_BITMAP:
+ case ClipboardFormats.CF_DIB:
+ {
+ data = ImageToDIB((Image)obj);
+ type = (int)ClipboardFormats.CF_DIB;
+ break;
+ }
+
+ default:
+ {
+ if (converter != null && !converter(ref type, obj, out data))
+ {
+ data = null; // ensure that a failed conversion leaves null.
+ }
+ break;
+ }
+ }
+ if (data != null)
+ {
+ SetClipboardData((uint)type, data);
+ }
+ }
+
+ internal static byte[] StringToUnicode(string text)
+ {
+ return Encoding.Unicode.GetBytes(text + "\0");
+ }
+
+ internal static byte[] StringToAnsi(string text)
+ {
+ // FIXME, follow the behaviour of the previous code using UTF-8,
+ // but this should be 'ANSI' on Windows, i.e. the current code page.
+ // Does Encoding.Default work on Windows?
+ return Encoding.UTF8.GetBytes(text + "\0");
+ }
+
+ private void SetClipboardData(uint type, byte[] data)
+ {
+ if (data.Length == 0)
+ // Shouldn't call Win32SetClipboard with NULL, as, from MSDN:
+ // "This parameter can be NULL, indicating that the window provides data
+ // in the specified clipboard format (renders the format) upon request."
+ // and I don't think we support that...
+ // Note this is unrelated to the fact that passing a null obj to
+ // ClipboardStore is actually a request to empty the clipboard!
+ return;
+ IntPtr hmem = CopyToMoveableMemory(data);
+ if (hmem == IntPtr.Zero)
+ // As above, should not call with null.
+ // (Not that CopyToMoveableMemory should ever return null!)
+ throw new ExternalException("CopyToMoveableMemory failed.");
+ if (Win32SetClipboardData(type, hmem) == IntPtr.Zero)
+ throw new ExternalException("Win32SetClipboardData");
+ }
+
+ /// <summary>
+ /// Creates a memory block with GlobalAlloc(GMEM_MOVEABLE), copies the data
+ /// into it, and returns the handle to the memory.
+ /// </summary>
+ /// -
+ /// <param name="data">The data. Must not be null or zero-length &#x2014;
+ /// see the exception notes.</param>
+ /// -
+ /// <returns>The *handle* to the allocated GMEM_MOVEABLE block.</returns>
+ /// -
+ /// <exception cref="T:System.ArgumentException">The data was null or zero
+ /// length. This is disallowed since a zero length allocation can't be made
+ /// </exception>
+ /// <exception cref="T:System.ComponentModel.Win32Exception">The allocation,
+ /// or locking (handle->pointer) failed.
+ /// Either out of memory or the handle table is full (256 max currently).
+ /// Note Win32Exception is a subclass of ExternalException so this is OK in
+ /// the documented Clipboard interface.
+ /// </exception>
+ internal static IntPtr CopyToMoveableMemory(byte[] data)
+ {
+ if (data == null || data.Length == 0)
+ // detect this before GlobalAlloc does.
+ throw new ArgumentException("Can't create a zero length memory block.");
+
+ IntPtr hmem = Win32GlobalAlloc(GAllocFlags.GMEM_MOVEABLE | GAllocFlags.GMEM_DDESHARE, data.Length);
+ if (hmem == IntPtr.Zero)
+ throw new Win32Exception();
+ IntPtr hmem_ptr = Win32GlobalLock(hmem);
+ if (hmem_ptr == IntPtr.Zero) // If the allocation was valid this shouldn't occur.
+ throw new Win32Exception();
+ Marshal.Copy(data, 0, hmem_ptr, data.Length);
+ Win32GlobalUnlock(hmem);
+ return hmem;
+ }
+
+
+ internal override void SetAllowDrop(IntPtr hwnd, bool allowed)
+ {
+ if (allowed)
+ {
+ Win32DnD.RegisterDropTarget(hwnd);
+ }
+ else
+ {
+ Win32DnD.UnregisterDropTarget(hwnd);
+ }
+ }
+
+ internal override DragDropEffects StartDrag(IntPtr hwnd, object data, DragDropEffects allowedEffects)
+ {
+ return Win32DnD.StartDrag(hwnd, data, allowedEffects);
+ }
+
+ // XXX this doesn't work at all for FrameStyle.Dashed - it draws like Thick, and in the Thick case
+ // the corners are drawn incorrectly.
+ internal override void DrawReversibleFrame(Rectangle rectangle, Color backColor, FrameStyle style)
+ {
+ IntPtr hdc;
+ IntPtr pen;
+ IntPtr oldpen;
+ COLORREF clrRef = new COLORREF();
+
+ // If we want the standard hatch pattern we would
+ // need to create a brush
+
+ clrRef.R = backColor.R;
+ clrRef.G = backColor.G;
+ clrRef.B = backColor.B;
+
+ // Grab a pen
+ pen = Win32CreatePen(style == FrameStyle.Thick ? PenStyle.PS_SOLID : PenStyle.PS_DASH,
+ style == FrameStyle.Thick ? 4 : 2, ref clrRef);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ Win32SetROP2(hdc, ROP2DrawMode.R2_NOT);
+ oldpen = Win32SelectObject(hdc, pen);
+
+ Win32MoveToEx(hdc, rectangle.Left, rectangle.Top, IntPtr.Zero);
+ if ((rectangle.Width > 0) && (rectangle.Height > 0))
+ {
+ Win32LineTo(hdc, rectangle.Right, rectangle.Top);
+ Win32LineTo(hdc, rectangle.Right, rectangle.Bottom);
+ Win32LineTo(hdc, rectangle.Left, rectangle.Bottom);
+ Win32LineTo(hdc, rectangle.Left, rectangle.Top);
+ }
+ else
+ {
+ if (rectangle.Width > 0)
+ {
+ Win32LineTo(hdc, rectangle.Right, rectangle.Top);
+ }
+ else
+ {
+ Win32LineTo(hdc, rectangle.Left, rectangle.Bottom);
+ }
+ }
+
+ Win32SelectObject(hdc, oldpen);
+ Win32DeleteObject(pen);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ internal override void DrawReversibleLine(Point start, Point end, Color backColor)
+ {
+ IntPtr hdc;
+ IntPtr pen;
+ IntPtr oldpen;
+ POINT pt;
+ COLORREF clrRef = new COLORREF();
+
+ pt = new POINT();
+ pt.x = 0;
+ pt.y = 0;
+ Win32ClientToScreen(IntPtr.Zero, ref pt);
+
+ // If we want the standard hatch pattern we would
+ // need to create a brush
+
+ clrRef.R = backColor.R;
+ clrRef.G = backColor.G;
+ clrRef.B = backColor.B;
+
+ // Grab a pen
+ pen = Win32CreatePen(PenStyle.PS_SOLID, 1, ref clrRef);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ Win32SetROP2(hdc, ROP2DrawMode.R2_NOT);
+ oldpen = Win32SelectObject(hdc, pen);
+
+ Win32MoveToEx(hdc, pt.x + start.X, pt.y + start.Y, IntPtr.Zero);
+ Win32LineTo(hdc, pt.x + end.X, pt.y + end.Y);
+
+ Win32SelectObject(hdc, oldpen);
+ Win32DeleteObject(pen);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ internal override void FillReversibleRectangle(Rectangle rectangle, Color backColor)
+ {
+ RECT rect;
+
+ rect = new RECT();
+ rect.left = rectangle.Left;
+ rect.top = rectangle.Top;
+ rect.right = rectangle.Right;
+ rect.bottom = rectangle.Bottom;
+
+ IntPtr hdc;
+ IntPtr brush;
+ IntPtr oldbrush;
+ COLORREF clrRef = new COLORREF();
+
+ clrRef.R = backColor.R;
+ clrRef.G = backColor.G;
+ clrRef.B = backColor.B;
+
+ // Grab a brush
+ brush = Win32CreateSolidBrush(clrRef);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ oldbrush = Win32SelectObject(hdc, brush);
+
+ Win32PatBlt(hdc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, PatBltRop.DSTINVERT);
+
+ Win32SelectObject(hdc, oldbrush);
+ Win32DeleteObject(brush);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width)
+ {
+ IntPtr hdc;
+ IntPtr pen;
+ IntPtr oldpen;
+ POINT pt;
+
+ pt = new POINT();
+ pt.x = 0;
+ pt.y = 0;
+ Win32ClientToScreen(handle, ref pt);
+
+ // If we want the standard hatch pattern we would
+ // need to create a brush
+
+ // Grab a pen
+ pen = Win32CreatePen(PenStyle.PS_SOLID, line_width, IntPtr.Zero);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ Win32SetROP2(hdc, ROP2DrawMode.R2_NOT);
+ oldpen = Win32SelectObject(hdc, pen);
+
+ Widget c = Widget.FromHandle(handle);
+ if (c != null)
+ {
+ RECT window_rect;
+ Win32GetWindowRect(c.Handle, out window_rect);
+ Region r = new Region(new Rectangle(window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top));
+ 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))
+ {
+ Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top);
+ Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Bottom);
+ Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom);
+ Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Top);
+ }
+ else
+ {
+ if (rect.Width > 0)
+ {
+ Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top);
+ }
+ else
+ {
+ Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom);
+ }
+ }
+
+ Win32SelectObject(hdc, oldpen);
+ Win32DeleteObject(pen);
+ if (c != null)
+ Win32ExtSelectClipRgn(hdc, IntPtr.Zero, (int)ClipCombineMode.RGN_COPY);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ 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.FromHwnd(GetFosterParent());
+
+ width = (float)(g.MeasureString(magic_string, font).Width / magic_number);
+ return new SizeF(width, font.Height);
+ }
+
+ internal override IntPtr SendMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ return Win32SendMessage(hwnd, message, wParam, lParam);
+ }
+
+ internal override bool PostMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ return Win32PostMessage(hwnd, message, wParam, lParam);
+ }
+
+ internal override int SendInput(IntPtr hwnd, Queue keys)
+ {
+ INPUT[] inputs = new INPUT[keys.Count];
+ const Int32 INPUT_KEYBOARD = 1;
+ uint returns = 0;
+ int i = 0;
+ while (keys.Count > 0)
+ {
+ MSG msg = (MSG)keys.Dequeue();
+
+
+ inputs[i].ki.wScan = 0;
+ inputs[i].ki.time = 0;
+ inputs[i].ki.dwFlags = (Int32)(msg.message == Msg.WM_KEYUP ? InputFlags.KEYEVENTF_KEYUP : 0);
+ inputs[i].ki.wVk = (short)msg.wParam.ToInt32();
+ inputs[i].type = INPUT_KEYBOARD;
+ i++;
+ }
+ returns = Win32SendInput((UInt32)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
+
+ return (int)returns;
+ }
+
+ internal override int KeyboardSpeed
+ {
+ get
+ {
+ int speed = 0;
+ Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDSPEED, 0, ref speed, 0);
+ //
+ // Return values range from 0 to 31 which map to 2.5 to 30 repetitions per second.
+ //
+ return speed;
+ }
+ }
+
+ internal override int KeyboardDelay
+ {
+ get
+ {
+ int delay = 1;
+ Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDDELAY, 0, ref delay, 0);
+ //
+ // Return values must range from 0 to 4, 0 meaning 250ms,
+ // and 4 meaning 1000 ms.
+ //
+ return delay;
+ }
+ }
+
+ private class WinBuffer
+ {
+ public IntPtr hdc;
+ public IntPtr bitmap;
+
+ public WinBuffer(IntPtr hdc, IntPtr bitmap)
+ {
+ this.hdc = hdc;
+ this.bitmap = bitmap;
+ }
+ }
+
+ internal override void CreateOffscreenDrawable(IntPtr handle, int width, int height, out object offscreen_drawable)
+ {
+ Graphics destG = Graphics.FromHwnd(handle);
+ IntPtr destHdc = destG.GetHdc();
+
+ IntPtr srcHdc = Win32CreateCompatibleDC(destHdc);
+ IntPtr srcBmp = Win32CreateCompatibleBitmap(destHdc, width, height);
+ Win32SelectObject(srcHdc, srcBmp);
+
+ offscreen_drawable = new WinBuffer(srcHdc, srcBmp);
+
+ destG.ReleaseHdc(destHdc);
+ }
+
+ internal override Graphics GetOffscreenGraphics(object offscreen_drawable)
+ {
+ return Graphics.FromHdc(((WinBuffer)offscreen_drawable).hdc);
+ }
+
+ internal override void BlitFromOffscreen(IntPtr dest_handle, Graphics dest_dc, object offscreen_drawable, Graphics offscreen_dc, Rectangle r)
+ {
+ WinBuffer wb = (WinBuffer)offscreen_drawable;
+
+ IntPtr destHdc = dest_dc.GetHdc();
+ Win32BitBlt(destHdc, r.Left, r.Top, r.Width, r.Height, wb.hdc, r.Left, r.Top, TernaryRasterOperations.SRCCOPY);
+ dest_dc.ReleaseHdc(destHdc);
+ }
+
+ internal override void DestroyOffscreenDrawable(object offscreen_drawable)
+ {
+ WinBuffer wb = (WinBuffer)offscreen_drawable;
+
+ Win32DeleteObject(wb.bitmap);
+ Win32DeleteDC(wb.hdc);
+ }
+
+ internal override void SetForegroundWindow(IntPtr handle)
+ {
+ Win32SetForegroundWindow(handle);
+ }
+
+ internal override event EventHandler Idle;
+#endregion // Public Static Methods
+
+ }
+}
+#endregion
+#endif \ No newline at end of file
diff --git a/source/ShiftUI/Internal/XplatUIDriver.cs b/source/ShiftUI/Internal/XplatUIDriver.cs
new file mode 100644
index 0000000..c3f5e0d
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUIDriver.cs
@@ -0,0 +1,532 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+// Sebastien Pouliot [email protected]
+//
+
+// COMPLETE
+
+using System.Drawing;
+using System.Threading;
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI {
+ internal abstract class XplatUIDriver {
+ internal abstract IntPtr InitializeDriver();
+ internal abstract void ShutdownDriver(IntPtr token);
+ internal delegate IntPtr WndProc(IntPtr hwnd, Msg msg, IntPtr wParam, IntPtr lParam);
+
+
+ #region XplatUI Driver Properties
+ internal virtual int ActiveWindowTrackingDelay { get { return 0; } }
+
+ internal virtual Color ForeColor {
+ get {
+ return ThemeEngine.Current.DefaultWindowForeColor;
+ }
+ }
+
+ internal virtual Color BackColor {
+ get {
+ return ThemeEngine.Current.DefaultWindowBackColor;
+ }
+ }
+
+ internal virtual Size Border3DSize {
+ get {
+ return new Size (2, 2);
+ }
+ }
+
+ internal virtual Size BorderSize {
+ get {
+ return new Size (1, 1);
+ }
+ }
+
+ internal virtual Size CaptionButtonSize {
+ get {
+ return new Size (18, 18);
+ }
+ }
+
+ internal virtual int CaretBlinkTime { get { return 530; } }
+ internal virtual int CaretWidth { get { return 10; } }
+
+ internal virtual Size DoubleClickSize {
+ get {
+ return new Size (4, 4);
+ }
+ }
+
+ internal virtual int DoubleClickTime {
+ get {
+ return 500;
+ }
+ }
+
+ internal virtual Size FixedFrameBorderSize {
+ get {
+ return new Size (3, 3);
+ }
+ }
+
+ internal virtual Font Font {
+ get {
+ return ThemeEngine.Current.DefaultFont;
+ }
+ }
+
+ internal virtual int FontSmoothingContrast { get { return 1400; } }
+ internal virtual int FontSmoothingType { get { return 1; } }
+ internal virtual int HorizontalResizeBorderThickness { get { return 8; } }
+ internal virtual bool IsActiveWindowTrackingEnabled { get { return false; } }
+ internal virtual bool IsComboBoxAnimationEnabled { get { return false; } }
+ internal virtual bool IsDropShadowEnabled { get { return false; } }
+ internal virtual bool IsFontSmoothingEnabled { get { return true; } }
+ internal virtual bool IsHotTrackingEnabled { get { return false; } }
+ internal virtual bool IsIconTitleWrappingEnabled { get { return true; } }
+ internal virtual bool IsKeyboardPreferred { get { return false; } }
+ internal virtual bool IsListBoxSmoothScrollingEnabled { get { return true; } }
+ internal virtual bool IsMenuAnimationEnabled { get { return false; } }
+ internal virtual bool IsMenuFadeEnabled { get { return true; } }
+ internal virtual bool IsMinimizeRestoreAnimationEnabled { get { return false; } }
+ internal virtual bool IsSelectionFadeEnabled { get { return false; } }
+ internal virtual bool IsSnapToDefaultEnabled { get { return false; } }
+ internal virtual bool IsTitleBarGradientEnabled { get { return false; } }
+ internal virtual bool IsToolTipAnimationEnabled { get { return false; } }
+ internal virtual Size MenuBarButtonSize { get { return new Size (19, 19); } }
+ public virtual Size MenuButtonSize {
+ get {
+ return new Size(18, 18);
+ }
+ }
+ internal virtual int MenuShowDelay { get { return 0; } }
+
+ internal virtual Keys ModifierKeys {
+ get {
+ return Keys.None;
+ }
+ }
+
+ internal virtual MouseButtons MouseButtons {
+ get {
+ return MouseButtons.None;
+ }
+ }
+
+ internal virtual Size MouseHoverSize {
+ get {
+ return new Size (1, 1);
+ }
+ }
+
+ internal virtual int MouseHoverTime {
+ get {
+ return 500;
+ }
+ }
+
+ internal virtual int MouseSpeed {
+ get { return 10; }
+ }
+
+ internal virtual int MouseWheelScrollDelta {
+ get {
+ return 120;
+ }
+ }
+
+ internal virtual Point MousePosition {
+ get {
+ return Point.Empty;
+ }
+ }
+
+ internal virtual int MenuHeight {
+ get {
+ return 19;
+ }
+ }
+
+ internal virtual LeftRightAlignment PopupMenuAlignment {
+ get { return LeftRightAlignment.Left; }
+ }
+
+ internal virtual PowerStatus PowerStatus {
+ get { throw new NotImplementedException ("Has not been implemented yet for this platform."); }
+ }
+
+ internal virtual int SizingBorderWidth {
+ get { return 4; }
+ }
+
+ internal virtual Size SmallCaptionButtonSize {
+ get { return new Size (15, 15); }
+ }
+
+ internal virtual bool UIEffectsEnabled {
+ get { return false; }
+ }
+
+ internal virtual bool DropTarget {
+ get {
+ return false;
+ }
+
+ set {
+ }
+ }
+
+ internal virtual int HorizontalScrollBarHeight {
+ get {
+ return 16;
+ }
+ }
+
+ internal virtual bool UserClipWontExposeParent {
+ get {
+ return true;
+ }
+ }
+
+ internal virtual int VerticalResizeBorderThickness { get { return 8; } }
+
+ internal virtual int VerticalScrollBarWidth {
+ get {
+ return 16;
+ }
+ }
+
+ internal abstract int CaptionHeight { get; }
+ internal abstract Size CursorSize { get; }
+ internal abstract bool DragFullWindows { get; }
+ internal abstract Size DragSize { get; }
+ internal abstract Size FrameBorderSize { get; }
+ internal abstract Size IconSize { get; }
+ internal abstract Size MaxWindowTrackSize { get; }
+ internal abstract bool MenuAccessKeysUnderlined { get; }
+ internal virtual Size MinimizedWindowSize {
+ get {
+ const int BorderWidth = 3;
+ return new Size (154 + 2 * BorderWidth, SystemInformation.CaptionHeight + 2 * BorderWidth - 1);
+ }
+ }
+ internal abstract Size MinimizedWindowSpacingSize { get; }
+ internal abstract Size MinimumWindowSize { get; }
+ internal virtual Size MinimumFixedToolWindowSize { get { return Size.Empty; } }
+ internal virtual Size MinimumSizeableToolWindowSize { get { return Size.Empty; } }
+ internal virtual Size MinimumNoBorderWindowSize { get { return Size.Empty; } }
+ internal virtual Size MinWindowTrackSize {
+ get {
+ return new Size (112, 27);
+ }
+ }
+ internal abstract Size SmallIconSize { get; }
+ internal abstract int MouseButtonCount { get; }
+ internal abstract bool MouseButtonsSwapped { get; }
+ internal abstract bool MouseWheelPresent { get; }
+ internal abstract Rectangle VirtualScreen { get; }
+ internal abstract Rectangle WorkingArea { get; }
+ internal abstract Screen[] AllScreens { get; }
+ internal abstract bool ThemesEnabled { get; }
+
+ internal virtual bool RequiresPositiveClientAreaSize {
+ get {
+ return true;
+ }
+ }
+
+ public virtual int ToolWindowCaptionHeight {
+ get {
+ return 16;
+ }
+ }
+
+ public virtual Size ToolWindowCaptionButtonSize {
+ get {
+ return new Size (15, 15);
+ }
+ }
+ #endregion // XplatUI Driver Properties
+
+ internal abstract event EventHandler Idle;
+
+ #region XplatUI Driver Methods
+ internal abstract void AudibleAlert(AlertType alert);
+
+ internal abstract void BeginMoveResize (IntPtr handle); // init a window manager driven resize event
+
+ internal abstract void EnableThemes();
+
+ internal abstract void GetDisplaySize(out Size size);
+
+ internal abstract IntPtr CreateWindow(CreateParams cp);
+ internal abstract IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height);
+ internal abstract void DestroyWindow(IntPtr handle);
+
+ internal abstract FormWindowState GetWindowState(IntPtr handle);
+ internal abstract void SetWindowState(IntPtr handle, FormWindowState state);
+ internal abstract void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max);
+
+ internal abstract void SetWindowStyle(IntPtr handle, CreateParams cp);
+
+ internal abstract double GetWindowTransparency(IntPtr handle);
+ internal abstract void SetWindowTransparency(IntPtr handle, double transparency, Color key);
+ internal abstract TransparencySupport SupportsTransparency();
+
+ internal virtual void SetAllowDrop (IntPtr handle, bool value)
+ {
+ Console.Error.WriteLine ("Drag and Drop is currently " +
+ "not supported on this platform");
+ }
+
+ internal virtual DragDropEffects StartDrag(IntPtr handle, object data, DragDropEffects allowedEffects) {
+ Console.Error.WriteLine ("Drag and Drop is currently " +
+ "not supported on this platform");
+ return DragDropEffects.None;
+ }
+
+ internal abstract void SetBorderStyle(IntPtr handle, FormBorderStyle border_style);
+ internal abstract void SetMenu(IntPtr handle, Menu menu);
+
+ internal abstract bool GetText(IntPtr handle, out string text);
+ internal abstract bool Text(IntPtr handle, string text);
+ internal abstract bool SetVisible(IntPtr handle, bool visible, bool activate);
+ internal abstract bool IsVisible(IntPtr handle);
+ internal abstract bool IsEnabled(IntPtr handle);
+ internal virtual bool IsKeyLocked (VirtualKeys key) { return false; }
+ internal abstract IntPtr SetParent(IntPtr handle, IntPtr parent);
+ internal abstract IntPtr GetParent(IntPtr handle);
+
+ internal abstract void UpdateWindow(IntPtr handle);
+ internal abstract PaintEventArgs PaintEventStart (ref Message msg, IntPtr handle, bool client);
+ internal abstract void PaintEventEnd (ref Message msg, IntPtr handle, bool client);
+
+ internal abstract void SetWindowPos(IntPtr handle, int x, int y, int width, int height);
+ internal abstract 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);
+ internal abstract void Activate(IntPtr handle);
+ internal abstract void EnableWindow(IntPtr handle, bool Enable);
+ internal abstract void SetModal(IntPtr handle, bool Modal);
+ internal abstract void Invalidate(IntPtr handle, Rectangle rc, bool clear);
+ internal abstract void InvalidateNC(IntPtr handle);
+ internal abstract IntPtr DefWndProc(ref Message msg);
+ internal abstract void HandleException(Exception e);
+ internal abstract void DoEvents();
+ internal abstract bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags);
+ internal abstract void PostQuitMessage(int exitCode);
+ internal abstract bool GetMessage(object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax);
+ internal abstract bool TranslateMessage(ref MSG msg);
+ internal abstract IntPtr DispatchMessage(ref MSG msg);
+
+ internal abstract bool SetZOrder(IntPtr hWnd, IntPtr AfterhWnd, bool Top, bool Bottom);
+ internal abstract bool SetTopmost(IntPtr hWnd, bool Enabled);
+ internal abstract bool SetOwner(IntPtr hWnd, IntPtr hWndOwner);
+
+ internal abstract bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect);
+
+ internal abstract Region GetClipRegion(IntPtr hwnd);
+ internal abstract void SetClipRegion(IntPtr hwnd, Region region);
+
+ internal abstract void SetCursor(IntPtr hwnd, IntPtr cursor);
+ internal abstract void ShowCursor(bool show);
+ internal abstract void OverrideCursor(IntPtr cursor);
+ internal abstract IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot);
+ internal abstract IntPtr DefineStdCursor(StdCursor id);
+ internal abstract Bitmap DefineStdCursorBitmap(StdCursor id);
+ internal abstract void DestroyCursor(IntPtr cursor);
+ internal abstract void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y);
+
+ internal abstract void GetCursorPos(IntPtr hwnd, out int x, out int y);
+ internal abstract void SetCursorPos(IntPtr hwnd, int x, int y);
+
+ internal abstract void ScreenToClient(IntPtr hwnd, ref int x, ref int y);
+ internal abstract void ClientToScreen(IntPtr hwnd, ref int x, ref int y);
+
+ internal abstract void GrabWindow(IntPtr hwnd, IntPtr ConfineToHwnd);
+ internal abstract void GrabInfo(out IntPtr hwnd, out bool GrabConfined, out Rectangle GrabArea);
+ internal abstract void UngrabWindow(IntPtr hwnd);
+
+ internal abstract void SendAsyncMethod (AsyncMethodData method);
+ internal abstract void SetTimer (Timer timer);
+ internal abstract void KillTimer (Timer timer);
+
+ internal abstract void CreateCaret(IntPtr hwnd, int width, int height);
+ internal abstract void DestroyCaret(IntPtr hwnd);
+ internal abstract void SetCaretPos(IntPtr hwnd, int x, int y);
+ internal abstract void CaretVisible(IntPtr hwnd, bool visible);
+
+ internal abstract IntPtr GetFocus();
+ internal abstract void SetFocus(IntPtr hwnd);
+ internal abstract IntPtr GetActive();
+ internal abstract IntPtr GetPreviousWindow(IntPtr hwnd);
+
+ internal abstract void ScrollWindow(IntPtr hwnd, Rectangle rectangle, int XAmount, int YAmount, bool with_children);
+ internal abstract void ScrollWindow(IntPtr hwnd, int XAmount, int YAmount, bool with_children);
+
+ internal abstract bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent);
+
+ internal abstract bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt);
+ internal abstract bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt);
+ internal abstract void SystrayRemove(IntPtr hwnd, ref ToolTip tt);
+ internal abstract void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon);
+
+ internal abstract Point GetMenuOrigin(IntPtr hwnd);
+ internal abstract void MenuToScreen(IntPtr hwnd, ref int x, ref int y);
+ internal abstract void ScreenToMenu(IntPtr hwnd, ref int x, ref int y);
+
+ internal abstract void SetIcon(IntPtr handle, Icon icon);
+
+ internal abstract void ClipboardClose(IntPtr handle);
+ internal abstract IntPtr ClipboardOpen (bool primary_selection);
+ internal abstract int ClipboardGetID(IntPtr handle, string format);
+ internal abstract void ClipboardStore(IntPtr handle, object obj, int id, XplatUI.ObjectToClipboard converter, bool copy);
+ internal abstract int[] ClipboardAvailableFormats(IntPtr handle);
+ internal abstract object ClipboardRetrieve(IntPtr handle, int id, XplatUI.ClipboardToObject converter);
+
+ internal abstract void DrawReversibleLine(Point start, Point end, Color backColor);
+ internal abstract void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width);
+ internal abstract void FillReversibleRectangle (Rectangle rectangle, Color backColor);
+ internal abstract void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style);
+
+ internal abstract SizeF GetAutoScaleSize(Font font);
+
+ internal abstract IntPtr SendMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
+ internal abstract bool PostMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
+ internal abstract int SendInput(IntPtr hwnd, System.Collections.Queue keys);
+
+ internal abstract object StartLoop(Thread thread);
+ internal abstract void EndLoop(Thread thread);
+
+ internal abstract void RequestNCRecalc(IntPtr hwnd);
+ internal abstract void ResetMouseHover(IntPtr hwnd);
+ internal abstract void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave);
+
+ internal abstract void RaiseIdle (EventArgs e);
+
+ // System information
+ internal abstract int KeyboardSpeed { get; }
+ internal abstract int KeyboardDelay { get; }
+
+
+ // Double buffering
+ internal virtual void CreateOffscreenDrawable (IntPtr handle,
+ int width, int height,
+ out object offscreen_drawable)
+ {
+ Bitmap bmp = new Bitmap (width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+ offscreen_drawable = bmp;
+ }
+
+ internal virtual void DestroyOffscreenDrawable (object offscreen_drawable)
+ {
+ Bitmap bmp = (Bitmap)offscreen_drawable;
+
+ bmp.Dispose ();
+ }
+
+ internal virtual Graphics GetOffscreenGraphics (object offscreen_drawable)
+ {
+ Bitmap bmp = (Bitmap)offscreen_drawable;
+ return Graphics.FromImage (bmp);
+ }
+
+ internal virtual void BlitFromOffscreen (IntPtr dest_handle,
+ Graphics dest_dc,
+ object offscreen_drawable,
+ Graphics offscreen_dc,
+ Rectangle r)
+ {
+ dest_dc.DrawImage ((Bitmap)offscreen_drawable, r, r, GraphicsUnit.Pixel);
+ }
+
+ internal virtual void SetForegroundWindow (IntPtr handle)
+ {
+ }
+
+#endregion // XplatUI Driver Methods
+ }
+
+ static class XplatUIDriverSupport {
+ #region XplatUI Driver Support Methods
+ internal static void ExecutionCallback (AsyncMethodData data)
+ {
+ AsyncMethodResult result = data.Result;
+
+ object ret;
+ try {
+ ret = data.Method.DynamicInvoke (data.Args);
+ } catch (Exception ex) {
+ if (result != null) {
+ result.CompleteWithException (ex);
+ return;
+ }
+
+ throw;
+ }
+
+ if (result != null) {
+ result.Complete (ret);
+ }
+ }
+
+ static void ExecutionCallbackInContext (object state)
+ {
+ AsyncMethodData data = (AsyncMethodData) state;
+
+ if (data.SyncContext == null) {
+ ExecutionCallback (data);
+ return;
+ }
+
+ var oldContext = SynchronizationContext.Current;
+ SynchronizationContext.SetSynchronizationContext (data.SyncContext);
+
+ try {
+ ExecutionCallback (data);
+ } finally {
+ SynchronizationContext.SetSynchronizationContext (oldContext);
+ }
+ }
+
+ internal static void ExecuteClientMessage (GCHandle gchandle)
+ {
+ AsyncMethodData data = (AsyncMethodData) gchandle.Target;
+ try {
+ if (data.Context == null) {
+ ExecutionCallback (data);
+ } else {
+ data.SyncContext = SynchronizationContext.Current;
+ ExecutionContext.Run (data.Context, new ContextCallback (ExecutionCallbackInContext), data);
+ }
+ }
+ finally {
+ gchandle.Free ();
+ }
+ }
+
+ #endregion // XplatUI Driver Support Methods
+ }
+}
diff --git a/source/ShiftUI/Internal/XplatUIStructs.cs b/source/ShiftUI/Internal/XplatUIStructs.cs
new file mode 100644
index 0000000..f0c3bc5
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUIStructs.cs
@@ -0,0 +1,1042 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+// *** When you make some changes to this file, dont forget to update Tests/TestHelper class ***
+
+// NOT COMPLETE
+
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+#if PUBLIC_TYPES
+namespace Mono.Winforms
+#else
+namespace ShiftUI
+#endif
+{
+ [Flags]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum WindowStyles : int {
+ WS_OVERLAPPED = 0x00000000,
+ WS_POPUP = unchecked((int)0x80000000),
+ WS_CHILD = 0x40000000,
+ WS_MINIMIZE = 0x20000000,
+ WS_VISIBLE = 0x10000000,
+ WS_DISABLED = 0x08000000,
+ WS_CLIPSIBLINGS = 0x04000000,
+ WS_CLIPCHILDREN = 0x02000000,
+ WS_MAXIMIZE = 0x01000000,
+ WS_CAPTION = 0x00C00000, // == WS_BORDER | WS_DLGFRAME
+ WS_BORDER = 0x00800000,
+ WS_DLGFRAME = 0x00400000,
+ WS_VSCROLL = 0x00200000,
+ WS_HSCROLL = 0x00100000,
+ WS_SYSMENU = 0x00080000,
+ WS_THICKFRAME = 0x00040000,
+ WS_GROUP = 0x00020000,
+ WS_TABSTOP = 0x00010000,
+ WS_MINIMIZEBOX = 0x00020000,
+ WS_MAXIMIZEBOX = 0x00010000,
+ WS_TILED = 0x00000000,
+ WS_ICONIC = 0x20000000,
+ WS_SIZEBOX = 0x00040000,
+ WS_POPUPWINDOW = unchecked((int)0x80880000),
+ WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
+ WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW,
+ WS_CHILDWINDOW = WS_CHILD,
+ }
+
+ [Flags]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum WindowExStyles : int {
+ // Extended Styles
+ WS_EX_DLGMODALFRAME = 0x00000001,
+ WS_EX_DRAGDETECT = 0x00000002,
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+ WS_EX_TOPMOST = 0x00000008,
+ WS_EX_ACCEPTFILES = 0x00000010,
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ WS_EX_MDICHILD = 0x00000040,
+ WS_EX_TOOLWINDOW = 0x00000080,
+ WS_EX_WINDOWEDGE = 0x00000100,
+ WS_EX_CLIENTEDGE = 0x00000200,
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ WS_EX_RIGHT = 0x00001000,
+ WS_EX_LEFT = 0x00000000,
+ WS_EX_RTLREADING = 0x00002000,
+ WS_EX_LTRREADING = 0x00000000,
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+ WS_EX_LAYERED = 0x00080000,
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ WS_EX_WidgetPARENT = 0x00010000,
+ WS_EX_STATICEDGE = 0x00020000,
+ WS_EX_APPWINDOW = 0x00040000,
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+ WS_EX_LAYOUTRTL = 0x00400000,
+ WS_EX_COMPOSITED = 0x02000000,
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST
+ }
+
+ [Flags]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum ToolBarStyles : int {
+ TBSTYLE_TOOLTIPS = 0x100,
+ TBSTYLE_FLAT = 0x800,
+ TBSTYLE_LIST = 0x1000,
+ TBSTYLE_TRANSPARENT = 0x8000
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum Msg {
+ WM_NULL = 0x0000,
+ WM_CREATE = 0x0001,
+ WM_DESTROY = 0x0002,
+ WM_MOVE = 0x0003,
+ WM_SIZE = 0x0005,
+ WM_ACTIVATE = 0x0006,
+ WM_SETFOCUS = 0x0007,
+ WM_KILLFOCUS = 0x0008,
+ // public const uint WM_SETVISIBLE = 0x0009;
+ WM_ENABLE = 0x000A,
+ WM_SETREDRAW = 0x000B,
+ WM_SETTEXT = 0x000C,
+ WM_GETTEXT = 0x000D,
+ WM_GETTEXTLENGTH = 0x000E,
+ WM_PAINT = 0x000F,
+ WM_CLOSE = 0x0010,
+ WM_QUERYENDSESSION = 0x0011,
+ WM_QUIT = 0x0012,
+ WM_QUERYOPEN = 0x0013,
+ WM_ERASEBKGND = 0x0014,
+ WM_SYSCOLORCHANGE = 0x0015,
+ WM_ENDSESSION = 0x0016,
+ // public const uint WM_SYSTEMERROR = 0x0017;
+ WM_SHOWWINDOW = 0x0018,
+ WM_CTLCOLOR = 0x0019,
+ WM_WININICHANGE = 0x001A,
+ WM_SETTINGCHANGE = 0x001A,
+ WM_DEVMODECHANGE = 0x001B,
+ WM_ACTIVATEAPP = 0x001C,
+ WM_FONTCHANGE = 0x001D,
+ WM_TIMECHANGE = 0x001E,
+ WM_CANCELMODE = 0x001F,
+ WM_SETCURSOR = 0x0020,
+ WM_MOUSEACTIVATE = 0x0021,
+ WM_CHILDACTIVATE = 0x0022,
+ WM_QUEUESYNC = 0x0023,
+ WM_GETMINMAXINFO = 0x0024,
+ WM_PAINTICON = 0x0026,
+ WM_ICONERASEBKGND = 0x0027,
+ WM_NEXTDLGCTL = 0x0028,
+ // public const uint WM_ALTTABACTIVE = 0x0029;
+ WM_SPOOLERSTATUS = 0x002A,
+ WM_DRAWITEM = 0x002B,
+ WM_MEASUREITEM = 0x002C,
+ WM_DELETEITEM = 0x002D,
+ WM_VKEYTOITEM = 0x002E,
+ WM_CHARTOITEM = 0x002F,
+ WM_SETFONT = 0x0030,
+ WM_GETFONT = 0x0031,
+ WM_SETHOTKEY = 0x0032,
+ WM_GETHOTKEY = 0x0033,
+ // public const uint WM_FILESYSCHANGE = 0x0034;
+ // public const uint WM_ISACTIVEICON = 0x0035;
+ // public const uint WM_QUERYPARKICON = 0x0036;
+ WM_QUERYDRAGICON = 0x0037,
+ WM_COMPAREITEM = 0x0039,
+ // public const uint WM_TESTING = 0x003a;
+ // public const uint WM_OTHERWINDOWCREATED = 0x003c;
+ WM_GETOBJECT = 0x003D,
+ // public const uint WM_ACTIVATESHELLWINDOW = 0x003e;
+ WM_COMPACTING = 0x0041,
+ WM_COMMNOTIFY = 0x0044 ,
+ WM_WINDOWPOSCHANGING = 0x0046,
+ WM_WINDOWPOSCHANGED = 0x0047,
+ WM_POWER = 0x0048,
+ WM_COPYDATA = 0x004A,
+ WM_CANCELJOURNAL = 0x004B,
+ WM_NOTIFY = 0x004E,
+ WM_INPUTLANGCHANGEREQUEST = 0x0050,
+ WM_INPUTLANGCHANGE = 0x0051,
+ WM_TCARD = 0x0052,
+ WM_HELP = 0x0053,
+ WM_USERCHANGED = 0x0054,
+ WM_NOTIFYFORMAT = 0x0055,
+ WM_CONTEXTMENU = 0x007B,
+ WM_STYLECHANGING = 0x007C,
+ WM_STYLECHANGED = 0x007D,
+ WM_DISPLAYCHANGE = 0x007E,
+ WM_GETICON = 0x007F,
+
+ // Non-Client messages
+ WM_SETICON = 0x0080,
+ WM_NCCREATE = 0x0081,
+ WM_NCDESTROY = 0x0082,
+ WM_NCCALCSIZE = 0x0083,
+ WM_NCHITTEST = 0x0084,
+ WM_NCPAINT = 0x0085,
+ WM_NCACTIVATE = 0x0086,
+ WM_GETDLGCODE = 0x0087,
+ WM_SYNCPAINT = 0x0088,
+ // public const uint WM_SYNCTASK = 0x0089;
+ WM_NCMOUSEMOVE = 0x00A0,
+ WM_NCLBUTTONDOWN = 0x00A1,
+ WM_NCLBUTTONUP = 0x00A2,
+ WM_NCLBUTTONDBLCLK = 0x00A3,
+ WM_NCRBUTTONDOWN = 0x00A4,
+ WM_NCRBUTTONUP = 0x00A5,
+ WM_NCRBUTTONDBLCLK = 0x00A6,
+ WM_NCMBUTTONDOWN = 0x00A7,
+ WM_NCMBUTTONUP = 0x00A8,
+ WM_NCMBUTTONDBLCLK = 0x00A9,
+ // public const uint WM_NCXBUTTONDOWN = 0x00ab;
+ // public const uint WM_NCXBUTTONUP = 0x00ac;
+ // public const uint WM_NCXBUTTONDBLCLK = 0x00ad;
+ WM_KEYDOWN = 0x0100,
+ WM_KEYFIRST = 0x0100,
+ WM_KEYUP = 0x0101,
+ WM_CHAR = 0x0102,
+ WM_DEADCHAR = 0x0103,
+ WM_SYSKEYDOWN = 0x0104,
+ WM_SYSKEYUP = 0x0105,
+ WM_SYSCHAR = 0x0106,
+ WM_SYSDEADCHAR = 0x0107,
+ WM_KEYLAST = 0x0108,
+ WM_IME_STARTCOMPOSITION = 0x010D,
+ WM_IME_ENDCOMPOSITION = 0x010E,
+ WM_IME_COMPOSITION = 0x010F,
+ WM_IME_KEYLAST = 0x010F,
+ WM_INITDIALOG = 0x0110,
+ WM_COMMAND = 0x0111,
+ WM_SYSCOMMAND = 0x0112,
+ WM_TIMER = 0x0113,
+ WM_HSCROLL = 0x0114,
+ WM_VSCROLL = 0x0115,
+ WM_INITMENU = 0x0116,
+ WM_INITMENUPOPUP = 0x0117,
+ // public const uint WM_SYSTIMER = 0x0118;
+ WM_MENUSELECT = 0x011F,
+ WM_MENUCHAR = 0x0120,
+ WM_ENTERIDLE = 0x0121,
+ WM_MENURBUTTONUP = 0x0122,
+ WM_MENUDRAG = 0x0123,
+ WM_MENUGETOBJECT = 0x0124,
+ WM_UNINITMENUPOPUP = 0x0125,
+ WM_MENUCOMMAND = 0x0126,
+
+ WM_CHANGEUISTATE = 0x0127,
+ WM_UPDATEUISTATE = 0x0128,
+ WM_QUERYUISTATE = 0x0129,
+
+ // public const uint WM_LBTRACKPOINT = 0x0131;
+ WM_CTLCOLORMSGBOX = 0x0132,
+ WM_CTLCOLOREDIT = 0x0133,
+ WM_CTLCOLORLISTBOX = 0x0134,
+ WM_CTLCOLORBTN = 0x0135,
+ WM_CTLCOLORDLG = 0x0136,
+ WM_CTLCOLORSCROLLBAR = 0x0137,
+ WM_CTLCOLORSTATIC = 0x0138,
+ WM_MOUSEMOVE = 0x0200,
+ WM_MOUSEFIRST = 0x0200,
+ WM_LBUTTONDOWN = 0x0201,
+ WM_LBUTTONUP = 0x0202,
+ WM_LBUTTONDBLCLK = 0x0203,
+ WM_RBUTTONDOWN = 0x0204,
+ WM_RBUTTONUP = 0x0205,
+ WM_RBUTTONDBLCLK = 0x0206,
+ WM_MBUTTONDOWN = 0x0207,
+ WM_MBUTTONUP = 0x0208,
+ WM_MBUTTONDBLCLK = 0x0209,
+ WM_MOUSEWHEEL = 0x020A,
+ WM_MOUSELAST = 0x020D,
+ // public const uint WM_XBUTTONDOWN = 0x020B;
+ // public const uint WM_XBUTTONUP = 0x020C;
+ // public const uint WM_XBUTTONDBLCLK = 0x020D;
+ WM_PARENTNOTIFY = 0x0210,
+ WM_ENTERMENULOOP = 0x0211,
+ WM_EXITMENULOOP = 0x0212,
+ WM_NEXTMENU = 0x0213,
+ WM_SIZING = 0x0214,
+ WM_CAPTURECHANGED = 0x0215,
+ WM_MOVING = 0x0216,
+ // public const uint WM_POWERBROADCAST = 0x0218;
+ WM_DEVICECHANGE = 0x0219,
+ WM_MDICREATE = 0x0220,
+ WM_MDIDESTROY = 0x0221,
+ WM_MDIACTIVATE = 0x0222,
+ WM_MDIRESTORE = 0x0223,
+ WM_MDINEXT = 0x0224,
+ WM_MDIMAXIMIZE = 0x0225,
+ WM_MDITILE = 0x0226,
+ WM_MDICASCADE = 0x0227,
+ WM_MDIICONARRANGE = 0x0228,
+ WM_MDIGETACTIVE = 0x0229,
+ /* D&D messages */
+ // public const uint WM_DROPOBJECT = 0x022A;
+ // public const uint WM_QUERYDROPOBJECT = 0x022B;
+ // public const uint WM_BEGINDRAG = 0x022C;
+ // public const uint WM_DRAGLOOP = 0x022D;
+ // public const uint WM_DRAGSELECT = 0x022E;
+ // public const uint WM_DRAGMOVE = 0x022F;
+ WM_MDISETMENU = 0x0230,
+ WM_ENTERSIZEMOVE = 0x0231,
+ WM_EXITSIZEMOVE = 0x0232,
+ WM_DROPFILES = 0x0233,
+ WM_MDIREFRESHMENU = 0x0234,
+ WM_IME_SETCONTEXT = 0x0281,
+ WM_IME_NOTIFY = 0x0282,
+ WM_IME_Widget = 0x0283,
+ WM_IME_COMPOSITIONFULL = 0x0284,
+ WM_IME_SELECT = 0x0285,
+ WM_IME_CHAR = 0x0286,
+ WM_IME_REQUEST = 0x0288,
+ WM_IME_KEYDOWN = 0x0290,
+ WM_IME_KEYUP = 0x0291,
+ WM_NCMOUSEHOVER = 0x02A0,
+ WM_MOUSEHOVER = 0x02A1,
+ WM_NCMOUSELEAVE = 0x02A2,
+ WM_MOUSELEAVE = 0x02A3,
+ WM_CUT = 0x0300,
+ WM_COPY = 0x0301,
+ WM_PASTE = 0x0302,
+ WM_CLEAR = 0x0303,
+ WM_UNDO = 0x0304,
+ WM_RENDERFORMAT = 0x0305,
+ WM_RENDERALLFORMATS = 0x0306,
+ WM_DESTROYCLIPBOARD = 0x0307,
+ WM_DRAWCLIPBOARD = 0x0308,
+ WM_PAINTCLIPBOARD = 0x0309,
+ WM_VSCROLLCLIPBOARD = 0x030A,
+ WM_SIZECLIPBOARD = 0x030B,
+ WM_ASKCBFORMATNAME = 0x030C,
+ WM_CHANGECBCHAIN = 0x030D,
+ WM_HSCROLLCLIPBOARD = 0x030E,
+ WM_QUERYNEWPALETTE = 0x030F,
+ WM_PALETTEISCHANGING = 0x0310,
+ WM_PALETTECHANGED = 0x0311,
+ WM_HOTKEY = 0x0312,
+ WM_PRINT = 0x0317,
+ WM_PRINTCLIENT = 0x0318,
+ WM_HANDHELDFIRST = 0x0358,
+ WM_HANDHELDLAST = 0x035F,
+ WM_AFXFIRST = 0x0360,
+ WM_AFXLAST = 0x037F,
+ WM_PENWINFIRST = 0x0380,
+ WM_PENWINLAST = 0x038F,
+ WM_APP = 0x8000,
+ WM_USER = 0x0400,
+
+ // Our "private" ones
+ WM_MOUSE_ENTER = 0x0401,
+ WM_ASYNC_MESSAGE = 0x0403,
+ WM_REFLECT = WM_USER + 0x1c00,
+ WM_CLOSE_INTERNAL = WM_USER + 0x1c01,
+
+ // private messages to support on-the-spot IME editing.
+ WM_XIM_PREEDITSTART = WM_USER + 0x1d00,
+ WM_XIM_PREEDITDONE = WM_USER + 0x1d01,
+ WM_XIM_PREEDITDRAW = WM_USER + 0x1d02,
+ WM_XIM_PREEDITCARET = WM_USER + 0x1d03,
+
+ // NotifyIcon (Systray) Balloon messages
+ NIN_BALLOONSHOW = WM_USER + 0x0002,
+ NIN_BALLOONHIDE = WM_USER + 0x0003,
+ NIN_BALLOONTIMEOUT = WM_USER + 0x0004,
+ NIN_BALLOONUSERCLICK = WM_USER + 0x0005
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum MsgButtons {
+ MK_LBUTTON = 0x0001,
+ MK_RBUTTON = 0x0002,
+ MK_SHIFT = 0x0004,
+ MK_CONTROL = 0x0008,
+ MK_MBUTTON = 0x0010,
+ MK_XBUTTON1 = 0x0020,
+ MK_XBUTTON2 = 0x0040,
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum MsgUIState {
+ UIS_SET = 1,
+ UIS_CLEAR = 2,
+ UIS_INITIALIZE = 3,
+ UISF_HIDEFOCUS = 0x1,
+ UISF_HIDEACCEL = 0x2,
+ UISF_ACTIVE = 0x4
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ struct POINT {
+ public int x;
+ public int y;
+
+ public POINT (int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Point ToPoint ()
+ {
+ return new Point (x, y);
+ }
+
+ public override string ToString ()
+ {
+ return "Point {" + x.ToString () + ", " + y.ToString () + "}";
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ struct MSG {
+ internal IntPtr hwnd;
+ internal Msg message;
+ internal IntPtr wParam;
+ internal IntPtr lParam;
+ internal uint time;
+ internal POINT pt;
+ internal object refobject;
+
+ public override string ToString ()
+ {
+ return String.Format ("msg=0x{0:x} ({1}) hwnd=0x{2:x} wparam=0x{3:x} lparam=0x{4:x} pt={5}", (int) message, message.ToString (), hwnd.ToInt32 (), wParam.ToInt32 (), lParam.ToInt32 (), pt);
+ }
+ }
+
+ [Flags]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum TransparencySupport {
+ None = 0x00,
+ Get = 0x01,
+ Set = 0x02,
+ GetSet = 0x03
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum WindowActiveFlags {
+ WA_INACTIVE = 0,
+ WA_ACTIVE = 1,
+ WA_CLICKACTIVE = 2
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum KeybdEventFlags {
+ None = 0,
+ ExtendedKey = 0x0001,
+ KeyUp = 0x0002
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum VirtualKeys {
+ VK_LBUTTON = 0x01,
+ VK_RBUTTON = 0x02,
+ VK_CANCEL = 0x03,
+ VK_MBUTTON = 0x04,
+ VK_XBUTTON1 = 0x05,
+ VK_XBUTTON2 = 0x06,
+ VK_BACK = 0x08,
+ VK_TAB = 0x09,
+ VK_CLEAR = 0x0C,
+ VK_RETURN = 0x0D,
+ VK_SHIFT = 0x10,
+ VK_CONTROL = 0x11,
+ VK_MENU = 0x12,
+ VK_PAUSE = 0x13,
+ VK_CAPITAL = 0x14,
+ VK_ESCAPE = 0x1B,
+ VK_CONVERT = 0x1C,
+ VK_NONCONVERT = 0x1D,
+ VK_SPACE = 0x20,
+ VK_PRIOR = 0x21,
+ VK_NEXT = 0x22,
+ VK_END = 0x23,
+ VK_HOME = 0x24,
+ VK_LEFT = 0x25,
+ VK_UP = 0x26,
+ VK_RIGHT = 0x27,
+ VK_DOWN = 0x28,
+ VK_SELECT = 0x29,
+ VK_PRINT = 0x2A,
+ VK_EXECUTE = 0x2B,
+ VK_SNAPSHOT = 0x2C,
+ VK_INSERT = 0x2D,
+ VK_DELETE = 0x2E,
+ VK_HELP = 0x2F,
+ VK_0 = 0x30,
+ VK_1 = 0x31,
+ VK_2 = 0x32,
+ VK_3 = 0x33,
+ VK_4 = 0x34,
+ VK_5 = 0x35,
+ VK_6 = 0x36,
+ VK_7 = 0x37,
+ VK_8 = 0x38,
+ VK_9 = 0x39,
+ VK_A = 0x41,
+ VK_B = 0x42,
+ VK_C = 0x43,
+ VK_D = 0x44,
+ VK_E = 0x45,
+ VK_F = 0x46,
+ VK_G = 0x47,
+ VK_H = 0x48,
+ VK_I = 0x49,
+ VK_J = 0x4A,
+ VK_K = 0x4B,
+ VK_L = 0x4C,
+ VK_M = 0x4D,
+ VK_N = 0x4E,
+ VK_O = 0x4F,
+ VK_P = 0x50,
+ VK_Q = 0x51,
+ VK_R = 0x52,
+ VK_S = 0x53,
+ VK_T = 0x54,
+ VK_U = 0x55,
+ VK_V = 0x56,
+ VK_W = 0x57,
+ VK_X = 0x58,
+ VK_Y = 0x59,
+ VK_Z = 0x5A,
+ VK_LWIN = 0x5B,
+ VK_RWIN = 0x5C,
+ VK_APPS = 0x5D,
+ VK_NUMPAD0 = 0x60,
+ VK_NUMPAD1 = 0x61,
+ VK_NUMPAD2 = 0x62,
+ VK_NUMPAD3 = 0x63,
+ VK_NUMPAD4 = 0x64,
+ VK_NUMPAD5 = 0x65,
+ VK_NUMPAD6 = 0x66,
+ VK_NUMPAD7 = 0x67,
+ VK_NUMPAD8 = 0x68,
+ VK_NUMPAD9 = 0x69,
+ VK_MULTIPLY = 0x6A,
+ VK_ADD = 0x6B,
+ VK_SEPARATOR = 0x6C,
+ VK_SUBTRACT = 0x6D,
+ VK_DECIMAL = 0x6E,
+ VK_DIVIDE = 0x6F,
+ VK_F1 = 0x70,
+ VK_F2 = 0x71,
+ VK_F3 = 0x72,
+ VK_F4 = 0x73,
+ VK_F5 = 0x74,
+ VK_F6 = 0x75,
+ VK_F7 = 0x76,
+ VK_F8 = 0x77,
+ VK_F9 = 0x78,
+ VK_F10 = 0x79,
+ VK_F11 = 0x7A,
+ VK_F12 = 0x7B,
+ VK_F13 = 0x7C,
+ VK_F14 = 0x7D,
+ VK_F15 = 0x7E,
+ VK_F16 = 0x7F,
+ VK_F17 = 0x80,
+ VK_F18 = 0x81,
+ VK_F19 = 0x82,
+ VK_F20 = 0x83,
+ VK_F21 = 0x84,
+ VK_F22 = 0x85,
+ VK_F23 = 0x86,
+ VK_F24 = 0x87,
+ VK_NUMLOCK = 0x90,
+ VK_SCROLL = 0x91,
+ VK_LSHIFT = 0xA0,
+ VK_RSHIFT = 0xA1,
+ VK_LWidget = 0xA2,
+ VK_RWidget = 0xA3,
+ VK_LMENU = 0xA4,
+ VK_RMENU = 0xA5,
+ VK_OEM_1 = 0xBA,
+ VK_OEM_PLUS = 0xBB,
+ VK_OEM_COMMA = 0xBC,
+ VK_OEM_MINUS = 0xBD,
+ VK_OEM_PERIOD = 0xBE,
+ VK_OEM_2 = 0xBF,
+ VK_OEM_3 = 0xC0,
+ VK_OEM_4 = 0xDB,
+ VK_OEM_5 = 0xDC,
+ VK_OEM_6 = 0xDD,
+ VK_OEM_7 = 0xDE,
+ VK_OEM_8 = 0xDF,
+ VK_OEM_AX = 0xE1,
+ VK_OEM_102 = 0xE2,
+ VK_ICO_HELP = 0xE3,
+ VK_ICO_00 = 0xE4,
+ VK_PROCESSKEY = 0xE5,
+ VK_OEM_ATTN = 0xF0,
+ VK_OEM_COPY = 0xF2,
+ VK_OEM_AUTO = 0xF3,
+ VK_OEM_ENLW = 0xF4,
+ VK_OEM_BACKTAB = 0xF5,
+ VK_ATTN = 0xF6,
+ VK_CRSEL = 0xF7,
+ VK_EXSEL = 0xF8,
+ VK_EREOF = 0xF9,
+ VK_PLAY = 0xFA,
+ VK_ZOOM = 0xFB,
+ VK_NONAME = 0xFC,
+ VK_PA1 = 0xFD,
+ VK_OEM_CLEAR = 0xFE,
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum TtyKeys {
+ XK_BackSpace = 0xff08, /* Back space, back char */
+ XK_Tab = 0xff09,
+ XK_Linefeed = 0xff0a, /* Linefeed, LF */
+ XK_Clear = 0xff0b,
+ XK_Return = 0xff0d, /* Return, enter */
+ XK_Pause = 0xff13, /* Pause, hold */
+ XK_Scroll_Lock = 0xff14,
+ XK_Sys_Req = 0xff15,
+ XK_Escape = 0xff1b,
+ XK_Delete = 0xffff /* Delete, rubout */
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum MiscKeys {
+ XK_ISO_Lock = 0xfe01,
+ XK_ISO_Last_Group_Lock = 0xfe0f,
+ XK_Select = 0xff60,
+ XK_Print = 0xff61,
+ XK_Execute = 0xff62,
+ XK_Insert = 0xff63,
+ XK_Undo = 0xff65,
+ XK_Redo = 0xff66,
+ XK_Menu = 0xff67,
+ XK_Find = 0xff68,
+ XK_Cancel = 0xff69,
+ XK_Help = 0xff6a,
+ XK_Break = 0xff6b,
+ XK_Mode_switch = 0xff7e,
+ XK_script_switch = 0xff7e,
+ XK_Num_Lock = 0xff7f
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum KeypadKeys {
+ XK_KP_Space = 0xff80,
+ XK_KP_Tab = 0xff89,
+ XK_KP_Enter = 0xff8d, /* Enter */
+ XK_KP_F1 = 0xff91, /* PF1, KP_A, ... */
+ XK_KP_F2 = 0xff92,
+ XK_KP_F3 = 0xff93,
+ XK_KP_F4 = 0xff94,
+ XK_KP_Home = 0xff95,
+ XK_KP_Left = 0xff96,
+ XK_KP_Up = 0xff97,
+ XK_KP_Right = 0xff98,
+ XK_KP_Down = 0xff99,
+ XK_KP_Prior = 0xff9a,
+ XK_KP_Page_Up = 0xff9a,
+ XK_KP_Next = 0xff9b,
+ XK_KP_Page_Down = 0xff9b,
+ XK_KP_End = 0xff9c,
+ XK_KP_Begin = 0xff9d,
+ XK_KP_Insert = 0xff9e,
+ XK_KP_Delete = 0xff9f,
+ XK_KP_Equal = 0xffbd, /* Equals */
+ XK_KP_Multiply = 0xffaa,
+ XK_KP_Add = 0xffab,
+ XK_KP_Separator = 0xffac, /* Separator, often comma */
+ XK_KP_Subtract = 0xffad,
+ XK_KP_Decimal = 0xffae,
+ XK_KP_Divide = 0xffaf,
+
+ XK_KP_0 = 0xffb0,
+ XK_KP_1 = 0xffb1,
+ XK_KP_2 = 0xffb2,
+ XK_KP_3 = 0xffb3,
+ XK_KP_4 = 0xffb4,
+ XK_KP_5 = 0xffb5,
+ XK_KP_6 = 0xffb6,
+ XK_KP_7 = 0xffb7,
+ XK_KP_8 = 0xffb8,
+ XK_KP_9 = 0xffb9
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum DeadKeys {
+ XK_dead_grave = 0xfe50,
+ XK_dead_acute = 0xfe51,
+ XK_dead_circumflex = 0xfe52,
+ XK_dead_tilde = 0xfe53,
+ XK_dead_macron = 0xfe54,
+ XK_dead_breve = 0xfe55,
+ XK_dead_abovedot = 0xfe56,
+ XK_dead_diaeresis = 0xfe57,
+ XK_dead_abovering = 0xfe58,
+ XK_dead_doubleacute = 0xfe59,
+ XK_dead_caron = 0xfe5a,
+ XK_dead_cedilla = 0xfe5b,
+ XK_dead_ogonek = 0xfe5c,
+ XK_dead_iota = 0xfe5d,
+ XK_dead_voiced_sound = 0xfe5e,
+ XK_dead_semivoiced_sound = 0xfe5f,
+ XK_dead_belowdot = 0xfe60,
+ XK_dead_hook = 0xfe61,
+ XK_dead_horn = 0xfe62
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ struct HELPINFO {
+ internal uint cbSize;
+ internal int iContextType;
+ internal int iCtrlId;
+ internal IntPtr hItemHandle;
+ internal uint dwContextId;
+ internal POINT MousePos;
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum PeekMessageFlags {
+ PM_NOREMOVE = 0x00000000,
+ PM_REMOVE = 0x00000001,
+ PM_NOYIELD = 0x00000002
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum StdCursor {
+ Default = 0,
+ AppStarting = 1,
+ Arrow = 2,
+ Cross = 3,
+ Hand = 4,
+ Help = 5,
+ HSplit = 6,
+ IBeam = 7,
+ No = 8,
+ NoMove2D = 9,
+ NoMoveHoriz = 10,
+ NoMoveVert = 11,
+ PanEast = 12,
+ PanNE = 13,
+ PanNorth = 14,
+ PanNW = 15,
+ PanSE = 16,
+ PanSouth = 17,
+ PanSW = 18,
+ PanWest = 19,
+ SizeAll = 20,
+ SizeNESW = 21,
+ SizeNS = 22,
+ SizeNWSE = 23,
+ SizeWE = 24,
+ UpArrow = 25,
+ VSplit = 26,
+ WaitCursor = 27
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum HitTest {
+ HTERROR = -2,
+ HTTRANSPARENT = -1,
+ HTNOWHERE = 0,
+ HTCLIENT = 1,
+ HTCAPTION = 2,
+ HTSYSMENU = 3,
+ HTGROWBOX = 4,
+ HTSIZE = HTGROWBOX,
+ HTMENU = 5,
+ HTHSCROLL = 6,
+ HTVSCROLL = 7,
+ HTMINBUTTON = 8,
+ HTMAXBUTTON = 9,
+ HTLEFT = 10,
+ HTRIGHT = 11,
+ HTTOP = 12,
+ HTTOPLEFT = 13,
+ HTTOPRIGHT = 14,
+ HTBOTTOM = 15,
+ HTBOTTOMLEFT = 16,
+ HTBOTTOMRIGHT = 17,
+ HTBORDER = 18,
+ HTREDUCE = HTMINBUTTON,
+ HTZOOM = HTMAXBUTTON,
+ HTSIZEFIRST = HTLEFT,
+ HTSIZELAST = HTBOTTOMRIGHT,
+ HTOBJECT = 19,
+ HTCLOSE = 20,
+ HTHELP = 21
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum TitleStyle {
+ None = 0,
+ Normal = 1,
+ Tool = 2
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ struct BITMAPINFOHEADER {
+ internal uint biSize;
+ internal int biWidth;
+ internal int biHeight;
+ internal ushort biPlanes;
+ internal ushort biBitCount;
+ internal uint biCompression;
+ internal uint biSizeImage;
+ internal int biXPelsPerMeter;
+ internal int biYPelsPerMeter;
+ internal uint biClrUsed;
+ internal uint biClrImportant;
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum ClipboardFormats : ushort {
+ CF_TEXT = 1,
+ CF_BITMAP = 2,
+ CF_METAFILEPICT = 3,
+ CF_SYLK = 4,
+ CF_DIF = 5,
+ CF_TIFF = 6,
+ CF_OEMTEXT = 7,
+ CF_DIB = 8,
+ CF_PALETTE = 9,
+ CF_PENDATA = 10,
+ CF_RIFF = 11,
+ CF_WAVE = 12,
+ CF_UNICODETEXT = 13,
+ CF_ENHMETAFILE = 14,
+ CF_HDROP = 15,
+ CF_LOCALE = 16,
+ CF_DIBV5 = 17
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ struct MINMAXINFO {
+ internal POINT ptReserved;
+ internal POINT ptMaxSize;
+ internal POINT ptMaxPosition;
+ internal POINT ptMinTrackSize;
+ internal POINT ptMaxTrackSize;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ struct KeyFilterData {
+ internal bool Down;
+ internal int keycode;
+ internal int keysym;
+ internal Keys ModifierKeys;
+ internal String str;
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum ScrollBarCommands {
+ SB_LINEUP = 0,
+ SB_LINELEFT = 0,
+ SB_LINEDOWN = 1,
+ SB_LINERIGHT = 1,
+ SB_PAGEUP = 2,
+ SB_PAGELEFT = 2,
+ SB_PAGEDOWN = 3,
+ SB_PAGERIGHT = 3,
+ SB_THUMBPOSITION = 4,
+ SB_THUMBTRACK = 5,
+ SB_TOP = 6,
+ SB_LEFT = 6,
+ SB_BOTTOM = 7,
+ SB_RIGHT = 7,
+ SB_ENDSCROLL = 8
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum ClipCombineMode {
+ RGN_AND = 1,
+ RGN_OR,
+ RGN_XOR,
+ RGN_DIFF,
+ RGN_COPY,
+
+ RGN_MIN = RGN_AND,
+ RGN_MAX = RGN_COPY
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum SystemCommands {
+ SC_SIZE = 0xF000,
+ SC_MOVE = 0xF010,
+ SC_MINIMIZE = 0xF020,
+ SC_MAXIMIZE = 0xF030,
+ SC_NEXTWINDOW = 0xF040,
+ SC_PREVWINDOW = 0xF050,
+ SC_CLOSE = 0xF060,
+ SC_VSCROLL = 0xF070,
+ SC_HSCROLL = 0xF080,
+ SC_MOUSEMENU = 0xF090,
+ SC_KEYMENU = 0xF100,
+ SC_ARRANGE = 0xF110,
+ SC_RESTORE = 0xF120,
+ SC_TASKLIST = 0xF130,
+ SC_SCREENSAVE = 0xF140,
+ SC_HOTKEY = 0xF150,
+ SC_DEFAULT = 0xF160,
+ SC_MONITORPOWER = 0xF170,
+ SC_CONTEXTHELP = 0xF180
+ }
+
+#if PUBLIC_TYPES
+ public
+#else
+ internal
+#endif
+ enum AlertType {
+ Default = 1,
+ Error = 2,
+ Question = 3,
+ Warning = 4,
+ Information = 5
+ }
+}
+
diff --git a/source/ShiftUI/Internal/XplatUIWin32.cs b/source/ShiftUI/Internal/XplatUIWin32.cs
new file mode 100644
index 0000000..a741a46
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUIWin32.cs
@@ -0,0 +1,3751 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+// NOT COMPLETE
+
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+
+
+/// Win32 Version
+namespace ShiftUI {
+ internal class XplatUIWin32 : XplatUIDriver {
+ #region Local Variables
+ private static XplatUIWin32 instance;
+ private static int ref_count;
+ private static IntPtr FosterParentLast;
+
+ internal static MouseButtons mouse_state;
+ internal static Point mouse_position;
+ internal static bool grab_confined;
+ internal static IntPtr grab_hwnd;
+ internal static Rectangle grab_area;
+ internal static WndProc wnd_proc;
+ internal static IntPtr prev_mouse_hwnd;
+ internal static bool caret_visible;
+
+ internal static bool themes_enabled;
+ private Hashtable timer_list;
+ private static Queue message_queue;
+ 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 RECT clipped_cursor_rect;
+ private Hashtable registered_classes;
+ private Hwnd HwndCreating; // the Hwnd we are currently creating (see CreateWindow)
+
+ #endregion // Local Variables
+
+ #region Private Structs
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+ private struct WNDCLASS {
+ internal int style;
+ internal WndProc lpfnWndProc;
+ internal int cbClsExtra;
+ internal int cbWndExtra;
+ internal IntPtr hInstance;
+ internal IntPtr hIcon;
+ internal IntPtr hCursor;
+ internal IntPtr hbrBackground;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ internal string lpszMenuName;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ internal string lpszClassName;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct RECT {
+ internal int left;
+ internal int top;
+ internal int right;
+ internal int bottom;
+
+ public RECT (int left, int top, int right, int bottom)
+ {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ #region Instance Properties
+ public int Height { get { return bottom - top; } }
+ public int Width { get { return right - left; } }
+ public Size Size { get { return new Size (Width, Height); } }
+ public Point Location { get { return new Point (left, top); } }
+ #endregion
+
+ #region Instance Methods
+ public Rectangle ToRectangle ()
+ {
+ return Rectangle.FromLTRB (left, top, right, bottom);
+ }
+
+ public static RECT FromRectangle (Rectangle rectangle)
+ {
+ return new RECT (rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom);
+ }
+
+ public override int GetHashCode ()
+ {
+ return left ^ ((top << 13) | (top >> 0x13))
+ ^ ((Width << 0x1a) | (Width >> 6))
+ ^ ((Height << 7) | (Height >> 0x19));
+ }
+
+ public override string ToString ()
+ {
+ return String.Format("RECT left={0}, top={1}, right={2}, bottom={3}, width={4}, height={5}", left, top, right, bottom, right-left, bottom-top);
+ }
+ #endregion
+
+ #region Operator overloads
+ public static implicit operator Rectangle (RECT rect)
+ {
+ return Rectangle.FromLTRB (rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ public static implicit operator RECT (Rectangle rect)
+ {
+ return new RECT (rect.Left, rect.Top, rect.Right, rect.Bottom);
+ }
+ #endregion
+ }
+
+ internal enum SPIAction {
+ SPI_GETACTIVEWINDOWTRACKING = 0x1000,
+ SPI_GETACTIVEWNDTRKTIMEOUT = 0x2002,
+ SPI_GETANIMATION = 0x0048,
+ SPI_GETCARETWIDTH = 0x2006,
+ SPI_GETCOMBOBOXANIMATION = 0x1004,
+ SPI_GETDRAGFULLWINDOWS = 0x0026,
+ SPI_GETDROPSHADOW = 0x1024,
+ SPI_GETFONTSMOOTHING = 0x004A,
+ SPI_GETFONTSMOOTHINGCONTRAST = 0x200C,
+ SPI_GETFONTSMOOTHINGTYPE = 0x200A,
+ SPI_GETGRADIENTCAPTIONS = 0x1008,
+ SPI_GETHOTTRACKING = 0x100E,
+ SPI_GETICONTITLEWRAP = 0x0019,
+ SPI_GETKEYBOARDSPEED = 0x000A,
+ SPI_GETKEYBOARDDELAY = 0x0016,
+ SPI_GETKEYBOARDCUES = 0x100A,
+ SPI_GETKEYBOARDPREF = 0x0044,
+ SPI_GETLISTBOXSMOOTHSCROLLING = 0x1006,
+ SPI_GETMENUANIMATION = 0x1002,
+ SPI_GETMENUDROPALIGNMENT = 0x001B,
+ SPI_GETMENUFADE = 0x1012,
+ SPI_GETMENUSHOWDELAY = 0x006A,
+ SPI_GETMOUSESPEED = 0x0070,
+ SPI_GETSELECTIONFADE = 0x1014,
+ SPI_GETSNAPTODEFBUTTON = 0x005F,
+ SPI_GETTOOLTIPANIMATION = 0x1016,
+ SPI_GETWORKAREA = 0x0030,
+ SPI_GETMOUSEHOVERWIDTH = 0x0062,
+ SPI_GETMOUSEHOVERHEIGHT = 0x0064,
+ SPI_GETMOUSEHOVERTIME = 0x0066,
+ SPI_GETUIEFFECTS = 0x103E,
+ SPI_GETWHEELSCROLLLINES = 0x0068
+ }
+
+ internal enum WindowPlacementFlags {
+ SW_HIDE = 0,
+ SW_SHOWNORMAL = 1,
+ SW_NORMAL = 1,
+ SW_SHOWMINIMIZED = 2,
+ SW_SHOWMAXIMIZED = 3,
+ SW_MAXIMIZE = 3,
+ SW_SHOWNOACTIVATE = 4,
+ SW_SHOW = 5,
+ SW_MINIMIZE = 6,
+ SW_SHOWMINNOACTIVE = 7,
+ SW_SHOWNA = 8,
+ SW_RESTORE = 9,
+ SW_SHOWDEFAULT = 10,
+ SW_FORCEMINIMIZE = 11,
+ SW_MAX = 11
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct WINDOWPLACEMENT {
+ internal uint length;
+ internal uint flags;
+ internal WindowPlacementFlags showCmd;
+ internal POINT ptMinPosition;
+ internal POINT ptMaxPosition;
+ internal RECT rcNormalPosition;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct NCCALCSIZE_PARAMS {
+ internal RECT rgrc1;
+ internal RECT rgrc2;
+ internal RECT rgrc3;
+ internal IntPtr lppos;
+ }
+
+ [Flags]
+ private enum TMEFlags {
+ TME_HOVER = 0x00000001,
+ TME_LEAVE = 0x00000002,
+ TME_NONCLIENT = 0x00000010,
+ TME_QUERY = unchecked((int)0x40000000),
+ TME_CANCEL = unchecked((int)0x80000000)
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct TRACKMOUSEEVENT {
+ internal int size;
+ internal TMEFlags dwFlags;
+ internal IntPtr hWnd;
+ internal int dwHoverTime;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct PAINTSTRUCT {
+ internal IntPtr hdc;
+ internal int fErase;
+ internal RECT rcPaint;
+ internal int fRestore;
+ internal int fIncUpdate;
+ internal int Reserved1;
+ internal int Reserved2;
+ internal int Reserved3;
+ internal int Reserved4;
+ internal int Reserved5;
+ internal int Reserved6;
+ internal int Reserved7;
+ internal int Reserved8;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct KEYBDINPUT {
+ internal short wVk;
+ internal short wScan;
+ internal Int32 dwFlags;
+ internal Int32 time;
+ internal UIntPtr dwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MOUSEINPUT {
+ internal Int32 dx;
+ internal Int32 dy;
+ internal Int32 mouseData;
+ internal Int32 dwFlags;
+ internal Int32 time;
+ internal UIntPtr dwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct HARDWAREINPUT {
+ internal Int32 uMsg;
+ internal short wParamL;
+ internal short wParamH;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct ICONINFO {
+ internal bool fIcon;
+ internal Int32 xHotspot;
+ internal Int32 yHotspot;
+ internal IntPtr hbmMask;
+ internal IntPtr hbmColor;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct INPUT {
+ [FieldOffset(0)]
+ internal Int32 type;
+
+ [FieldOffset(4)]
+ internal MOUSEINPUT mi;
+
+ [FieldOffset(4)]
+ internal KEYBDINPUT ki;
+
+ [FieldOffset(4)]
+ internal HARDWAREINPUT hi;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct ANIMATIONINFO {
+ internal uint cbSize;
+ internal int iMinAnimate;
+ }
+
+ internal enum InputFlags {
+ KEYEVENTF_EXTENDEDKEY = 0x0001,
+ KEYEVENTF_KEYUP = 0x0002,
+ KEYEVENTF_SCANCODE = 0x0003,
+ KEYEVENTF_UNICODE = 0x0004,
+ }
+
+ internal enum ClassStyle {
+ CS_VREDRAW = 0x00000001,
+ CS_HREDRAW = 0x00000002,
+ CS_KEYCVTWINDOW = 0x00000004,
+ CS_DBLCLKS = 0x00000008,
+ CS_OWNDC = 0x00000020,
+ CS_CLASSDC = 0x00000040,
+ CS_PARENTDC = 0x00000080,
+ CS_NOKEYCVT = 0x00000100,
+ CS_NOCLOSE = 0x00000200,
+ CS_SAVEBITS = 0x00000800,
+ CS_BYTEALIGNCLIENT = 0x00001000,
+ CS_BYTEALIGNWINDOW = 0x00002000,
+ CS_GLOBALCLASS = 0x00004000,
+ CS_IME = 0x00010000,
+ // Windows XP+
+ CS_DROPSHADOW = 0x00020000
+ }
+
+ internal enum SetWindowPosZOrder {
+ HWND_TOP = 0,
+ HWND_BOTTOM = 1,
+ HWND_TOPMOST = -1,
+ HWND_NOTOPMOST = -2
+ }
+
+ [Flags]
+ internal enum SetWindowPosFlags {
+ SWP_ASYNCWINDOWPOS = 0x4000,
+ SWP_DEFERERASE = 0x2000,
+ SWP_DRAWFRAME = 0x0020,
+ SWP_FRAMECHANGED = 0x0020,
+ SWP_HIDEWINDOW = 0x0080,
+ SWP_NOACTIVATE = 0x0010,
+ SWP_NOCOPYBITS = 0x0100,
+ SWP_NOMOVE = 0x0002,
+ SWP_NOOWNERZORDER = 0x0200,
+ SWP_NOREDRAW = 0x0008,
+ SWP_NOREPOSITION = 0x0200,
+ SWP_NOENDSCHANGING = 0x0400,
+ SWP_NOSIZE = 0x0001,
+ SWP_NOZORDER = 0x0004,
+ SWP_SHOWWINDOW = 0x0040
+ }
+
+ internal enum GetSysColorIndex {
+ COLOR_SCROLLBAR = 0,
+ COLOR_BACKGROUND = 1,
+ COLOR_ACTIVECAPTION = 2,
+ COLOR_INACTIVECAPTION = 3,
+ COLOR_MENU = 4,
+ COLOR_WINDOW = 5,
+ COLOR_WINDOWFRAME = 6,
+ COLOR_MENUTEXT = 7,
+ COLOR_WINDOWTEXT = 8,
+ COLOR_CAPTIONTEXT = 9,
+ COLOR_ACTIVEBORDER = 10,
+ COLOR_INACTIVEBORDER = 11,
+ COLOR_APPWORKSPACE = 12,
+ COLOR_HIGHLIGHT = 13,
+ COLOR_HIGHLIGHTTEXT = 14,
+ COLOR_BTNFACE = 15,
+ COLOR_BTNSHADOW = 16,
+ COLOR_GRAYTEXT = 17,
+ COLOR_BTNTEXT = 18,
+ COLOR_INACTIVECAPTIONTEXT = 19,
+ COLOR_BTNHIGHLIGHT = 20,
+ COLOR_3DDKSHADOW = 21,
+ COLOR_3DLIGHT = 22,
+ COLOR_INFOTEXT = 23,
+ COLOR_INFOBK = 24,
+
+ COLOR_HOTLIGHT = 26,
+ COLOR_GRADIENTACTIVECAPTION = 27,
+ COLOR_GRADIENTINACTIVECAPTION = 28,
+ COLOR_MENUHIGHLIGHT = 29,
+ COLOR_MENUBAR = 30,
+
+ COLOR_DESKTOP = 1,
+ COLOR_3DFACE = 16,
+ COLOR_3DSHADOW = 16,
+ COLOR_3DHIGHLIGHT = 20,
+ COLOR_3DHILIGHT = 20,
+ COLOR_BTNHILIGHT = 20,
+ COLOR_MAXVALUE = 24,/* Maximum value */
+ }
+
+ private enum LoadCursorType {
+ First = 32512,
+ IDC_ARROW = 32512,
+ IDC_IBEAM = 32513,
+ IDC_WAIT = 32514,
+ IDC_CROSS = 32515,
+ IDC_UPARROW = 32516,
+ IDC_SIZE = 32640,
+ IDC_ICON = 32641,
+ IDC_SIZENWSE = 32642,
+ IDC_SIZENESW = 32643,
+ IDC_SIZEWE = 32644,
+ IDC_SIZENS = 32645,
+ IDC_SIZEALL = 32646,
+ IDC_NO = 32648,
+ IDC_HAND = 32649,
+ IDC_APPSTARTING = 32650,
+ IDC_HELP = 32651,
+ Last = 32651
+ }
+
+ private enum AncestorType {
+ GA_PARENT = 1,
+ GA_ROOT = 2,
+ GA_ROOTOWNER = 3
+ }
+
+ [Flags]
+ private enum WindowLong {
+ GWL_WNDPROC = -4,
+ GWL_HINSTANCE = -6,
+ GWL_HWNDPARENT = -8,
+ GWL_STYLE = -16,
+ GWL_EXSTYLE = -20,
+ GWL_USERDATA = -21,
+ GWL_ID = -12
+ }
+
+ [Flags]
+ private enum LogBrushStyle {
+ BS_SOLID = 0,
+ BS_NULL = 1,
+ BS_HATCHED = 2,
+ BS_PATTERN = 3,
+ BS_INDEXED = 4,
+ BS_DIBPATTERN = 5,
+ BS_DIBPATTERNPT = 6,
+ BS_PATTERN8X8 = 7,
+ BS_DIBPATTERN8X8 = 8,
+ BS_MONOPATTERN = 9
+ }
+
+ [Flags]
+ private enum LogBrushHatch {
+ HS_HORIZONTAL = 0, /* ----- */
+ HS_VERTICAL = 1, /* ||||| */
+ HS_FDIAGONAL = 2, /* \\\\\ */
+ HS_BDIAGONAL = 3, /* ///// */
+ HS_CROSS = 4, /* +++++ */
+ HS_DIAGCROSS = 5, /* xxxxx */
+ }
+
+ internal struct COLORREF {
+ internal byte R;
+ internal byte G;
+ internal byte B;
+ internal byte A;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct LOGBRUSH {
+ internal LogBrushStyle lbStyle;
+ internal COLORREF lbColor;
+ internal LogBrushHatch lbHatch;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct TEXTMETRIC {
+ internal int tmHeight;
+ internal int tmAscent;
+ internal int tmDescent;
+ internal int tmInternalLeading;
+ internal int tmExternalLeading;
+ internal int tmAveCharWidth;
+ internal int tmMaxCharWidth;
+ internal int tmWeight;
+ internal int tmOverhang;
+ internal int tmDigitizedAspectX;
+ internal int tmDigitizedAspectY;
+ internal short tmFirstChar;
+ internal short tmLastChar;
+ internal short tmDefaultChar;
+ internal short tmBreakChar;
+ internal byte tmItalic;
+ internal byte tmUnderlined;
+ internal byte tmStruckOut;
+ internal byte tmPitchAndFamily;
+ internal byte tmCharSet;
+ }
+
+ public enum TernaryRasterOperations : uint
+ {
+ SRCCOPY = 0x00CC0020,
+ SRCPAINT = 0x00EE0086,
+ SRCAND = 0x008800C6,
+ SRCINVERT = 0x00660046,
+ SRCERASE = 0x00440328,
+ NOTSRCCOPY = 0x00330008,
+ NOTSRCERASE = 0x001100A6,
+ MERGECOPY = 0x00C000CA,
+ MERGEPAINT = 0x00BB0226,
+ PATCOPY = 0x00F00021,
+ PATPAINT = 0x00FB0A09,
+ PATINVERT = 0x005A0049,
+ DSTINVERT = 0x00550009,
+ BLACKNESS = 0x00000042,
+ WHITENESS = 0x00FF0062
+ }
+
+ [Flags]
+ private enum ScrollWindowExFlags {
+ SW_NONE = 0x0000,
+ SW_SCROLLCHILDREN = 0x0001,
+ SW_INVALIDATE = 0x0002,
+ SW_ERASE = 0x0004,
+ SW_SMOOTHSCROLL = 0x0010
+ }
+
+ internal enum SystemMetrics {
+ SM_CXSCREEN = 0,
+ SM_CYSCREEN = 1,
+ SM_CXVSCROLL = 2,
+ SM_CYHSCROLL = 3,
+ SM_CYCAPTION = 4,
+ SM_CXBORDER = 5,
+ SM_CYBORDER = 6,
+ SM_CXDLGFRAME = 7,
+ SM_CYDLGFRAME = 8,
+ SM_CYVTHUMB = 9,
+ SM_CXHTHUMB = 10,
+ SM_CXICON = 11,
+ SM_CYICON = 12,
+ SM_CXCURSOR = 13,
+ SM_CYCURSOR = 14,
+ SM_CYMENU = 15,
+ SM_CXFULLSCREEN = 16,
+ SM_CYFULLSCREEN = 17,
+ SM_CYKANJIWINDOW = 18,
+ SM_MOUSEPRESENT = 19,
+ SM_CYVSCROLL = 20,
+ SM_CXHSCROLL = 21,
+ SM_DEBUG = 22,
+ SM_SWAPBUTTON = 23,
+ SM_RESERVED1 = 24,
+ SM_RESERVED2 = 25,
+ SM_RESERVED3 = 26,
+ SM_RESERVED4 = 27,
+ SM_CXMIN = 28,
+ SM_CYMIN = 29,
+ SM_CXSIZE = 30,
+ SM_CYSIZE = 31,
+ SM_CXFRAME = 32,
+ SM_CYFRAME = 33,
+ SM_CXMINTRACK = 34,
+ SM_CYMINTRACK = 35,
+ SM_CXDOUBLECLK = 36,
+ SM_CYDOUBLECLK = 37,
+ SM_CXICONSPACING = 38,
+ SM_CYICONSPACING = 39,
+ SM_MENUDROPALIGNMENT = 40,
+ SM_PENWINDOWS = 41,
+ SM_DBCSENABLED = 42,
+ SM_CMOUSEBUTTONS = 43,
+ SM_CXFIXEDFRAME = SM_CXDLGFRAME,
+ SM_CYFIXEDFRAME = SM_CYDLGFRAME,
+ SM_CXSIZEFRAME = SM_CXFRAME,
+ SM_CYSIZEFRAME = SM_CYFRAME,
+ SM_SECURE = 44,
+ SM_CXEDGE = 45,
+ SM_CYEDGE = 46,
+ SM_CXMINSPACING = 47,
+ SM_CYMINSPACING = 48,
+ SM_CXSMICON = 49,
+ SM_CYSMICON = 50,
+ SM_CYSMCAPTION = 51,
+ SM_CXSMSIZE = 52,
+ SM_CYSMSIZE = 53,
+ SM_CXMENUSIZE = 54,
+ SM_CYMENUSIZE = 55,
+ SM_ARRANGE = 56,
+ SM_CXMINIMIZED = 57,
+ SM_CYMINIMIZED = 58,
+ SM_CXMAXTRACK = 59,
+ SM_CYMAXTRACK = 60,
+ SM_CXMAXIMIZED = 61,
+ SM_CYMAXIMIZED = 62,
+ SM_NETWORK = 63,
+ SM_CLEANBOOT = 67,
+ SM_CXDRAG = 68,
+ SM_CYDRAG = 69,
+ SM_SHOWSOUNDS = 70,
+ SM_CXMENUCHECK = 71,
+ SM_CYMENUCHECK = 72,
+ SM_SLOWMACHINE = 73,
+ SM_MIDEASTENABLED = 74,
+ SM_MOUSEWHEELPRESENT = 75,
+ SM_XVIRTUALSCREEN = 76,
+ SM_YVIRTUALSCREEN = 77,
+ SM_CXVIRTUALSCREEN = 78,
+ SM_CYVIRTUALSCREEN = 79,
+ SM_CMONITORS = 80,
+ SM_SAMEDISPLAYFORMAT = 81,
+ SM_IMMENABLED = 82,
+ SM_CXFOCUSBORDER = 83,
+ SM_CYFOCUSBORDER = 84,
+ SM_TABLETPC = 86,
+ SM_MEDIACENTER = 87,
+ SM_CMETRICS = 88
+ }
+
+ // We'll only support _WIN32_IE < 0x0500 for now
+ internal enum NotifyIconMessage {
+ NIM_ADD = 0x00000000,
+ NIM_MODIFY = 0x00000001,
+ NIM_DELETE = 0x00000002,
+ }
+
+ [Flags]
+ internal enum NotifyIconFlags {
+ NIF_MESSAGE = 0x00000001,
+ NIF_ICON = 0x00000002,
+ NIF_TIP = 0x00000004,
+ NIF_STATE = 0x00000008,
+ NIF_INFO = 0x00000010
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+ internal struct NOTIFYICONDATA {
+ internal uint cbSize;
+ internal IntPtr hWnd;
+ internal uint uID;
+ internal NotifyIconFlags uFlags;
+ internal uint uCallbackMessage;
+ internal IntPtr hIcon;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
+ internal string szTip;
+ internal int dwState;
+ internal int dwStateMask;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
+ internal string szInfo;
+ internal int uTimeoutOrVersion;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
+ internal string szInfoTitle;
+ internal ToolTipIcon dwInfoFlags;
+ }
+
+ [Flags]
+ internal enum DCExFlags {
+ DCX_WINDOW = 0x00000001,
+ DCX_CACHE = 0x00000002,
+ DCX_NORESETATTRS = 0x00000004,
+ DCX_CLIPCHILDREN = 0x00000008,
+ DCX_CLIPSIBLINGS = 0x00000010,
+ DCX_PARENTCLIP = 0x00000020,
+ DCX_EXCLUDERGN = 0x00000040,
+ DCX_INTERSECTRGN = 0x00000080,
+ DCX_EXCLUDEUPDATE = 0x00000100,
+ DCX_INTERSECTUPDATE = 0x00000200,
+ DCX_LOCKWINDOWUPDATE = 0x00000400,
+ DCX_USESTYLE = 0x00010000,
+ DCX_VALIDATE = 0x00200000
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+ internal struct CLIENTCREATESTRUCT {
+ internal IntPtr hWindowMenu;
+ internal uint idFirstChild;
+ }
+
+ private enum ClassLong : int {
+ GCL_MENUNAME = -8,
+ GCL_HBRBACKGROUND = -10,
+ GCL_HCURSOR = -12,
+ GCL_HICON = -14,
+ GCL_HMODULE = -16,
+ GCL_CBWNDEXTRA = -18,
+ GCL_CBCLSEXTRA = -20,
+ GCL_WNDPROC = -24,
+ GCL_STYLE = -26,
+ GCW_ATOM = -32,
+ GCL_HICONSM = -34
+ }
+
+ [Flags]
+ internal enum GAllocFlags : uint {
+ GMEM_FIXED = 0x0000,
+ GMEM_MOVEABLE = 0x0002,
+ GMEM_NOCOMPACT = 0x0010,
+ GMEM_NODISCARD = 0x0020,
+ GMEM_ZEROINIT = 0x0040,
+ GMEM_MODIFY = 0x0080,
+ GMEM_DISCARDABLE = 0x0100,
+ GMEM_NOT_BANKED = 0x1000,
+ GMEM_SHARE = 0x2000,
+ GMEM_DDESHARE = 0x2000,
+ GMEM_NOTIFY = 0x4000,
+ GMEM_LOWER = GMEM_NOT_BANKED,
+ GMEM_VALID_FLAGS = 0x7F72,
+ GMEM_INVALID_HANDLE = 0x8000,
+ GHND = (GMEM_MOVEABLE | GMEM_ZEROINIT),
+ GPTR = (GMEM_FIXED | GMEM_ZEROINIT)
+ }
+
+ internal enum ROP2DrawMode : int {
+ R2_BLACK = 1,
+ R2_NOTMERGEPEN = 2,
+ R2_MASKNOTPEN = 3,
+ R2_NOTCOPYPEN = 4,
+ R2_MASKPENNOT = 5,
+ R2_NOT = 6,
+ R2_XORPEN = 7,
+ R2_NOTMASKPEN = 8,
+ R2_MASKPEN = 9,
+ R2_NOTXORPEN = 10,
+ R2_NOP = 11,
+ R2_MERGENOTPEN = 12,
+ R2_COPYPEN = 13,
+ R2_MERGEPENNOT = 14,
+ R2_MERGEPEN = 15,
+ R2_WHITE = 16,
+ R2_LAST = 16
+ }
+
+ internal enum PenStyle : int {
+ PS_SOLID = 0,
+ PS_DASH = 1,
+ PS_DOT = 2,
+ PS_DASHDOT = 3,
+ PS_DASHDOTDOT = 4,
+ PS_NULL = 5,
+ PS_INSIDEFRAME = 6,
+ PS_USERSTYLE = 7,
+ PS_ALTERNATE = 8
+ }
+
+ internal enum PatBltRop : int {
+ PATCOPY = 0xf00021,
+ PATINVERT = 0x5a0049,
+ DSTINVERT = 0x550009,
+ BLACKNESS = 0x000042,
+ WHITENESS = 0xff0062,
+ }
+
+ internal enum StockObject : int {
+ WHITE_BRUSH = 0,
+ LTGRAY_BRUSH = 1,
+ GRAY_BRUSH = 2,
+ DKGRAY_BRUSH = 3,
+ BLACK_BRUSH = 4,
+ NULL_BRUSH = 5,
+ HOLLOW_BRUSH = NULL_BRUSH,
+ WHITE_PEN = 6,
+ BLACK_PEN = 7,
+ NULL_PEN = 8,
+ OEM_FIXED_FONT = 10,
+ ANSI_FIXED_FONT = 11,
+ ANSI_VAR_FONT = 12,
+ SYSTEM_FONT = 13,
+ DEVICE_DEFAULT_FONT = 14,
+ DEFAULT_PALETTE = 15,
+ SYSTEM_FIXED_FONT = 16
+ }
+
+ internal enum HatchStyle : int {
+ HS_HORIZONTAL = 0,
+ HS_VERTICAL = 1,
+ HS_FDIAGONAL = 2,
+ HS_BDIAGONAL = 3,
+ HS_CROSS = 4,
+ HS_DIAGCROSS = 5
+ }
+
+ [Flags]
+ internal enum SndFlags : int {
+ SND_SYNC = 0x0000,
+ SND_ASYNC = 0x0001,
+ SND_NODEFAULT = 0x0002,
+ SND_MEMORY = 0x0004,
+ SND_LOOP = 0x0008,
+ SND_NOSTOP = 0x0010,
+ SND_NOWAIT = 0x00002000,
+ SND_ALIAS = 0x00010000,
+ SND_ALIAS_ID = 0x00110000,
+ SND_FILENAME = 0x00020000,
+ SND_RESOURCE = 0x00040004,
+ SND_PURGE = 0x0040,
+ SND_APPLICATION = 0x0080,
+ }
+
+ [Flags]
+ internal enum LayeredWindowAttributes : int {
+ LWA_COLORKEY = 0x1,
+ LWA_ALPHA = 0x2,
+ }
+
+ public enum ACLineStatus : byte {
+ Offline = 0,
+ Online = 1,
+ Unknown = 255
+ }
+
+ public enum BatteryFlag : byte {
+ High = 1,
+ Low = 2,
+ Critical = 4,
+ Charging = 8,
+ NoSystemBattery = 128,
+ Unknown = 255
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ public class SYSTEMPOWERSTATUS {
+ public ACLineStatus _ACLineStatus;
+ public BatteryFlag _BatteryFlag;
+ public Byte _BatteryLifePercent;
+ public Byte _Reserved1;
+ public Int32 _BatteryLifeTime;
+ public Int32 _BatteryFullLifeTime;
+ }
+ #endregion
+
+ #region Constructor & Destructor
+ private XplatUIWin32() {
+ // Handle singleton stuff first
+ ref_count=0;
+
+ mouse_state = MouseButtons.None;
+ mouse_position = Point.Empty;
+
+ grab_confined = false;
+ grab_area = Rectangle.Empty;
+
+ message_queue = new Queue();
+
+ themes_enabled = false;
+
+ wnd_proc = new WndProc(InternalWndProc);
+
+ FosterParentLast = IntPtr.Zero;
+
+ scroll_height = Win32GetSystemMetrics(SystemMetrics.SM_CYHSCROLL);
+ scroll_width = Win32GetSystemMetrics(SystemMetrics.SM_CXVSCROLL);
+
+ timer_list = new Hashtable ();
+ registered_classes = new Hashtable ();
+ }
+ #endregion // Constructor & Destructor
+
+ #region Private Support Methods
+
+ private IntPtr GetFosterParent()
+ {
+ if (!IsWindow(FosterParentLast))
+ {
+ FosterParentLast=Win32CreateWindow(WindowExStyles.WS_EX_TOOLWINDOW, "static", "Foster Parent Window", WindowStyles.WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+
+ if (FosterParentLast==IntPtr.Zero) {
+ Win32MessageBox(IntPtr.Zero, "Could not create foster window, win32 error " + Win32GetLastError().ToString(), "Oops", 0);
+ }
+ }
+ return FosterParentLast;
+ }
+
+ private string RegisterWindowClass (int classStyle)
+ {
+ string class_name;
+
+ lock (registered_classes) {
+ class_name = (string)registered_classes[classStyle];
+
+ if (class_name != null)
+ return class_name;
+
+ class_name = string.Format ("ShiftUI.Form.Thread={0}.GUID={1}", System.Threading.Thread.GetDomainID ().ToString (), Guid.NewGuid().ToString());
+
+ WNDCLASS wndClass;
+
+ wndClass.style = classStyle;
+ wndClass.lpfnWndProc = wnd_proc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hbrBackground = (IntPtr)(GetSysColorIndex.COLOR_WINDOW + 1);
+ wndClass.hCursor = Win32LoadCursor (IntPtr.Zero, LoadCursorType.IDC_ARROW);
+ wndClass.hIcon = IntPtr.Zero;
+ wndClass.hInstance = IntPtr.Zero;
+ wndClass.lpszClassName = class_name;
+ wndClass.lpszMenuName = "";
+
+ bool result = Win32RegisterClass (ref wndClass);
+
+ if (result == false)
+ Win32MessageBox (IntPtr.Zero, "Could not register the window class, win32 error " + Win32GetLastError ().ToString (), "Oops", 0);
+
+ registered_classes[classStyle] = class_name;
+ }
+
+ return class_name;
+ }
+
+ private static bool RetrieveMessage(ref MSG msg) {
+ MSG message;
+
+ if (message_queue.Count == 0) {
+ return false;
+ }
+
+ message = (MSG)message_queue.Dequeue();
+ msg = message;
+
+ return true;
+ }
+
+ private static bool StoreMessage(ref MSG msg) {
+ MSG message = new MSG();
+
+ message = msg;
+ message_queue.Enqueue(message);
+
+ return true;
+ }
+
+ internal static String AnsiToString(IntPtr ansi_data) {
+ return (string)Marshal.PtrToStringAnsi(ansi_data);
+ }
+
+ internal static String UnicodeToString(IntPtr unicode_data) {
+ return (string)Marshal.PtrToStringUni(unicode_data);
+ }
+
+ internal static Image DIBtoImage(IntPtr dib_data) {
+ BITMAPINFOHEADER bmi;
+ int ncolors;
+ int imagesize;
+ //int palettesize;
+ Bitmap bmp;
+ BitmapData bits;
+ ColorPalette pal;
+ int[] palette;
+ byte[] imagebits;
+ int bytesPerLine;
+
+ bmi = (BITMAPINFOHEADER)Marshal.PtrToStructure(dib_data, typeof(BITMAPINFOHEADER));
+
+ ncolors = (int)bmi.biClrUsed;
+ if (ncolors == 0) {
+ if (bmi.biBitCount < 24) {
+ ncolors = (int)(1 << bmi.biBitCount);
+ }
+ }
+ //palettesize = ncolors * 4;
+
+ imagesize = (int)bmi.biSizeImage;
+ if (imagesize == 0) {
+ imagesize = (int)(((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight);
+ }
+
+ switch(bmi.biBitCount) {
+ case 1: { // Monochrome
+ bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format1bppIndexed);
+ palette = new int[2];
+ break;
+ }
+
+ case 4: { // 4bpp
+ bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format4bppIndexed);
+ palette = new int[16];
+ break;
+ }
+
+ case 8: { // 8bpp
+ bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format8bppIndexed);
+ palette = new int[256];
+ break;
+ }
+
+ case 24:
+ case 32: { // 32bpp
+ bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format32bppArgb);
+ palette = new int[0];
+ break;
+ }
+
+ default: {
+ throw new Exception("Unexpected number of bits:" + bmi.biBitCount.ToString());
+ }
+ }
+
+ if (bmi.biBitCount < 24) {
+ pal = bmp.Palette; // Managed palette
+ Marshal.Copy((IntPtr)((int)dib_data + Marshal.SizeOf(typeof(BITMAPINFOHEADER))), palette, 0, palette.Length);
+
+ for (int i = 0; i < ncolors; i++) {
+ pal.Entries[i] = Color.FromArgb(palette[i] | unchecked((int)0xff000000));
+ }
+ bmp.Palette = pal;
+ }
+
+ bytesPerLine = (int)((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3);
+ bits = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
+
+ imagebits = new byte[bytesPerLine];
+
+ for (int y = 0; y < bmi.biHeight; y++) {
+ // Copy from source to managed
+ Marshal.Copy((IntPtr)((int)dib_data + Marshal.SizeOf(typeof(BITMAPINFOHEADER)) + palette.Length * 4 + bytesPerLine * y), imagebits, 0, bytesPerLine);
+
+ // Copy from managed to dest
+ Marshal.Copy(imagebits, 0, (IntPtr)((int)bits.Scan0 + bits.Stride * (bmi.biHeight - 1 - y)), imagebits.Length);
+ }
+
+ bmp.UnlockBits(bits);
+
+ return bmp;
+ }
+
+ internal static byte[] ImageToDIB(Image image) {
+ MemoryStream ms;
+ byte[] buffer;
+ byte[] retbuf;
+
+ ms = new MemoryStream();
+ image.Save(ms, ImageFormat.Bmp);
+ buffer = ms.GetBuffer();
+
+ // Filter out the file header
+ retbuf = new byte[buffer.Length];
+ Array.Copy(buffer, 14, retbuf, 0, buffer.Length - 14);
+ return retbuf;
+ }
+
+ internal static IntPtr DupGlobalMem(IntPtr mem) {
+ IntPtr dup;
+ IntPtr dup_ptr;
+ IntPtr mem_ptr;
+ uint len;
+
+ len = Win32GlobalSize(mem);
+ mem_ptr = Win32GlobalLock(mem);
+
+ dup = Win32GlobalAlloc(GAllocFlags.GMEM_MOVEABLE, (int)len);
+ dup_ptr = Win32GlobalLock(dup);
+
+ Win32CopyMemory(dup_ptr, mem_ptr, (int)len);
+
+ Win32GlobalUnlock(mem);
+ Win32GlobalUnlock(dup);
+
+ return dup;
+ }
+
+ private int GetSystemParametersInfoInt (SPIAction spi)
+ {
+ int value = 0;
+
+ Win32SystemParametersInfo (spi, 0, ref value, 0);
+
+ return value;
+ }
+
+ private bool GetSystemParametersInfoBool (SPIAction spi)
+ {
+ bool value = false;
+
+ Win32SystemParametersInfo (spi, 0, ref value, 0);
+
+ return value;
+ }
+ #endregion // Private Support Methods
+
+ #region Static Properties
+ internal override int ActiveWindowTrackingDelay {
+ get { return GetSystemParametersInfoInt (SPIAction.SPI_GETACTIVEWNDTRKTIMEOUT); }
+ }
+
+ internal override int CaretWidth {
+ get {
+ // Supported on 2k, XP, 2k3 +
+ if (Environment.OSVersion.Version.Major < 5)
+ throw new NotSupportedException ();
+
+ return GetSystemParametersInfoInt (SPIAction.SPI_GETCARETWIDTH);
+ }
+ }
+
+ internal override int FontSmoothingContrast {
+ get {
+ // Supported on XP, 2k3 +
+ if (Environment.OSVersion.Version.Major < 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0))
+ throw new NotSupportedException ();
+
+ return GetSystemParametersInfoInt (SPIAction.SPI_GETFONTSMOOTHINGCONTRAST);
+ }
+ }
+
+ internal override int FontSmoothingType {
+ get {
+ // Supported on XP, 2k3 +
+ if (Environment.OSVersion.Version.Major < 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0))
+ throw new NotSupportedException ();
+
+ return GetSystemParametersInfoInt (SPIAction.SPI_GETFONTSMOOTHINGTYPE);
+ }
+ }
+
+ internal override int HorizontalResizeBorderThickness {
+ get { return Win32GetSystemMetrics (SystemMetrics.SM_CXSIZEFRAME); }
+ }
+
+ internal override bool IsActiveWindowTrackingEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETACTIVEWINDOWTRACKING); }
+ }
+
+ internal override bool IsComboBoxAnimationEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETCOMBOBOXANIMATION); }
+ }
+
+ internal override bool IsDropShadowEnabled {
+ get {
+ // Supported on XP, 2k3 +
+ if (Environment.OSVersion.Version.Major < 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0))
+ throw new NotSupportedException ();
+
+ return GetSystemParametersInfoBool (SPIAction.SPI_GETDROPSHADOW);
+ }
+ }
+
+ internal override bool IsFontSmoothingEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETFONTSMOOTHING); }
+ }
+
+ internal override bool IsHotTrackingEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETHOTTRACKING); }
+ }
+
+ internal override bool IsIconTitleWrappingEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETICONTITLEWRAP); }
+ }
+
+ internal override bool IsKeyboardPreferred {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETKEYBOARDPREF); }
+ }
+
+ internal override bool IsListBoxSmoothScrollingEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETLISTBOXSMOOTHSCROLLING); }
+ }
+
+ internal override bool IsMenuAnimationEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETMENUANIMATION); }
+ }
+
+ internal override bool IsMenuFadeEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETMENUFADE); }
+ }
+
+ internal override bool IsMinimizeRestoreAnimationEnabled {
+ get {
+ ANIMATIONINFO ai = new ANIMATIONINFO ();
+ ai.cbSize = (uint)Marshal.SizeOf (ai);
+
+ Win32SystemParametersInfo (SPIAction.SPI_GETANIMATION, 0, ref ai, 0);
+ return ai.iMinAnimate == 0 ? false : true;
+ }
+ }
+
+ internal override bool IsSelectionFadeEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETSELECTIONFADE); }
+ }
+
+ internal override bool IsSnapToDefaultEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETSNAPTODEFBUTTON); }
+ }
+
+ internal override bool IsTitleBarGradientEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETGRADIENTCAPTIONS); }
+ }
+
+ internal override bool IsToolTipAnimationEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETTOOLTIPANIMATION); }
+ }
+
+ internal override Size MenuBarButtonSize {
+ get {
+ return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXMENUSIZE),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYMENUSIZE));
+ }
+ }
+
+ public override Size MenuButtonSize {
+ get {
+ return new Size (
+ Win32GetSystemMetrics (SystemMetrics.SM_CXMENUSIZE),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYMENUSIZE));
+ }
+ }
+
+ internal override int MenuShowDelay {
+ get { return GetSystemParametersInfoInt (SPIAction.SPI_GETMENUSHOWDELAY); }
+ }
+
+ internal override int MouseSpeed {
+ get { return GetSystemParametersInfoInt (SPIAction.SPI_GETMOUSESPEED); }
+ }
+
+ internal override LeftRightAlignment PopupMenuAlignment {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETMENUDROPALIGNMENT) == true ? LeftRightAlignment.Left : LeftRightAlignment.Right; }
+ }
+
+ internal override PowerStatus PowerStatus {
+ get {
+ SYSTEMPOWERSTATUS p = new SYSTEMPOWERSTATUS ();
+
+ Win32GetSystemPowerStatus (p);
+
+ PowerStatus ps = new PowerStatus ((BatteryChargeStatus)p._BatteryFlag, p._BatteryFullLifeTime, (float)p._BatteryLifePercent / 255f, p._BatteryLifeTime, (PowerLineStatus)p._ACLineStatus);
+
+ return ps;
+ }
+ }
+
+ internal override int SizingBorderWidth {
+ get { return Win32GetSystemMetrics (SystemMetrics.SM_CXSIZEFRAME); }
+ }
+
+ internal override Size SmallCaptionButtonSize {
+ get {
+ return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXSMSIZE),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYSMSIZE));
+ }
+ }
+
+ internal override bool UIEffectsEnabled {
+ get { return GetSystemParametersInfoBool (SPIAction.SPI_GETUIEFFECTS); }
+ }
+
+ internal override int VerticalResizeBorderThickness {
+ get { return Win32GetSystemMetrics (SystemMetrics.SM_CYSIZEFRAME); }
+ }
+
+ internal override void RaiseIdle (EventArgs e)
+ {
+ if (Idle != null)
+ Idle (this, e);
+ }
+
+ internal override Keys ModifierKeys {
+ get {
+ short state;
+ Keys key_state;
+
+ key_state = Keys.None;
+
+ state = Win32GetKeyState(VirtualKeys.VK_SHIFT);
+ if ((state & 0x8000) != 0) {
+ key_state |= Keys.Shift;
+ }
+ state = Win32GetKeyState(VirtualKeys.VK_CONTROL);
+ if ((state & 0x8000) != 0) {
+ key_state |= Keys.Widget;
+ }
+
+ state = Win32GetKeyState(VirtualKeys.VK_MENU);
+ if ((state & 0x8000) != 0) {
+ key_state |= Keys.Alt;
+ }
+
+ return key_state;
+ }
+ }
+
+ internal override MouseButtons MouseButtons {
+ get {
+ return mouse_state;
+ }
+ }
+
+ internal override Point MousePosition {
+ get {
+ return mouse_position;
+ }
+ }
+
+ internal override Size MouseHoverSize {
+ get {
+ int width = 4;
+ int height = 4;
+
+ Win32SystemParametersInfo(SPIAction.SPI_GETMOUSEHOVERWIDTH, 0, ref width, 0);
+ Win32SystemParametersInfo(SPIAction.SPI_GETMOUSEHOVERWIDTH, 0, ref height, 0);
+ return new Size(width, height);
+ }
+ }
+
+ internal override int MouseHoverTime {
+ get {
+ int time = 500;
+
+ Win32SystemParametersInfo(SPIAction.SPI_GETMOUSEHOVERTIME, 0, ref time, 0);
+ return time;
+ }
+ }
+
+ internal override int MouseWheelScrollDelta {
+ get {
+ int delta = 120;
+ Win32SystemParametersInfo(SPIAction.SPI_GETWHEELSCROLLLINES, 0, ref delta, 0);
+ return delta;
+ }
+ }
+
+ internal override int HorizontalScrollBarHeight {
+ get {
+ return scroll_height;
+ }
+ }
+
+ internal override bool UserClipWontExposeParent {
+ get {
+ return false;
+ }
+ }
+
+
+ internal override int VerticalScrollBarWidth {
+ get {
+ return scroll_width;
+ }
+ }
+
+ internal override int MenuHeight {
+ get {
+ return Win32GetSystemMetrics(SystemMetrics.SM_CYMENU);
+ }
+ }
+
+ internal override Size Border3DSize {
+ get {
+ return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXEDGE),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYEDGE));
+ }
+ }
+
+ internal override Size BorderSize {
+ get {
+ return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXBORDER),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYBORDER));
+ }
+ }
+
+ internal override bool DropTarget {
+ get {
+ return false;
+ }
+
+ set {
+ if (value) {
+ //throw new NotImplementedException("Need to figure out D'n'D for Win32");
+ }
+ }
+ }
+
+ internal override Size CaptionButtonSize {
+ get {
+ return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXSIZE),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYSIZE));
+ }
+ }
+
+ internal override int CaptionHeight {
+ get {
+ return Win32GetSystemMetrics(SystemMetrics.SM_CYCAPTION);
+ }
+ }
+
+ internal override Size CursorSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CYCURSOR));
+ }
+ }
+
+ internal override bool DragFullWindows {
+ get {
+ int full = 0;
+ Win32SystemParametersInfo (SPIAction.SPI_GETDRAGFULLWINDOWS, 0, ref full, 0);
+ return (full != 0);
+ }
+ }
+
+ internal override Size DragSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXDRAG), Win32GetSystemMetrics(SystemMetrics.SM_CYDRAG));
+ }
+ }
+
+ internal override Size DoubleClickSize {
+ get {
+ return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXDOUBLECLK),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYDOUBLECLK));
+ }
+ }
+
+ internal override int DoubleClickTime {
+ get {
+ return Win32GetDoubleClickTime ();
+ }
+ }
+
+ internal override Size FixedFrameBorderSize {
+ get {
+ return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXFIXEDFRAME),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYFIXEDFRAME));
+ }
+ }
+
+ internal override Size FrameBorderSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXFRAME), Win32GetSystemMetrics(SystemMetrics.SM_CYFRAME));
+ }
+ }
+
+ internal override Size IconSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXICON), Win32GetSystemMetrics(SystemMetrics.SM_CYICON));
+ }
+ }
+
+ internal override Size MaxWindowTrackSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMAXTRACK), Win32GetSystemMetrics(SystemMetrics.SM_CYMAXTRACK));
+ }
+ }
+
+ internal override bool MenuAccessKeysUnderlined {
+ get {
+ int underlined = 0;
+ Win32SystemParametersInfo (SPIAction.SPI_GETKEYBOARDCUES, 0, ref underlined, 0);
+ return (underlined != 0);
+ }
+ }
+
+ internal override Size MinimizedWindowSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMINIMIZED), Win32GetSystemMetrics(SystemMetrics.SM_CYMINIMIZED));
+ }
+ }
+
+ internal override Size MinimizedWindowSpacingSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMINSPACING), Win32GetSystemMetrics(SystemMetrics.SM_CYMINSPACING));
+ }
+ }
+
+ internal override Size MinimumWindowSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMIN), Win32GetSystemMetrics(SystemMetrics.SM_CYMIN));
+ }
+ }
+
+ internal override Size MinWindowTrackSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMINTRACK), Win32GetSystemMetrics(SystemMetrics.SM_CYMINTRACK));
+ }
+ }
+
+ internal override Size SmallIconSize {
+ get {
+ return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXSMICON), Win32GetSystemMetrics(SystemMetrics.SM_CYSMICON));
+ }
+ }
+
+ internal override int MouseButtonCount {
+ get {
+ return Win32GetSystemMetrics(SystemMetrics.SM_CMOUSEBUTTONS);
+ }
+ }
+
+ internal override bool MouseButtonsSwapped {
+ get {
+ return Win32GetSystemMetrics(SystemMetrics.SM_SWAPBUTTON) != 0;
+ }
+ }
+
+ internal override bool MouseWheelPresent {
+ get {
+ return Win32GetSystemMetrics(SystemMetrics.SM_MOUSEWHEELPRESENT) != 0;
+ }
+ }
+
+ internal override Rectangle VirtualScreen {
+ get {
+ return new Rectangle( Win32GetSystemMetrics(SystemMetrics.SM_XVIRTUALSCREEN), Win32GetSystemMetrics(SystemMetrics.SM_YVIRTUALSCREEN),
+ Win32GetSystemMetrics(SystemMetrics.SM_CXVIRTUALSCREEN), Win32GetSystemMetrics(SystemMetrics.SM_CYVIRTUALSCREEN));
+ }
+ }
+
+ internal override Rectangle WorkingArea {
+ get {
+ RECT rect;
+
+ rect = new RECT();
+ Win32SystemParametersInfo(SPIAction.SPI_GETWORKAREA, 0, ref rect, 0);
+ return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ //return new Rectangle(0, 0, Win32GetSystemMetrics(SystemMetrics.SM.SM_CXSCREEN), Win32GetSystemMetrics(SystemMetrics.SM_CYSCREEN));
+ }
+ }
+
+ [MonoTODO]
+ internal override Screen[] AllScreens {
+ get {
+ // To support multiples, we need to use GetMonitorInfo API on Win32
+ return null;
+ }
+ }
+
+ internal override bool ThemesEnabled {
+ get {
+ return XplatUIWin32.themes_enabled;
+ }
+ }
+
+ internal override bool RequiresPositiveClientAreaSize {
+ get {
+ return false;
+ }
+ }
+
+ public override int ToolWindowCaptionHeight {
+ get {
+ return Win32GetSystemMetrics (SystemMetrics.SM_CYSMCAPTION);
+ }
+ }
+
+ public override Size ToolWindowCaptionButtonSize {
+ get {
+ return new Size (
+ Win32GetSystemMetrics (SystemMetrics.SM_CXSMSIZE),
+ Win32GetSystemMetrics (SystemMetrics.SM_CYSMSIZE));
+ }
+ }
+ #endregion // Static Properties
+
+ #region Singleton Specific Code
+ public static XplatUIWin32 GetInstance() {
+ if (instance==null) {
+ instance=new XplatUIWin32();
+ }
+ ref_count++;
+ return instance;
+ }
+
+ public int Reference {
+ get {
+ return ref_count;
+ }
+ }
+ #endregion
+
+ #region Public Static Methods
+ internal override IntPtr InitializeDriver() {
+ return IntPtr.Zero;
+ }
+
+ internal override void ShutdownDriver(IntPtr token) {
+ Console.WriteLine("XplatUIWin32 ShutdownDriver called");
+ }
+
+
+ internal void Version() {
+ Console.WriteLine("Xplat version $revision: $");
+ }
+
+ string GetSoundAlias (AlertType alert)
+ {
+ switch (alert) {
+ case AlertType.Error:
+ return "SystemHand";
+ case AlertType.Question:
+ return "SystemQuestion";
+ case AlertType.Warning:
+ return "SystemExclamation";
+ case AlertType.Information:
+ return "SystemAsterisk";
+ default:
+ return "SystemDefault";
+ }
+ }
+
+ internal override void AudibleAlert(AlertType alert) {
+ Win32PlaySound(GetSoundAlias (alert), IntPtr.Zero, SndFlags.SND_ALIAS_ID | SndFlags.SND_ASYNC | SndFlags.SND_NOSTOP | SndFlags.SND_NOWAIT);
+ }
+
+ internal override void BeginMoveResize (IntPtr handle) {
+ }
+
+ internal override void GetDisplaySize(out Size size) {
+ RECT rect;
+
+ Win32GetWindowRect(Win32GetDesktopWindow(), out rect);
+
+ size = new Size(rect.right - rect.left, rect.bottom - rect.top);
+ }
+
+ internal override void EnableThemes() {
+ themes_enabled=true;
+ }
+
+ internal override IntPtr CreateWindow(CreateParams cp) {
+ IntPtr WindowHandle;
+ IntPtr ParentHandle;
+ Hwnd hwnd;
+
+ hwnd = new Hwnd();
+
+ ParentHandle=cp.Parent;
+
+ if ((ParentHandle==IntPtr.Zero) && (cp.Style & (int)(WindowStyles.WS_CHILD))!=0) {
+ // We need to use our foster parent window until this poor child gets it's parent assigned
+ ParentHandle = GetFosterParent();
+ }
+
+ if ( ((cp.Style & (int)(WindowStyles.WS_CHILD | WindowStyles.WS_POPUP))==0) && ((cp.ExStyle & (int)WindowExStyles.WS_EX_APPWINDOW) == 0)) {
+ // If we want to be hidden from the taskbar we need to be 'owned' by
+ // something not on the taskbar. FosterParent is just that
+ ParentHandle = GetFosterParent();
+ }
+
+ Point location;
+ if (cp.HasWindowManager) {
+ location = Hwnd.GetNextStackedFormLocation (cp, Hwnd.ObjectFromHandle (cp.Parent));
+ } else {
+ location = new Point (cp.X, cp.Y);
+ }
+
+ string class_name = RegisterWindowClass (cp.ClassStyle);
+ HwndCreating = hwnd;
+
+ // We cannot actually send the WS_EX_MDICHILD flag to Windows because we
+ // are faking MDI, not uses Windows' version.
+ if ((cp.WindowExStyle & WindowExStyles.WS_EX_MDICHILD) == WindowExStyles.WS_EX_MDICHILD)
+ cp.WindowExStyle ^= WindowExStyles.WS_EX_MDICHILD;
+
+ WindowHandle = Win32CreateWindow (cp.WindowExStyle, class_name, cp.Caption, cp.WindowStyle, location.X, location.Y, cp.Width, cp.Height, ParentHandle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+
+ HwndCreating = null;
+
+ if (WindowHandle==IntPtr.Zero) {
+ int error = Marshal.GetLastWin32Error ();
+
+ Win32MessageBox(IntPtr.Zero, "Error : " + error.ToString(), "Failed to create window, class '"+cp.ClassName+"'", 0);
+ }
+
+ hwnd.ClientWindow = WindowHandle;
+ hwnd.Mapped = true;
+ Win32SetWindowLong(WindowHandle, WindowLong.GWL_USERDATA, (uint)ThemeEngine.Current.DefaultControlBackColor.ToArgb());
+
+ return WindowHandle;
+ }
+
+ 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 void DestroyWindow(IntPtr handle) {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ Win32DestroyWindow(handle);
+ hwnd.Dispose();
+ return;
+ }
+
+ internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
+ // We do nothing, Form has to handle WM_GETMINMAXINFO
+ }
+
+
+ internal override FormWindowState GetWindowState(IntPtr handle) {
+ uint style;
+
+ style = Win32GetWindowLong(handle, WindowLong.GWL_STYLE);
+ if ((style & (uint)WindowStyles.WS_MAXIMIZE) != 0) {
+ return FormWindowState.Maximized;
+ } else if ((style & (uint)WindowStyles.WS_MINIMIZE) != 0) {
+ return FormWindowState.Minimized;
+ }
+ return FormWindowState.Normal;
+ }
+
+ internal override void SetWindowState(IntPtr hwnd, FormWindowState state) {
+ switch(state) {
+ case FormWindowState.Normal: {
+ Win32ShowWindow(hwnd, WindowPlacementFlags.SW_RESTORE);
+ return;
+ }
+
+ case FormWindowState.Minimized: {
+ Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MINIMIZE);
+ return;
+ }
+
+ case FormWindowState.Maximized: {
+ Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MAXIMIZE);
+ return;
+ }
+ }
+ }
+
+ internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
+
+ Win32SetWindowLong(handle, WindowLong.GWL_STYLE, (uint)cp.Style);
+ Win32SetWindowLong(handle, WindowLong.GWL_EXSTYLE, (uint)cp.ExStyle);
+
+ // From MSDN:
+ // Certain window data is cached, so changes you make using SetWindowLong
+ // will not take effect until you call the SetWindowPos function. Specifically,
+ // if you change any of the frame styles, you must call SetWindowPos with
+ // the SWP_FRAMECHANGED flag for the cache to be updated properly.
+ if (cp.control is Form)
+ XplatUI.RequestNCRecalc (handle);
+ }
+
+ 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);
+ COLORREF clrRef = new COLORREF();
+ if (key != Color.Empty) {
+ clrRef.R = key.R;
+ clrRef.G = key.G;
+ clrRef.B = key.B;
+ lwa = (LayeredWindowAttributes)( (int)lwa | (int)LayeredWindowAttributes.LWA_COLORKEY );
+ }
+ RECT rc;
+ rc.right = 1000;
+ rc.bottom = 1000;
+ Win32SetLayeredWindowAttributes(handle, clrRef, opacity, lwa);
+ }
+
+ 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) {
+ Win32UpdateWindow(handle);
+ }
+
+ internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) {
+ IntPtr hdc;
+ PAINTSTRUCT ps;
+ PaintEventArgs paint_event;
+ RECT rect;
+ Rectangle clip_rect;
+ Hwnd hwnd;
+
+ clip_rect = new Rectangle();
+ rect = new RECT();
+ ps = new PAINTSTRUCT();
+
+ hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
+
+ if (client) {
+ if (Win32GetUpdateRect(msg.HWnd, ref rect, false)) {
+ if (handle != msg.HWnd) {
+ // We need to validate the window where the paint message
+ // was generated, otherwise we'll never stop getting paint
+ // messages.
+ Win32GetClientRect (msg.HWnd, out rect);
+ Win32ValidateRect (msg.HWnd, ref rect);
+ hdc = Win32GetDC (handle);
+ } else {
+ hdc = Win32BeginPaint (handle, ref ps);
+ rect = ps.rcPaint;
+ }
+ } else {
+ hdc = Win32GetDC(handle);
+ }
+ clip_rect = rect.ToRectangle ();
+ } else {
+ hdc = Win32GetWindowDC (handle);
+
+ // HACK this in for now
+ Win32GetWindowRect (handle, out rect);
+ clip_rect = new Rectangle (0, 0, rect.Width, rect.Height);
+ }
+
+ // If we called BeginPaint, store the PAINTSTRUCT,
+ // otherwise store hdc, so that PaintEventEnd can know
+ // whether to call EndPaint or ReleaseDC.
+ if (ps.hdc != IntPtr.Zero) {
+ hwnd.drawing_stack.Push (ps);
+ } else {
+ hwnd.drawing_stack.Push (hdc);
+ }
+
+ Graphics dc = Graphics.FromHdc(hdc);
+ hwnd.drawing_stack.Push (dc);
+
+ paint_event = new PaintEventArgs(dc, clip_rect);
+
+ return paint_event;
+ }
+
+ internal override void PaintEventEnd(ref Message m, IntPtr handle, bool client) {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(m.HWnd);
+
+ Graphics dc = (Graphics)hwnd.drawing_stack.Pop();
+ dc.Dispose ();
+
+ object o = hwnd.drawing_stack.Pop();
+ if (o is IntPtr) {
+ IntPtr hdc = (IntPtr) o;
+ Win32ReleaseDC (handle, hdc);
+ } else if (o is PAINTSTRUCT) {
+ PAINTSTRUCT ps = (PAINTSTRUCT) o;
+ Win32EndPaint (handle, ref ps);
+ }
+ }
+
+
+ internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
+ Win32MoveWindow(handle, x, y, width, height, true);
+ return;
+ }
+
+ 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) {
+ IntPtr parent;
+ RECT rect;
+ POINT pt;
+
+ Win32GetWindowRect(handle, out rect);
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+
+ pt.x=rect.left;
+ pt.y=rect.top;
+
+ parent = Win32GetAncestor (handle, AncestorType.GA_PARENT);
+ if (parent != IntPtr.Zero && parent != Win32GetDesktopWindow ())
+ Win32ScreenToClient(parent, ref pt);
+
+ x = pt.x;
+ y = pt.y;
+
+ Win32GetClientRect(handle, out rect);
+ client_width = rect.right - rect.left;
+ client_height = rect.bottom - rect.top;
+ return;
+ }
+
+ internal override void Activate(IntPtr handle) {
+ Win32SetActiveWindow(handle);
+ // delayed timer enabled
+ lock (timer_list) {
+ foreach (Timer t in timer_list.Values) {
+ if (t.Enabled && t.window == IntPtr.Zero) {
+ t.window = handle;
+ int id = t.GetHashCode ();
+ Win32SetTimer(handle, id, (uint)t.Interval, IntPtr.Zero);
+ }
+ }
+ }
+ }
+
+ internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
+ RECT rect;
+
+ rect.left=rc.Left;
+ rect.top=rc.Top;
+ rect.right=rc.Right;
+ rect.bottom=rc.Bottom;
+ 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);
+ }
+
+ private IntPtr InternalWndProc (IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam)
+ {
+ if (HwndCreating != null && HwndCreating.ClientWindow == IntPtr.Zero)
+ HwndCreating.ClientWindow = hWnd;
+ return NativeWindow.WndProc (hWnd, msg, wParam, lParam);
+ }
+
+ internal override IntPtr DefWndProc(ref Message msg) {
+ msg.Result=Win32DefWindowProc(msg.HWnd, (Msg)msg.Msg, msg.WParam, msg.LParam);
+ return msg.Result;
+ }
+
+ internal override void HandleException(Exception e) {
+ StackTrace st = new StackTrace(e);
+ Win32MessageBox(IntPtr.Zero, e.Message+st.ToString(), "Exception", 0);
+ Console.WriteLine("{0}{1}", e.Message, st.ToString());
+ }
+
+ internal override void DoEvents() {
+ MSG msg = new MSG();
+
+ while (GetMessage(ref msg, IntPtr.Zero, 0, 0, false)) {
+ Message m = Message.Create (msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
+
+ if (Application.FilterMessage (ref m))
+ continue;
+
+ XplatUI.TranslateMessage(ref msg);
+ XplatUI.DispatchMessage(ref msg);
+ }
+ }
+
+ internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
+ return Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, flags);
+ }
+
+ internal override void PostQuitMessage(int exitCode) {
+ 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 | SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE);
+ }
+
+ internal override void ResetMouseHover(IntPtr handle) {
+ TRACKMOUSEEVENT tme;
+
+ tme = new TRACKMOUSEEVENT();
+ tme.size = Marshal.SizeOf(tme);
+ tme.hWnd = handle;
+ tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER;
+ Win32TrackMouseEvent(ref tme);
+ }
+
+
+ internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax) {
+ return GetMessage(ref msg, hWnd, wFilterMin, wFilterMax, true);
+ }
+
+ private bool GetMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, bool blocking) {
+ bool result;
+
+ msg.refobject = 0;
+ if (RetrieveMessage(ref msg)) {
+ return true;
+ }
+
+ if (blocking) {
+ result = Win32GetMessage(ref msg, hWnd, wFilterMin, wFilterMax);
+ } else {
+ result = Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, (uint)PeekMessageFlags.PM_REMOVE);
+ if (!result) {
+ return false;
+ }
+ }
+
+ // We need to fake WM_MOUSE_ENTER
+ switch (msg.message) {
+ case Msg.WM_LBUTTONDOWN: {
+ mouse_state |= MouseButtons.Left;
+ break;
+ }
+
+ case Msg.WM_MBUTTONDOWN: {
+ mouse_state |= MouseButtons.Middle;
+ break;
+ }
+
+ case Msg.WM_RBUTTONDOWN: {
+ mouse_state |= MouseButtons.Right;
+ break;
+ }
+
+ case Msg.WM_LBUTTONUP: {
+ mouse_state &= ~MouseButtons.Left;
+ break;
+ }
+
+ case Msg.WM_MBUTTONUP: {
+ mouse_state &= ~MouseButtons.Middle;
+ break;
+ }
+
+ case Msg.WM_RBUTTONUP: {
+ mouse_state &= ~MouseButtons.Right;
+ break;
+ }
+
+ case Msg.WM_ASYNC_MESSAGE: {
+ XplatUIDriverSupport.ExecuteClientMessage((GCHandle)msg.lParam);
+ break;
+ }
+
+ case Msg.WM_MOUSEMOVE: {
+ if (msg.hwnd != prev_mouse_hwnd) {
+ TRACKMOUSEEVENT tme;
+
+ mouse_state = Widget.FromParamToMouseButtons ((int)msg.lParam.ToInt32());
+
+ // The current message will be sent out next time around
+ StoreMessage(ref msg);
+
+ // This is the message we want to send at this point
+ msg.message = Msg.WM_MOUSE_ENTER;
+
+ prev_mouse_hwnd = msg.hwnd;
+
+ tme = new TRACKMOUSEEVENT();
+ tme.size = Marshal.SizeOf(tme);
+ tme.hWnd = msg.hwnd;
+ tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER;
+ Win32TrackMouseEvent(ref tme);
+ return result;
+ }
+ break;
+ }
+
+ case Msg.WM_NCMOUSEMOVE: {
+ if (wm_nc_registered == null || !wm_nc_registered.Contains (msg.hwnd))
+ break;
+
+ mouse_state = Widget.FromParamToMouseButtons ((int)msg.lParam.ToInt32 ());
+
+ 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);
+ }
+
+ case Msg.WM_MOUSELEAVE: {
+ prev_mouse_hwnd = IntPtr.Zero;
+ break;
+ }
+
+ case Msg.WM_TIMER: {
+ Timer timer=(Timer)timer_list[(int)msg.wParam];
+
+ if (timer != null) {
+ timer.FireTick();
+ }
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ internal override bool TranslateMessage(ref MSG msg) {
+ return Win32TranslateMessage(ref msg);
+ }
+
+ internal override IntPtr DispatchMessage(ref MSG msg) {
+ return Win32DispatchMessage(ref msg);
+ }
+
+ internal override bool SetZOrder(IntPtr hWnd, IntPtr AfterhWnd, bool Top, bool Bottom) {
+ if (Top) {
+ Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOP, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ return true;
+ } else if (!Bottom) {
+ Win32SetWindowPos(hWnd, AfterhWnd, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ } else {
+ Win32SetWindowPos(hWnd, (IntPtr)SetWindowPosZOrder.HWND_BOTTOM, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ return true;
+ }
+ return false;
+ }
+
+ internal override bool SetTopmost(IntPtr hWnd, bool Enabled) {
+ if (Enabled) {
+ Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
+ return true;
+ } else {
+ Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_NOTOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
+ return true;
+ }
+ }
+
+ internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner) {
+ Win32SetWindowLong(hWnd, WindowLong.GWL_HWNDPARENT, (uint) hWndOwner);
+ return true;
+ }
+
+ internal override bool Text(IntPtr handle, string text) {
+ Win32SetWindowText(handle, text);
+ return true;
+ }
+
+ internal override bool GetText(IntPtr handle, out string text) {
+ StringBuilder sb;
+
+ sb = new StringBuilder(256);
+ Win32GetWindowText(handle, sb, sb.Capacity);
+ text = sb.ToString();
+ return true;
+ }
+
+ internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
+ {
+ if (visible) {
+ Widget c = Widget.FromHandle (handle);
+ if (c is Form) {
+ Form f;
+
+ f = (Form)Widget.FromHandle (handle);
+ WindowPlacementFlags flags = WindowPlacementFlags.SW_SHOWNORMAL;
+ switch (f.WindowState) {
+ case FormWindowState.Normal: flags = WindowPlacementFlags.SW_SHOWNORMAL; break;
+ case FormWindowState.Minimized: flags = WindowPlacementFlags.SW_MINIMIZE; break;
+ case FormWindowState.Maximized: flags = WindowPlacementFlags.SW_MAXIMIZE; break;
+ }
+
+ if (!f.ActivateOnShow)
+ flags = WindowPlacementFlags.SW_SHOWNOACTIVATE;
+
+ Win32ShowWindow (handle, flags);
+ }
+ else {
+ if (c.ActivateOnShow)
+ Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNORMAL);
+ else
+ Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNOACTIVATE);
+ }
+ }
+ else {
+ Win32ShowWindow (handle, WindowPlacementFlags.SW_HIDE);
+ }
+ return true;
+ }
+
+ internal override bool IsEnabled(IntPtr handle) {
+ return IsWindowEnabled (handle);
+ }
+
+ internal override bool IsKeyLocked (VirtualKeys key)
+ {
+ return (Win32GetKeyState (key) & 1) == 1;
+ }
+
+ internal override bool IsVisible(IntPtr handle) {
+ return IsWindowVisible (handle);
+ }
+
+ internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
+ Widget c = Widget.FromHandle (handle);
+ if (parent == IntPtr.Zero) {
+ if (!(c is Form)) {
+ Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE);
+ }
+ } else {
+ if (!(c is Form)) {
+ SetVisible (handle, c.is_visible, true);
+ }
+ }
+ // The Win32SetParent is lame, it can very well move the window
+ // ref: http://groups.google.com/group/microsoft.public.vb.winapi/browse_thread/thread/1b82ccc54231ecee/afa82835bfc0422a%23afa82835bfc0422a
+ // Here we save the position before changing the parent, and if it has changed afterwards restore it.
+ // Another possibility would be to intercept WM_WINDOWPOSCHANGING and restore the coords there, but this would require plumbing in weird places
+ // (either inside Widget or add handling to InternalWndProc)
+ // We also need to remove WS_CHILD if making the window parent-less, and add it if we're parenting it.
+ RECT rect, rect2;
+ IntPtr result;
+ WindowStyles style, new_style;
+
+ Win32GetWindowRect (handle, out rect);
+ style = (WindowStyles) Win32GetWindowLong (handle, WindowLong.GWL_STYLE);
+
+ if (parent == IntPtr.Zero) {
+ new_style = style & ~WindowStyles.WS_CHILD;
+ result = Win32SetParent (handle, GetFosterParent());
+ } else {
+ new_style = style | WindowStyles.WS_CHILD;
+ result = Win32SetParent (handle, parent);
+ }
+ if (style != new_style && c is Form) {
+ Win32SetWindowLong (handle, WindowLong.GWL_STYLE, (uint) new_style);
+ }
+ Win32GetWindowRect (handle, out rect2);
+ if (rect.top != rect2.top && rect.left != rect2.left && c is Form) {
+ Win32SetWindowPos (handle, IntPtr.Zero, rect.top, rect.left, rect.Width, rect.Height, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOENDSCHANGING | SetWindowPosFlags.SWP_NOACTIVATE);
+ }
+ return result;
+ }
+
+ // If we ever start using this, we should probably replace FosterParent with IntPtr.Zero
+ internal override IntPtr GetParent(IntPtr handle) {
+ return Win32GetParent(handle);
+ }
+
+ // This is a nop on win32 and x11
+ internal override IntPtr GetPreviousWindow(IntPtr handle) {
+ return handle;
+ }
+
+ internal override void GrabWindow(IntPtr hWnd, IntPtr ConfineToHwnd) {
+ grab_hwnd = hWnd;
+ Win32SetCapture(hWnd);
+
+ if (ConfineToHwnd != IntPtr.Zero) {
+ RECT window_rect;
+ Win32GetWindowRect (ConfineToHwnd, out window_rect);
+ Win32GetClipCursor (out clipped_cursor_rect);
+ Win32ClipCursor (ref window_rect);
+ }
+ }
+
+ internal override void GrabInfo(out IntPtr hWnd, out bool GrabConfined, out Rectangle GrabArea) {
+ hWnd = grab_hwnd;
+ GrabConfined = grab_confined;
+ GrabArea = grab_area;
+ }
+
+ internal override void UngrabWindow(IntPtr hWnd) {
+ if (!(clipped_cursor_rect.top == 0 && clipped_cursor_rect.bottom == 0 && clipped_cursor_rect.left == 0 && clipped_cursor_rect.right == 0)) {
+ Win32ClipCursor (ref clipped_cursor_rect);
+ clipped_cursor_rect = new RECT ();
+ }
+
+ Win32ReleaseCapture();
+ grab_hwnd = IntPtr.Zero;
+ }
+
+ internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) {
+ RECT rect;
+
+ rect.left=ClientRect.Left;
+ rect.top=ClientRect.Top;
+ rect.right=ClientRect.Right;
+ rect.bottom=ClientRect.Bottom;
+
+ if (!Win32AdjustWindowRectEx(ref rect, cp.Style, menu != null, cp.ExStyle)) {
+ WindowRect = new Rectangle(ClientRect.Left, ClientRect.Top, ClientRect.Width, ClientRect.Height);
+ return false;
+ }
+
+ WindowRect = new Rectangle(rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top);
+ return true;
+ }
+
+ internal override void SetCursor(IntPtr window, IntPtr cursor) {
+ Win32SetCursor(cursor);
+ return;
+ }
+
+ internal override void ShowCursor(bool show) {
+ Win32ShowCursor(show);
+ }
+
+ internal override void OverrideCursor(IntPtr cursor) {
+ Win32SetCursor(cursor);
+ }
+
+ internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
+ IntPtr cursor;
+ Bitmap cursor_bitmap;
+ Bitmap cursor_mask;
+ Byte[] cursor_bits;
+ Byte[] mask_bits;
+ Color pixel;
+ int width;
+ int height;
+
+ // Win32 only allows creation cursors of a certain size
+ if ((bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)) || (bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR))) {
+ cursor_bitmap = new Bitmap(bitmap, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)));
+ cursor_mask = new Bitmap(mask, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)));
+ } else {
+ cursor_bitmap = bitmap;
+ cursor_mask = mask;
+ }
+
+ width = cursor_bitmap.Width;
+ height = cursor_bitmap.Height;
+
+ cursor_bits = new Byte[(width / 8) * height];
+ mask_bits = new Byte[(width / 8) * height];
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ pixel = cursor_bitmap.GetPixel(x, y);
+
+ if (pixel == cursor_pixel) {
+ cursor_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8));
+ }
+
+ pixel = cursor_mask.GetPixel(x, y);
+
+ if (pixel == mask_pixel) {
+ mask_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8));
+ }
+ }
+ }
+
+ cursor = Win32CreateCursor(IntPtr.Zero, xHotSpot, yHotSpot, width, height, mask_bits, cursor_bits);
+
+ return cursor;
+ }
+
+ internal override Bitmap DefineStdCursorBitmap (StdCursor id)
+ {
+ // We load the cursor, create a bitmap, draw the cursor onto the bitmap and return the bitmap.
+ IntPtr cursor = DefineStdCursor (id);
+ // Windows only have one possible cursor size!
+ int width = Win32GetSystemMetrics (SystemMetrics.SM_CXCURSOR);
+ int height = Win32GetSystemMetrics (SystemMetrics.SM_CYCURSOR);
+ Bitmap bmp = new Bitmap (width, height);
+ Graphics gc = Graphics.FromImage (bmp);
+ IntPtr hdc = gc.GetHdc ();
+ Win32DrawIcon (hdc, 0, 0, cursor);
+ gc.ReleaseHdc (hdc);
+ gc.Dispose ();
+ return bmp;
+ }
+
+ [MonoTODO("Define the missing cursors")]
+ internal override IntPtr DefineStdCursor(StdCursor id) {
+ switch(id) {
+ case StdCursor.AppStarting: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_APPSTARTING);
+ case StdCursor.Arrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW);
+ case StdCursor.Cross: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_CROSS);
+ case StdCursor.Default: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW);
+ case StdCursor.Hand: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HAND);
+ case StdCursor.Help: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HELP);
+ case StdCursor.HSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.IBeam: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_IBEAM);
+ case StdCursor.No: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_NO);
+ case StdCursor.NoMove2D: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.NoMoveHoriz: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.NoMoveVert: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanEast: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanNE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanNorth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanNW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanSouth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanSW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.PanWest: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.SizeAll: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEALL);
+ case StdCursor.SizeNESW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENESW);
+ case StdCursor.SizeNS: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENS);
+ case StdCursor.SizeNWSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENWSE);
+ case StdCursor.SizeWE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEWE);
+ case StdCursor.UpArrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_UPARROW);
+ case StdCursor.VSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME
+ case StdCursor.WaitCursor: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_WAIT);
+ }
+ throw new NotImplementedException ();
+ }
+
+ internal override void DestroyCursor(IntPtr cursor) {
+ if ((cursor.ToInt32() < (int)LoadCursorType.First) || (cursor.ToInt32() > (int)LoadCursorType.Last)) {
+ Win32DestroyCursor(cursor);
+ }
+ }
+
+ [MonoTODO]
+ internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) {
+ ICONINFO ii = new ICONINFO ();
+
+ if (!Win32GetIconInfo (cursor, out ii))
+ throw new Win32Exception ();
+
+ width = 20;
+ height = 20;
+ hotspot_x = ii.xHotspot;
+ hotspot_y = ii.yHotspot;
+ }
+
+ internal override void SetCursorPos(IntPtr handle, int x, int y) {
+ Win32SetCursorPos(x, y);
+ }
+
+ internal override Region GetClipRegion(IntPtr hwnd) {
+ Region region;
+
+ region = new Region();
+
+ Win32GetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd)));
+
+ return region;
+ }
+
+ internal override void SetClipRegion(IntPtr hwnd, Region region) {
+ if (region == null)
+ Win32SetWindowRgn (hwnd, IntPtr.Zero, true);
+ else
+ Win32SetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd)), true);
+ }
+
+ internal override void EnableWindow(IntPtr handle, bool Enable) {
+ Win32EnableWindow(handle, Enable);
+ }
+
+ internal override void EndLoop(System.Threading.Thread thread) {
+ // Nothing to do
+ }
+
+ internal override object StartLoop(System.Threading.Thread thread) {
+ return null;
+ }
+
+ internal override void SetModal(IntPtr handle, bool Modal) {
+ // we do nothing on Win32
+ }
+
+ internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
+ POINT pt;
+
+ Win32GetCursorPos(out pt);
+
+ if (handle!=IntPtr.Zero) {
+ Win32ScreenToClient(handle, ref pt);
+ }
+
+ x=pt.x;
+ y=pt.y;
+ }
+
+ internal override void ScreenToClient(IntPtr handle, ref int x, ref int y)
+ {
+ POINT pnt = new POINT();
+
+ pnt.x = x;
+ pnt.y = y;
+ Win32ScreenToClient (handle, ref pnt);
+
+ x = pnt.x;
+ y = pnt.y;
+ }
+
+ internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) {
+ POINT pnt = new POINT();
+
+ pnt.x = x;
+ pnt.y = y;
+
+ Win32ClientToScreen(handle, ref pnt);
+
+ x = pnt.x;
+ y = pnt.y;
+ }
+
+ internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) {
+ RECT rect;
+
+ Win32GetWindowRect(handle, out rect);
+ x -= rect.left + SystemInformation.FrameBorderSize.Width;
+ y -= rect.top + SystemInformation.FrameBorderSize.Height;
+
+ WindowStyles style = (WindowStyles) Win32GetWindowLong (handle, WindowLong.GWL_STYLE);
+ if (CreateParams.IsSet (style, WindowStyles.WS_CAPTION)) {
+ y -= ThemeEngine.Current.CaptionHeight;
+ }
+ }
+
+ internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) {
+ RECT rect;
+
+ Win32GetWindowRect(handle, out rect);
+ x += rect.left + SystemInformation.FrameBorderSize.Width;
+ y += rect.top + SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight;
+ return;
+ }
+
+ internal override void SendAsyncMethod (AsyncMethodData method)
+ {
+ Win32PostMessage(GetFosterParent(), Msg.WM_ASYNC_MESSAGE, IntPtr.Zero, (IntPtr)GCHandle.Alloc (method));
+ }
+
+ internal override void SetTimer (Timer timer)
+ {
+ IntPtr FosterParent=GetFosterParent();
+ int index;
+
+ index = timer.GetHashCode();
+
+ lock (timer_list) {
+ timer_list[index]=timer;
+ }
+
+ if (Win32SetTimer(FosterParent, index, (uint)timer.Interval, IntPtr.Zero) != IntPtr.Zero)
+ timer.window = FosterParent;
+ else
+ timer.window = IntPtr.Zero;
+ }
+
+ internal override void KillTimer (Timer timer)
+ {
+ int index;
+
+ index = timer.GetHashCode();
+
+ Win32KillTimer(timer.window, index);
+
+ lock (timer_list) {
+ timer_list.Remove(index);
+ }
+ }
+
+ internal override void CreateCaret(IntPtr hwnd, int width, int height) {
+ Win32CreateCaret(hwnd, IntPtr.Zero, width, height);
+ caret_visible = false;
+ }
+
+ internal override void DestroyCaret(IntPtr hwnd) {
+ Win32DestroyCaret();
+ }
+
+ internal override void SetCaretPos(IntPtr hwnd, int x, int y) {
+ Win32SetCaretPos(x, y);
+ }
+
+ internal override void CaretVisible(IntPtr hwnd, bool visible) {
+ if (visible) {
+ if (!caret_visible) {
+ Win32ShowCaret(hwnd);
+ caret_visible = true;
+ }
+ } else {
+ if (caret_visible) {
+ Win32HideCaret(hwnd);
+ caret_visible = false;
+ }
+ }
+ }
+
+ internal override IntPtr GetFocus() {
+ return Win32GetFocus();
+ }
+
+ internal override void SetFocus(IntPtr hwnd) {
+ Win32SetFocus(hwnd);
+ }
+
+ internal override IntPtr GetActive() {
+ return Win32GetActiveWindow();
+ }
+
+ internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) {
+ IntPtr dc;
+ IntPtr prevobj;
+ TEXTMETRIC tm;
+
+ tm = new TEXTMETRIC();
+
+ dc = Win32GetDC (IntPtr.Zero);
+ prevobj = Win32SelectObject (dc, font.ToHfont ());
+
+ if (Win32GetTextMetrics (dc, ref tm) == false) {
+ prevobj = Win32SelectObject (dc, prevobj);
+ Win32DeleteObject (prevobj);
+ Win32ReleaseDC (IntPtr.Zero, dc);
+ ascent = 0;
+ descent = 0;
+ return false;
+ }
+ prevobj = Win32SelectObject (dc, prevobj);
+ Win32DeleteObject (prevobj);
+ Win32ReleaseDC (IntPtr.Zero, dc);
+
+ ascent = tm.tmAscent;
+ descent = tm.tmDescent;
+
+ return true;
+ }
+
+ internal override void ScrollWindow(IntPtr hwnd, Rectangle rectangle, int XAmount, int YAmount, bool with_children) {
+ RECT rect;
+
+ rect = new RECT();
+ rect.left = rectangle.X;
+ rect.top = rectangle.Y;
+ rect.right = rectangle.Right;
+ rect.bottom = rectangle.Bottom;
+
+ Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, ref rect, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE));
+ Win32UpdateWindow(hwnd);
+ }
+
+ internal override void ScrollWindow(IntPtr hwnd, int XAmount, int YAmount, bool with_children) {
+ Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE));
+ }
+
+ internal override bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt) {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uCallbackMessage = (uint)Msg.WM_USER;
+ nid.uFlags = NotifyIconFlags.NIF_MESSAGE;
+
+ if (tip != null) {
+ nid.szTip = tip;
+ nid.uFlags |= NotifyIconFlags.NIF_TIP;
+ }
+
+ if (icon != null) {
+ nid.hIcon = icon.Handle;
+ nid.uFlags |= NotifyIconFlags.NIF_ICON;
+ }
+
+ tt = null;
+
+ return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_ADD, ref nid);
+ }
+
+ internal override bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt) {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hIcon = icon.Handle;
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uCallbackMessage = (uint)Msg.WM_USER;
+ nid.uFlags = NotifyIconFlags.NIF_MESSAGE;
+
+ if (tip != null) {
+ nid.szTip = tip;
+ nid.uFlags |= NotifyIconFlags.NIF_TIP;
+ }
+
+ if (icon != null) {
+ nid.hIcon = icon.Handle;
+ nid.uFlags |= NotifyIconFlags.NIF_ICON;
+ }
+
+ return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid);
+ }
+
+ internal override void SystrayRemove(IntPtr hwnd, ref ToolTip tt) {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uFlags = 0;
+
+ Win32Shell_NotifyIcon(NotifyIconMessage.NIM_DELETE, ref nid);
+ }
+
+ internal override void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon)
+ {
+ NOTIFYICONDATA nid;
+
+ nid = new NOTIFYICONDATA();
+
+ nid.cbSize = (uint)Marshal.SizeOf(nid);
+ nid.hWnd = hwnd;
+ nid.uID = 1;
+ nid.uFlags = NotifyIconFlags.NIF_INFO;
+ nid.uTimeoutOrVersion = timeout;
+ nid.szInfoTitle = title;
+ nid.szInfo = text;
+ nid.dwInfoFlags = icon;
+
+ Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid);
+ }
+
+ internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
+ // Nothing to do on Win32
+ }
+
+ internal override void SetMenu(IntPtr handle, Menu menu) {
+ // Trigger WM_NCCALC
+ Win32SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE);
+ }
+
+ internal override Point GetMenuOrigin(IntPtr handle) {
+ Form form = Widget.FromHandle (handle) as Form;
+
+ if (form != null) {
+ if (form.FormBorderStyle == FormBorderStyle.None)
+ return Point.Empty;
+
+ int bordersize = (form.Width - form.ClientSize.Width) / 2;
+
+ if (form.FormBorderStyle == FormBorderStyle.FixedToolWindow || form.FormBorderStyle == FormBorderStyle.SizableToolWindow)
+ return new Point (bordersize, bordersize + SystemInformation.ToolWindowCaptionHeight);
+ else
+ return new Point (bordersize, bordersize + SystemInformation.CaptionHeight);
+ }
+
+ return new Point(SystemInformation.FrameBorderSize.Width, SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight);
+ }
+
+ internal override void SetIcon(IntPtr hwnd, Icon icon) {
+ Win32SendMessage(hwnd, Msg.WM_SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : icon.Handle); // 1 = large icon (0 would be small)
+ }
+
+ internal override void ClipboardClose(IntPtr handle) {
+ if (handle != clip_magic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+ Win32CloseClipboard();
+ }
+
+ internal override int ClipboardGetID(IntPtr handle, string format) {
+ if (handle != clip_magic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+ if (format == "Text" ) return 1;
+ else if (format == "Bitmap" ) return 2;
+ else if (format == "MetaFilePict" ) return 3;
+ else if (format == "SymbolicLink" ) return 4;
+ else if (format == "DataInterchangeFormat" ) return 5;
+ else if (format == "Tiff" ) return 6;
+ else if (format == "OEMText" ) return 7;
+ else if (format == "DeviceIndependentBitmap" ) return 8;
+ else if (format == "Palette" ) return 9;
+ else if (format == "PenData" ) return 10;
+ else if (format == "RiffAudio" ) return 11;
+ else if (format == "WaveAudio" ) return 12;
+ else if (format == "UnicodeText" ) return 13;
+ else if (format == "EnhancedMetafile" ) return 14;
+ else if (format == "FileDrop" ) return 15;
+ else if (format == "Locale" ) return 16;
+
+ return (int)Win32RegisterClipboardFormat(format);
+ }
+
+ internal override IntPtr ClipboardOpen(bool primary_selection) {
+ // Win32 does not have primary selection
+ Win32OpenClipboard(GetFosterParent());
+ return clip_magic;
+ }
+
+ internal override int[] ClipboardAvailableFormats(IntPtr handle) {
+ uint format;
+ int[] result;
+ int count;
+
+ if (handle != clip_magic) {
+ return null;
+ }
+
+ // Count first
+ count = 0;
+ format = 0;
+ do {
+ format = Win32EnumClipboardFormats(format);
+ if (format != 0) {
+ count++;
+ }
+ } while (format != 0);
+
+ // Now assign
+ result = new int[count];
+ count = 0;
+ format = 0;
+ do {
+ format = Win32EnumClipboardFormats(format);
+ if (format != 0) {
+ result[count++] = (int)format;
+ }
+ } while (format != 0);
+
+ return result;
+ }
+
+
+ internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) {
+ IntPtr hmem;
+ IntPtr data;
+ object obj;
+
+ if (handle != clip_magic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+
+ hmem = Win32GetClipboardData((uint)type);
+ if (hmem == IntPtr.Zero) {
+ return null;
+ }
+
+ data = Win32GlobalLock(hmem);
+ if (data == IntPtr.Zero) {
+ uint error = Win32GetLastError();
+ Console.WriteLine("Error: {0}", error);
+ return null;
+ }
+
+ obj = null;
+
+ if (type == DataFormats.GetFormat(DataFormats.Rtf).Id) {
+ obj = AnsiToString(data);
+ } else switch ((ClipboardFormats)type) {
+ case ClipboardFormats.CF_TEXT: {
+ obj = AnsiToString(data);
+ break;
+ }
+
+ case ClipboardFormats.CF_DIB: {
+ obj = DIBtoImage(data);
+ break;
+ }
+
+ case ClipboardFormats.CF_UNICODETEXT: {
+ obj = UnicodeToString(data);
+ break;
+ }
+
+ default: {
+ if (converter != null && !converter(type, data, out obj)) {
+ obj = null;
+ }
+ break;
+ }
+ }
+ Win32GlobalUnlock(hmem);
+
+ return obj;
+
+ }
+
+ internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy)
+ {
+ byte[] data = null;
+
+ if (handle != clip_magic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+
+ if (obj == null) {
+ // Just clear it
+ if (!Win32EmptyClipboard())
+ throw new ExternalException("Win32EmptyClipboard");
+ return;
+ }
+
+ if (type == -1) {
+ if (obj is string) {
+ type = (int)ClipboardFormats.CF_UNICODETEXT;
+ } else if (obj is Image) {
+ type = (int)ClipboardFormats.CF_DIB;
+ }
+ }
+
+ if (type == DataFormats.GetFormat(DataFormats.Rtf).Id) {
+ data = StringToAnsi ((string)obj);
+ } else switch((ClipboardFormats)type) {
+ case ClipboardFormats.CF_UNICODETEXT: {
+ data = StringToUnicode ((string)obj);
+ break;
+ }
+
+ case ClipboardFormats.CF_TEXT: {
+ data = StringToAnsi ((string)obj);
+ break;
+ }
+
+ case ClipboardFormats.CF_BITMAP:
+ case ClipboardFormats.CF_DIB: {
+ data = ImageToDIB ((Image)obj);
+ type = (int)ClipboardFormats.CF_DIB;
+ break;
+ }
+
+ default: {
+ if (converter != null && !converter(ref type, obj, out data)) {
+ data = null; // ensure that a failed conversion leaves null.
+ }
+ break;
+ }
+ }
+ if (data != null) {
+ SetClipboardData ((uint)type, data);
+ }
+ }
+
+ internal static byte[] StringToUnicode (string text)
+ {
+ return Encoding.Unicode.GetBytes (text + "\0");
+ }
+
+ internal static byte[] StringToAnsi (string text)
+ {
+ // FIXME, follow the behaviour of the previous code using UTF-8,
+ // but this should be 'ANSI' on Windows, i.e. the current code page.
+ // Does Encoding.Default work on Windows?
+ return Encoding.UTF8.GetBytes (text + "\0");
+ }
+
+ private void SetClipboardData (uint type, byte[] data)
+ {
+ if (data.Length == 0)
+ // Shouldn't call Win32SetClipboard with NULL, as, from MSDN:
+ // "This parameter can be NULL, indicating that the window provides data
+ // in the specified clipboard format (renders the format) upon request."
+ // and I don't think we support that...
+ // Note this is unrelated to the fact that passing a null obj to
+ // ClipboardStore is actually a request to empty the clipboard!
+ return;
+ IntPtr hmem = CopyToMoveableMemory (data);
+ if (hmem == IntPtr.Zero)
+ // As above, should not call with null.
+ // (Not that CopyToMoveableMemory should ever return null!)
+ throw new ExternalException ("CopyToMoveableMemory failed.");
+ if (Win32SetClipboardData (type, hmem) == IntPtr.Zero)
+ throw new ExternalException ("Win32SetClipboardData");
+ }
+
+ /// <summary>
+ /// Creates a memory block with GlobalAlloc(GMEM_MOVEABLE), copies the data
+ /// into it, and returns the handle to the memory.
+ /// </summary>
+ /// -
+ /// <param name="data">The data. Must not be null or zero-length &#x2014;
+ /// see the exception notes.</param>
+ /// -
+ /// <returns>The *handle* to the allocated GMEM_MOVEABLE block.</returns>
+ /// -
+ /// <exception cref="T:System.ArgumentException">The data was null or zero
+ /// length. This is disallowed since a zero length allocation can't be made
+ /// </exception>
+ /// <exception cref="T:System.ComponentModel.Win32Exception">The allocation,
+ /// or locking (handle->pointer) failed.
+ /// Either out of memory or the handle table is full (256 max currently).
+ /// Note Win32Exception is a subclass of ExternalException so this is OK in
+ /// the documented Clipboard interface.
+ /// </exception>
+ internal static IntPtr CopyToMoveableMemory (byte[] data)
+ {
+ if (data == null || data.Length == 0)
+ // detect this before GlobalAlloc does.
+ throw new ArgumentException ("Can't create a zero length memory block.");
+
+ IntPtr hmem = Win32GlobalAlloc (GAllocFlags.GMEM_MOVEABLE | GAllocFlags.GMEM_DDESHARE, data.Length);
+ if (hmem == IntPtr.Zero)
+ throw new Win32Exception ();
+ IntPtr hmem_ptr = Win32GlobalLock (hmem);
+ if (hmem_ptr == IntPtr.Zero) // If the allocation was valid this shouldn't occur.
+ throw new Win32Exception ();
+ Marshal.Copy (data, 0, hmem_ptr, data.Length);
+ Win32GlobalUnlock (hmem);
+ return hmem;
+ }
+
+
+ internal override void SetAllowDrop(IntPtr hwnd, bool allowed) {
+ if (allowed) {
+ Win32DnD.RegisterDropTarget(hwnd);
+ } else {
+ Win32DnD.UnregisterDropTarget(hwnd);
+ }
+ }
+
+ internal override DragDropEffects StartDrag(IntPtr hwnd, object data, DragDropEffects allowedEffects) {
+ return Win32DnD.StartDrag(hwnd, data, allowedEffects);
+ }
+
+ // XXX this doesn't work at all for FrameStyle.Dashed - it draws like Thick, and in the Thick case
+ // the corners are drawn incorrectly.
+ internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) {
+ IntPtr hdc;
+ IntPtr pen;
+ IntPtr oldpen;
+ COLORREF clrRef = new COLORREF();
+
+ // If we want the standard hatch pattern we would
+ // need to create a brush
+
+ clrRef.R = backColor.R;
+ clrRef.G = backColor.G;
+ clrRef.B = backColor.B;
+
+ // Grab a pen
+ pen = Win32CreatePen (style == FrameStyle.Thick ? PenStyle.PS_SOLID : PenStyle.PS_DASH,
+ style == FrameStyle.Thick ? 4 : 2, ref clrRef);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ Win32SetROP2(hdc, ROP2DrawMode.R2_NOT);
+ oldpen = Win32SelectObject(hdc, pen);
+
+ Win32MoveToEx(hdc, rectangle.Left, rectangle.Top, IntPtr.Zero);
+ if ((rectangle.Width > 0) && (rectangle.Height > 0)) {
+ Win32LineTo(hdc, rectangle.Right, rectangle.Top);
+ Win32LineTo(hdc, rectangle.Right, rectangle.Bottom);
+ Win32LineTo(hdc, rectangle.Left, rectangle.Bottom);
+ Win32LineTo(hdc, rectangle.Left, rectangle.Top);
+ } else {
+ if (rectangle.Width > 0) {
+ Win32LineTo(hdc, rectangle.Right, rectangle.Top);
+ } else {
+ Win32LineTo(hdc, rectangle.Left, rectangle.Bottom);
+ }
+ }
+
+ Win32SelectObject(hdc, oldpen);
+ Win32DeleteObject(pen);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ internal override void DrawReversibleLine(Point start, Point end, Color backColor) {
+ IntPtr hdc;
+ IntPtr pen;
+ IntPtr oldpen;
+ POINT pt;
+ COLORREF clrRef = new COLORREF();
+
+ pt = new POINT();
+ pt.x = 0;
+ pt.y = 0;
+ Win32ClientToScreen(IntPtr.Zero, ref pt);
+
+ // If we want the standard hatch pattern we would
+ // need to create a brush
+
+ clrRef.R = backColor.R;
+ clrRef.G = backColor.G;
+ clrRef.B = backColor.B;
+
+ // Grab a pen
+ pen = Win32CreatePen(PenStyle.PS_SOLID, 1, ref clrRef);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ Win32SetROP2(hdc, ROP2DrawMode.R2_NOT);
+ oldpen = Win32SelectObject(hdc, pen);
+
+ Win32MoveToEx(hdc, pt.x + start.X, pt.y + start.Y, IntPtr.Zero);
+ Win32LineTo(hdc, pt.x + end.X, pt.y + end.Y);
+
+ Win32SelectObject(hdc, oldpen);
+ Win32DeleteObject(pen);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
+ {
+ RECT rect;
+
+ rect = new RECT();
+ rect.left = rectangle.Left;
+ rect.top = rectangle.Top;
+ rect.right = rectangle.Right;
+ rect.bottom = rectangle.Bottom;
+
+ IntPtr hdc;
+ IntPtr brush;
+ IntPtr oldbrush;
+ COLORREF clrRef = new COLORREF();
+
+ clrRef.R = backColor.R;
+ clrRef.G = backColor.G;
+ clrRef.B = backColor.B;
+
+ // Grab a brush
+ brush = Win32CreateSolidBrush (clrRef);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ oldbrush = Win32SelectObject(hdc, brush);
+
+ Win32PatBlt (hdc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, PatBltRop.DSTINVERT);
+
+ Win32SelectObject(hdc, oldbrush);
+ Win32DeleteObject(brush);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) {
+ IntPtr hdc;
+ IntPtr pen;
+ IntPtr oldpen;
+ POINT pt;
+
+ pt = new POINT();
+ pt.x = 0;
+ pt.y = 0;
+ Win32ClientToScreen(handle, ref pt);
+
+ // If we want the standard hatch pattern we would
+ // need to create a brush
+
+ // Grab a pen
+ pen = Win32CreatePen(PenStyle.PS_SOLID, line_width, IntPtr.Zero);
+
+ hdc = Win32GetDC(IntPtr.Zero);
+ Win32SetROP2(hdc, ROP2DrawMode.R2_NOT);
+ oldpen = Win32SelectObject(hdc, pen);
+
+ Widget c = Widget.FromHandle (handle);
+ if (c != null) {
+ RECT window_rect;
+ Win32GetWindowRect (c.Handle, out window_rect);
+ Region r = new Region (new Rectangle(window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top));
+ 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)) {
+ Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top);
+ Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Bottom);
+ Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom);
+ Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Top);
+ } else {
+ if (rect.Width > 0) {
+ Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top);
+ } else {
+ Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom);
+ }
+ }
+
+ Win32SelectObject(hdc, oldpen);
+ Win32DeleteObject(pen);
+ if (c != null)
+ Win32ExtSelectClipRgn(hdc, IntPtr.Zero, (int) ClipCombineMode.RGN_COPY);
+
+ Win32ReleaseDC(IntPtr.Zero, hdc);
+ }
+
+ 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.FromHwnd(GetFosterParent());
+
+ width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
+ return new SizeF(width, font.Height);
+ }
+
+ internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) {
+ return Win32SendMessage(hwnd, message, wParam, lParam);
+ }
+
+ internal override bool PostMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) {
+ return Win32PostMessage(hwnd, message, wParam, lParam);
+ }
+
+ internal override int SendInput (IntPtr hwnd, Queue keys) {
+ INPUT[] inputs = new INPUT[keys.Count];
+ const Int32 INPUT_KEYBOARD = 1;
+ uint returns = 0;
+ int i = 0;
+ while (keys.Count > 0) {
+ MSG msg = (MSG)keys.Dequeue();
+
+
+ inputs[i].ki.wScan = 0;
+ inputs[i].ki.time = 0;
+ inputs[i].ki.dwFlags = (Int32)(msg.message == Msg.WM_KEYUP ? InputFlags.KEYEVENTF_KEYUP : 0);
+ inputs[i].ki.wVk = (short)msg.wParam.ToInt32();
+ inputs[i].type = INPUT_KEYBOARD;
+ i++;
+ }
+ returns = Win32SendInput((UInt32)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
+
+ return (int) returns;
+ }
+
+ internal override int KeyboardSpeed {
+ get {
+ int speed = 0;
+ Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDSPEED, 0, ref speed, 0);
+ //
+ // Return values range from 0 to 31 which map to 2.5 to 30 repetitions per second.
+ //
+ return speed;
+ }
+ }
+
+ internal override int KeyboardDelay {
+ get {
+ int delay = 1;
+ Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDDELAY, 0, ref delay, 0);
+ //
+ // Return values must range from 0 to 4, 0 meaning 250ms,
+ // and 4 meaning 1000 ms.
+ //
+ return delay;
+ }
+ }
+
+ private class WinBuffer
+ {
+ public IntPtr hdc;
+ public IntPtr bitmap;
+
+ public WinBuffer (IntPtr hdc, IntPtr bitmap)
+ {
+ this.hdc = hdc;
+ this.bitmap = bitmap;
+ }
+ }
+
+ internal override void CreateOffscreenDrawable (IntPtr handle, int width, int height, out object offscreen_drawable)
+ {
+ Graphics destG = Graphics.FromHwnd (handle);
+ IntPtr destHdc = destG.GetHdc ();
+
+ IntPtr srcHdc = Win32CreateCompatibleDC (destHdc);
+ IntPtr srcBmp = Win32CreateCompatibleBitmap (destHdc, width, height);
+ Win32SelectObject (srcHdc, srcBmp);
+
+ offscreen_drawable = new WinBuffer (srcHdc, srcBmp);
+
+ destG.ReleaseHdc (destHdc);
+ }
+
+ internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
+ {
+ return Graphics.FromHdc (((WinBuffer)offscreen_drawable).hdc);
+ }
+
+ internal override void BlitFromOffscreen (IntPtr dest_handle, Graphics dest_dc, object offscreen_drawable, Graphics offscreen_dc, Rectangle r)
+ {
+ WinBuffer wb = (WinBuffer)offscreen_drawable;
+
+ IntPtr destHdc = dest_dc.GetHdc ();
+ Win32BitBlt (destHdc, r.Left, r.Top, r.Width, r.Height, wb.hdc, r.Left, r.Top, TernaryRasterOperations.SRCCOPY);
+ dest_dc.ReleaseHdc (destHdc);
+ }
+
+ internal override void DestroyOffscreenDrawable (object offscreen_drawable)
+ {
+ WinBuffer wb = (WinBuffer)offscreen_drawable;
+
+ Win32DeleteObject (wb.bitmap);
+ Win32DeleteDC (wb.hdc);
+ }
+
+ internal override void SetForegroundWindow (IntPtr handle)
+ {
+ Win32SetForegroundWindow(handle);
+ }
+
+ internal override event EventHandler Idle;
+ #endregion // Public Static Methods
+
+ #region Win32 Imports
+ [DllImport ("kernel32.dll", EntryPoint="GetLastError", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32GetLastError();
+
+ [DllImport ("user32.dll", EntryPoint="CreateWindowExW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32CreateWindow(WindowExStyles dwExStyle, string lpClassName, string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lParam);
+
+ [DllImport ("user32.dll", EntryPoint="DestroyWindow", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32DestroyWindow(IntPtr hWnd);
+
+ [DllImport ("user32.dll", EntryPoint="PeekMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32PeekMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags);
+
+ [DllImport ("user32.dll", EntryPoint="GetMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32GetMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax);
+
+ [DllImport ("user32.dll", EntryPoint="TranslateMessage", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32TranslateMessage(ref MSG msg);
+
+ [DllImport ("user32.dll", EntryPoint="DispatchMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32DispatchMessage(ref MSG msg);
+
+ [DllImport ("user32.dll", EntryPoint="MoveWindow", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32MoveWindow(IntPtr hWnd, int x, int y, int width, int height, bool repaint);
+
+ [DllImport ("user32.dll", EntryPoint="SetWindowPos", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPosFlags Flags);
+
+ [DllImport ("user32.dll", EntryPoint="SetWindowPos", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32SetWindowPos(IntPtr hWnd, SetWindowPosZOrder pos, int x, int y, int cx, int cy, SetWindowPosFlags Flags);
+
+ [DllImport ("user32.dll", EntryPoint="SetWindowTextW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32SetWindowText(IntPtr hWnd, string lpString);
+
+ [DllImport ("user32.dll", EntryPoint="GetWindowTextW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport ("user32.dll", EntryPoint="SetParent", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32SetParent(IntPtr hWnd, IntPtr hParent);
+
+ [DllImport ("user32.dll", EntryPoint="RegisterClassW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32RegisterClass(ref WNDCLASS wndClass);
+
+ [DllImport ("user32.dll", EntryPoint="LoadCursorW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32LoadCursor(IntPtr hInstance, LoadCursorType type);
+
+ [DllImport ("user32.dll", EntryPoint="ShowCursor", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32ShowCursor(bool bShow);
+
+ [DllImport ("user32.dll", EntryPoint="SetCursor", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32SetCursor(IntPtr hCursor);
+
+ [DllImport ("user32.dll", EntryPoint="CreateCursor", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32CreateCursor(IntPtr hInstance, int xHotSpot, int yHotSpot, int nWidth, int nHeight, Byte[] pvANDPlane, Byte[] pvORPlane);
+
+ [DllImport ("user32.dll", EntryPoint="DestroyCursor", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32DestroyCursor(IntPtr hCursor);
+
+ [DllImport ("user32.dll", EntryPoint = "DrawIcon", CallingConvention = CallingConvention.StdCall)]
+ private extern static bool Win32DrawIcon (IntPtr hDC, int X, int Y, IntPtr hIcon);
+
+ [DllImport ("user32.dll", EntryPoint="DefWindowProcW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32DefWindowProc(IntPtr hWnd, Msg Msg, IntPtr wParam, IntPtr lParam);
+
+ //[DllImport ("user32.dll", EntryPoint="DefDlgProcW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ //private extern static IntPtr Win32DefDlgProc(IntPtr hWnd, Msg Msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport ("user32.dll", EntryPoint="PostQuitMessage", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32PostQuitMessage(int nExitCode);
+
+ [DllImport ("user32.dll", EntryPoint="UpdateWindow", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32UpdateWindow(IntPtr hWnd);
+
+ [DllImport ("user32.dll", EntryPoint="GetUpdateRect", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32GetUpdateRect(IntPtr hWnd, ref RECT rect, bool erase);
+
+ [DllImport ("user32.dll", EntryPoint="BeginPaint", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32BeginPaint(IntPtr hWnd, ref PAINTSTRUCT ps);
+
+ [DllImport ("user32.dll", EntryPoint = "ValidateRect", CallingConvention = CallingConvention.StdCall)]
+ private extern static IntPtr Win32ValidateRect (IntPtr hWnd, ref RECT rect);
+
+ [DllImport ("user32.dll", EntryPoint="EndPaint", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32EndPaint(IntPtr hWnd, ref PAINTSTRUCT ps);
+
+ [DllImport ("user32.dll", EntryPoint="GetDC", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetDC(IntPtr hWnd);
+
+ [DllImport ("user32.dll", EntryPoint="GetWindowDC", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetWindowDC(IntPtr hWnd);
+
+ //[DllImport ("user32.dll", EntryPoint="GetDCEx", CallingConvention=CallingConvention.StdCall)]
+ //private extern static IntPtr Win32GetDCEx(IntPtr hWnd, IntPtr hRgn, DCExFlags flags);
+
+ [DllImport ("user32.dll", EntryPoint="ReleaseDC", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32ReleaseDC(IntPtr hWnd, IntPtr hDC);
+
+ [DllImport ("user32.dll", EntryPoint="MessageBoxW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32MessageBox(IntPtr hParent, string pText, string pCaption, uint uType);
+
+ [DllImport ("user32.dll", EntryPoint="InvalidateRect", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32InvalidateRect(IntPtr hWnd, ref RECT lpRect, bool bErase);
+
+ //[DllImport ("user32.dll", EntryPoint="InvalidateRect", CallingConvention=CallingConvention.StdCall)]
+ //private extern static IntPtr Win32InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);
+
+ [DllImport ("user32.dll", EntryPoint="SetCapture", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32SetCapture(IntPtr hWnd);
+
+ [DllImport ("user32.dll", EntryPoint="ReleaseCapture", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32ReleaseCapture();
+
+ [DllImport ("user32.dll", EntryPoint="GetWindowRect", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetWindowRect(IntPtr hWnd, out RECT rect);
+
+ [DllImport ("user32.dll", EntryPoint="GetClientRect", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetClientRect(IntPtr hWnd, out RECT rect);
+
+ [DllImport ("user32.dll", EntryPoint="ScreenToClient", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32ScreenToClient(IntPtr hWnd, ref POINT pt);
+
+ [DllImport ("user32.dll", EntryPoint="ClientToScreen", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32ClientToScreen(IntPtr hWnd, ref POINT pt);
+
+ // This function returns the parent OR THE OWNER!
+ // Use GetAncestor to only get the parent.
+ [DllImport ("user32.dll", EntryPoint="GetParent", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetParent(IntPtr hWnd);
+
+ [DllImport ("user32.dll", EntryPoint = "GetAncestor", CallingConvention = CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetAncestor (IntPtr hWnd, AncestorType flags);
+
+ [DllImport ("user32.dll", EntryPoint="SetActiveWindow", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32SetActiveWindow(IntPtr hWnd);
+
+ [DllImport ("user32.dll", EntryPoint="AdjustWindowRectEx", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32AdjustWindowRectEx(ref RECT lpRect, int dwStyle, bool bMenu, int dwExStyle);
+
+ [DllImport ("user32.dll", EntryPoint="GetCursorPos", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32GetCursorPos(out POINT lpPoint);
+
+ [DllImport ("user32.dll", EntryPoint="SetCursorPos", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32SetCursorPos(int x, int y);
+
+ //[DllImport ("user32.dll", EntryPoint="GetWindowPlacement", CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
+
+ [DllImport ("user32.dll", EntryPoint="TrackMouseEvent", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32TrackMouseEvent(ref TRACKMOUSEEVENT tme);
+
+ //[DllImport ("gdi32.dll", EntryPoint="CreateBrushIndirect", CallingConvention=CallingConvention.StdCall)]
+ //private extern static IntPtr Win32CreateBrushIndirect(ref LOGBRUSH lb);
+
+ [DllImport ("gdi32.dll", EntryPoint="CreateSolidBrush", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32CreateSolidBrush(COLORREF clrRef);
+
+ [DllImport ("gdi32.dll", EntryPoint="PatBlt", CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32PatBlt(IntPtr hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, PatBltRop dwRop);
+
+ [DllImport ("user32.dll", EntryPoint="SetWindowLong", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32SetWindowLong(IntPtr hwnd, WindowLong index, uint value);
+
+ [DllImport ("user32.dll", EntryPoint="GetWindowLong", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32GetWindowLong(IntPtr hwnd, WindowLong index);
+
+ [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)]
+ public extern static bool Win32DeleteObject(IntPtr o);
+
+ [DllImport ("user32.dll", EntryPoint="GetKeyState", CallingConvention=CallingConvention.StdCall)]
+ private extern static short Win32GetKeyState(VirtualKeys nVirtKey);
+
+ [DllImport ("user32.dll", EntryPoint="GetDesktopWindow", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetDesktopWindow();
+
+ [DllImport ("user32.dll", EntryPoint="SetTimer", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32SetTimer(IntPtr hwnd, int nIDEvent, uint uElapse, IntPtr timerProc);
+
+ [DllImport ("user32.dll", EntryPoint="KillTimer", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32KillTimer(IntPtr hwnd, int nIDEvent);
+
+ [DllImport ("user32.dll", EntryPoint="ShowWindow", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32ShowWindow(IntPtr hwnd, WindowPlacementFlags nCmdShow);
+
+ [DllImport ("user32.dll", EntryPoint="EnableWindow", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32EnableWindow(IntPtr hwnd, bool Enabled);
+
+ [DllImport ("user32.dll", EntryPoint="SetFocus", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32SetFocus(IntPtr hwnd);
+
+ [DllImport ("user32.dll", EntryPoint="GetFocus", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32GetFocus();
+
+ [DllImport ("user32.dll", EntryPoint="CreateCaret", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32CreateCaret(IntPtr hwnd, IntPtr hBitmap, int nWidth, int nHeight);
+
+ [DllImport ("user32.dll", EntryPoint="DestroyCaret", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32DestroyCaret();
+
+ [DllImport ("user32.dll", EntryPoint="ShowCaret", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32ShowCaret(IntPtr hwnd);
+
+ [DllImport ("user32.dll", EntryPoint="HideCaret", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32HideCaret(IntPtr hwnd);
+
+ [DllImport ("user32.dll", EntryPoint="SetCaretPos", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32SetCaretPos(int X, int Y);
+
+ //[DllImport ("user32.dll", EntryPoint="GetCaretBlinkTime", CallingConvention=CallingConvention.StdCall)]
+ //private extern static uint Win32GetCaretBlinkTime();
+
+ [DllImport ("gdi32.dll", EntryPoint="GetTextMetricsW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32GetTextMetrics(IntPtr hdc, ref TEXTMETRIC tm);
+
+ [DllImport ("gdi32.dll", EntryPoint="SelectObject", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32SelectObject(IntPtr hdc, IntPtr hgdiobject);
+
+ //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, out RECT prcUpdate, ScrollWindowExFlags flags);
+
+ //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, IntPtr prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, out RECT prcUpdate, ScrollWindowExFlags flags);
+
+ //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, IntPtr prcClip, IntPtr hrgnUpdate, out RECT prcUpdate, ScrollWindowExFlags flags);
+
+ [DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, IntPtr prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags);
+
+ //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, IntPtr prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags);
+
+ //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags);
+
+ [DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, IntPtr prcScroll, IntPtr prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags);
+
+ [DllImport ("user32.dll", EntryPoint="GetActiveWindow", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetActiveWindow();
+
+ [DllImport ("user32.dll", EntryPoint="GetSystemMetrics", CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32GetSystemMetrics(SystemMetrics nIndex);
+
+ [DllImport ("shell32.dll", EntryPoint="Shell_NotifyIconW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32Shell_NotifyIcon(NotifyIconMessage dwMessage, ref NOTIFYICONDATA lpData);
+
+ [DllImport ("gdi32.dll", EntryPoint="CreateRectRgn", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
+
+ [DllImport ("user32.dll", EntryPoint="IsWindowEnabled", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool IsWindowEnabled(IntPtr hwnd);
+
+ [DllImport ("user32.dll", EntryPoint="IsWindowVisible", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool IsWindowVisible(IntPtr hwnd);
+
+ [DllImport ("user32.dll", EntryPoint="IsWindow", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool IsWindow(IntPtr hwnd);
+
+ //[DllImport ("user32.dll", EntryPoint="SetClassLong", CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32SetClassLong(IntPtr hwnd, ClassLong nIndex, IntPtr dwNewLong);
+
+ [DllImport ("user32.dll", EntryPoint="SendMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32SendMessage(IntPtr hwnd, Msg msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport ("user32.dll", EntryPoint="PostMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32PostMessage(IntPtr hwnd, Msg msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport ("user32.dll", EntryPoint="SendInput", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static UInt32 Win32SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray)] INPUT[] inputs, Int32 cbSize);
+
+ [DllImport ("user32.dll", EntryPoint="SystemParametersInfoW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32SystemParametersInfo(SPIAction uiAction, uint uiParam, ref RECT rect, uint fWinIni);
+
+ //[DllImport ("user32.dll", EntryPoint="SystemParametersInfoW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ //private extern static bool Win32SystemParametersInfo(SPIAction uiAction, uint uiParam, ref uint value, uint fWinIni);
+
+ [DllImport ("user32.dll", EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
+ private extern static bool Win32SystemParametersInfo (SPIAction uiAction, uint uiParam, ref int value, uint fWinIni);
+
+ [DllImport ("user32.dll", EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
+ private extern static bool Win32SystemParametersInfo (SPIAction uiAction, uint uiParam, ref bool value, uint fWinIni);
+
+ [DllImport ("user32.dll", EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
+ private extern static bool Win32SystemParametersInfo (SPIAction uiAction, uint uiParam, ref ANIMATIONINFO value, uint fWinIni);
+
+ [DllImport ("user32.dll", EntryPoint="OpenClipboard", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32OpenClipboard(IntPtr hwnd);
+
+ [DllImport ("user32.dll", EntryPoint="EmptyClipboard", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32EmptyClipboard();
+
+ [DllImport ("user32.dll", EntryPoint="RegisterClipboardFormatW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32RegisterClipboardFormat(string format);
+
+ [DllImport ("user32.dll", EntryPoint="CloseClipboard", CallingConvention=CallingConvention.StdCall)]
+ private extern static bool Win32CloseClipboard();
+
+ [DllImport ("user32.dll", EntryPoint="EnumClipboardFormats", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32EnumClipboardFormats(uint format);
+
+ [DllImport ("user32.dll", EntryPoint="GetClipboardData", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32GetClipboardData(uint format);
+
+ [DllImport ("user32.dll", EntryPoint="SetClipboardData", CallingConvention=CallingConvention.StdCall)]
+ private extern static IntPtr Win32SetClipboardData(uint format, IntPtr handle);
+
+ [DllImport ("kernel32.dll", EntryPoint="GlobalAlloc", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32GlobalAlloc(GAllocFlags Flags, int dwBytes);
+
+ [DllImport ("kernel32.dll", EntryPoint="CopyMemory", CallingConvention=CallingConvention.StdCall)]
+ internal extern static void Win32CopyMemory(IntPtr Destination, IntPtr Source, int length);
+
+ [DllImport ("kernel32.dll", EntryPoint="GlobalFree", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32GlobalFree(IntPtr hMem);
+
+ [DllImport ("kernel32.dll", EntryPoint="GlobalSize", CallingConvention=CallingConvention.StdCall)]
+ internal extern static uint Win32GlobalSize(IntPtr hMem);
+
+ [DllImport ("kernel32.dll", EntryPoint="GlobalLock", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32GlobalLock(IntPtr hMem);
+
+ [DllImport ("kernel32.dll", EntryPoint="GlobalUnlock", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32GlobalUnlock(IntPtr hMem);
+
+ [DllImport ("gdi32.dll", EntryPoint="SetROP2", CallingConvention=CallingConvention.StdCall)]
+ internal extern static int Win32SetROP2(IntPtr hdc, ROP2DrawMode fnDrawMode);
+
+ [DllImport ("gdi32.dll", EntryPoint="MoveToEx", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32MoveToEx(IntPtr hdc, int x, int y, ref POINT lpPoint);
+
+ [DllImport ("gdi32.dll", EntryPoint="MoveToEx", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32MoveToEx(IntPtr hdc, int x, int y, IntPtr lpPoint);
+
+ [DllImport ("gdi32.dll", EntryPoint="LineTo", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32LineTo(IntPtr hdc, int x, int y);
+
+ [DllImport ("gdi32.dll", EntryPoint="CreatePen", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32CreatePen(PenStyle fnPenStyle, int nWidth, ref COLORREF color);
+
+ [DllImport ("gdi32.dll", EntryPoint="CreatePen", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32CreatePen(PenStyle fnPenStyle, int nWidth, IntPtr color);
+
+ [DllImport ("gdi32.dll", EntryPoint="GetStockObject", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32GetStockObject(StockObject fnObject);
+
+ [DllImport ("gdi32.dll", EntryPoint="CreateHatchBrush", CallingConvention=CallingConvention.StdCall)]
+ internal extern static IntPtr Win32CreateHatchBrush(HatchStyle fnStyle, IntPtr color);
+
+ [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);
+
+ [DllImport ("user32.dll", EntryPoint="GetDoubleClickTime", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)]
+ private extern static int Win32GetDoubleClickTime ();
+
+ [DllImport ("user32.dll", EntryPoint="SetWindowRgn", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)]
+ internal extern static int Win32SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool redraw);
+
+ [DllImport ("user32.dll", EntryPoint="GetWindowRgn", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)]
+ internal extern static IntPtr Win32GetWindowRgn(IntPtr hWnd, IntPtr hRgn);
+
+ [DllImport ("user32.dll", EntryPoint="ClipCursor", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32ClipCursor (ref RECT lpRect);
+
+ [DllImport ("user32.dll", EntryPoint="GetClipCursor", CallingConvention=CallingConvention.StdCall)]
+ internal extern static bool Win32GetClipCursor (out RECT lpRect);
+
+ [DllImport ("gdi32.dll", EntryPoint="BitBlt", CallingConvention=CallingConvention.StdCall)]
+ internal static extern bool Win32BitBlt (IntPtr hObject, int nXDest, int nYDest, int nWidth,
+ int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
+
+ [DllImport ("gdi32.dll", EntryPoint="CreateCompatibleDC", CallingConvention=CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)]
+ internal static extern IntPtr Win32CreateCompatibleDC (IntPtr hdc);
+
+ [DllImport ("gdi32.dll", EntryPoint="DeleteDC", CallingConvention=CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)]
+ internal static extern bool Win32DeleteDC (IntPtr hdc);
+
+ [DllImport ("gdi32.dll", EntryPoint="CreateCompatibleBitmap", CallingConvention=CallingConvention.StdCall)]
+ internal static extern IntPtr Win32CreateCompatibleBitmap (IntPtr hdc, int nWidth, int nHeight);
+
+ [DllImport ("kernel32.dll", EntryPoint = "GetSystemPowerStatus", CallingConvention = CallingConvention.StdCall)]
+ internal static extern Boolean Win32GetSystemPowerStatus (SYSTEMPOWERSTATUS sps);
+
+ [DllImport ("user32.dll", EntryPoint = "GetIconInfo", CallingConvention = CallingConvention.StdCall)]
+ internal static extern bool Win32GetIconInfo (IntPtr hIcon, out ICONINFO piconinfo);
+
+ [DllImport ("user32.dll", EntryPoint="SetForegroundWindow", CallingConvention=CallingConvention.StdCall)]
+ extern static bool Win32SetForegroundWindow(IntPtr hWnd);
+ #endregion
+ }
+}
diff --git a/source/ShiftUI/Internal/XplatUIX11-new.cs b/source/ShiftUI/Internal/XplatUIX11-new.cs
new file mode 100644
index 0000000..3795406
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUIX11-new.cs
@@ -0,0 +1,1079 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+// Chris Toshok [email protected]
+//
+//
+
+// NOTE:
+// This driver understands the following environment variables: (Set the var to enable feature)
+//
+// MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered;
+// by default a message is displayed but execution continues
+//
+// MONO_XSYNC = perform all X11 commands synchronous; this is slower but
+// helps in debugging errors
+//
+
+// NOT COMPLETE
+
+// define to log Window handles and relationships to stdout
+#undef DriverDebug
+
+// Extra detailed debug
+#undef DriverDebugExtra
+#undef DriverDebugParent
+#undef DriverDebugCreate
+#undef DriverDebugDestroy
+#undef DriverDebugThreads
+#undef DriverDebugXEmbed
+
+using System;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using ShiftUI;
+
+/// X11 Version
+namespace ShiftUI.X11Internal {
+ internal class XplatUIX11_new : XplatUIX11 {
+
+
+ #region Local Variables
+ // General
+ static volatile XplatUIX11_new Instance;
+ static readonly object lockobj = new object ();
+ static int RefCount;
+ static bool themes_enabled;
+
+ static Hashtable MessageQueues; // Holds our thread-specific X11ThreadQueues
+
+ X11Display display;
+
+ #endregion // Local Variables
+ #region Constructors
+ private XplatUIX11_new() {
+ // Handle singleton stuff first
+ RefCount = 0;
+
+ // Now regular initialization
+ MessageQueues = Hashtable.Synchronized (new Hashtable(7));
+ if (Xlib.XInitThreads() == 0) {
+ Console.WriteLine ("Failed XInitThreads. The X11 event loop will not function properly");
+ }
+ }
+
+ private void InitializeDisplay ()
+ {
+ display = new X11Display (Xlib.XOpenDisplay(IntPtr.Zero));
+
+ Graphics.FromHdcInternal (display.Handle);
+ }
+
+ ~XplatUIX11_new() {
+ // Remove our display handle from S.D
+ Graphics.FromHdcInternal (IntPtr.Zero);
+ }
+
+ #endregion // Constructors
+
+ #region Singleton Specific Code
+ public static XplatUIX11_new GetInstance() {
+ lock (lockobj) {
+ if (Instance == null) {
+ Instance = new XplatUIX11_new ();
+
+ Instance.InitializeDisplay ();
+ }
+ RefCount++;
+ }
+ return Instance;
+ }
+
+ public int Reference {
+ get {
+ return RefCount;
+ }
+ }
+ #endregion
+
+ #region Internal Methods
+ internal static void Where() {
+ Console.WriteLine("Here: {0}\n", GetInstance().display.WhereString());
+ }
+
+ #endregion // Internal Methods
+
+ #region Private Methods
+
+ internal X11ThreadQueue ThreadQueue (Thread thread)
+ {
+ X11ThreadQueue queue;
+
+ queue = (X11ThreadQueue)MessageQueues[thread];
+ if (queue == null) {
+ queue = new X11ThreadQueue(thread);
+ MessageQueues[thread] = queue;
+ }
+
+ return queue;
+ }
+ #endregion // Private Methods
+
+
+ #region Public Properties
+ internal override int CaptionHeight {
+ get { return 19; }
+ }
+
+ internal override Size CursorSize {
+ get { return display.CursorSize; }
+ }
+
+ internal override bool DragFullWindows {
+ get { return true; }
+ }
+
+ internal override Size DragSize {
+ get { return new Size(4, 4); }
+ }
+
+ internal override Size FrameBorderSize {
+ get { return new Size (4, 4); }
+ }
+
+ internal override Size IconSize {
+ get { return display.IconSize; }
+ }
+
+ internal override int KeyboardSpeed {
+ get { return display.KeyboardSpeed; }
+ }
+
+ internal override int KeyboardDelay {
+ get { return display.KeyboardSpeed; }
+ }
+
+ internal override Size MaxWindowTrackSize {
+ get { return new Size (WorkingArea.Width, WorkingArea.Height); }
+ }
+
+ internal override bool MenuAccessKeysUnderlined {
+ get {
+ return false;
+ }
+ }
+
+ internal override Size MinimizedWindowSpacingSize {
+ get { return new Size(1, 1); }
+ }
+
+ internal override Size MinimumWindowSize {
+ get { return new Size(1, 1); }
+ }
+
+ internal override Keys ModifierKeys {
+ get { return display.ModifierKeys; }
+ }
+
+ internal override Size SmallIconSize {
+ get { return display.SmallIconSize; }
+ }
+
+ internal override int MouseButtonCount {
+ get { return 3; /* FIXME - should detect this somehow.. */}
+ }
+
+ internal override bool MouseButtonsSwapped {
+ get { return false; /*FIXME - how to detect? */}
+ }
+
+ internal override Size MouseHoverSize {
+ get { return new Size (1, 1); }
+ }
+
+ internal override int MouseHoverTime {
+ get { return display.MouseHoverTime; }
+ }
+
+ internal override bool MouseWheelPresent {
+ get { return true; /* FIXME - how to detect? */ }
+ }
+
+ internal override Rectangle VirtualScreen {
+ get { return display.VirtualScreen; }
+ }
+
+ internal override Rectangle WorkingArea {
+ get { return display.WorkingArea; }
+ }
+
+ internal override bool ThemesEnabled {
+ get { return XplatUIX11_new.themes_enabled; }
+ }
+
+
+ #endregion // Public properties
+
+ #region Public Static Methods
+ internal override void RaiseIdle (EventArgs e)
+ {
+ X11ThreadQueue queue = ThreadQueue (Thread.CurrentThread);
+ queue.OnIdle (e);
+ }
+
+ internal override IntPtr InitializeDriver ()
+ {
+ lock (this) {
+ if (display == null)
+ display = new X11Display (Xlib.XOpenDisplay(IntPtr.Zero));
+ }
+ return IntPtr.Zero;
+ }
+
+ internal override void ShutdownDriver(IntPtr token)
+ {
+ lock (this) {
+ if (display != null) {
+ display.Close ();
+ display = null;
+ }
+ }
+ }
+
+ internal override void EnableThemes()
+ {
+ themes_enabled = true;
+ }
+
+ internal override void Activate (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.Activate ();
+ }
+
+ internal override void AudibleAlert(AlertType atype)
+ {
+ display.AudibleAlert ();
+ }
+
+
+ internal override void CaretVisible (IntPtr handle, bool visible)
+ {
+ display.CaretVisible (handle, visible);
+ }
+
+ // XXX this implementation should probably be shared between all non-win32 backends
+ 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)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.ClientToScreen (ref x, ref y);
+ }
+
+ internal override void CreateCaret (IntPtr handle, int width, int height)
+ {
+ display.CreateCaret (handle, width, height);
+ }
+
+ internal override IntPtr CreateWindow (CreateParams cp)
+ {
+ X11Hwnd hwnd = new X11Hwnd (display);
+
+ hwnd.CreateWindow (cp);
+
+ 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.DefaultClassName;
+ create_params.ClassStyle = 0;
+ create_params.ExStyle = 0;
+ create_params.Parent = IntPtr.Zero;
+ create_params.Param = 0;
+
+ return CreateWindow (create_params);
+ }
+
+ internal override IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
+ {
+ return display.DefineCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot);
+ }
+ internal override Bitmap DefineStdCursorBitmap (StdCursor id)
+ {
+ return display.DefineStdCursorBitmap (id);
+ }
+ internal override IntPtr DefineStdCursor (StdCursor id)
+ {
+ return display.DefineStdCursor (id);
+ }
+
+ internal override IntPtr DefWndProc(ref Message msg)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(msg.HWnd);
+
+ if (hwnd == null)
+ return IntPtr.Zero;
+
+ return hwnd.DefWndProc (ref msg);
+ }
+
+ internal override void DestroyCaret (IntPtr handle)
+ {
+ display.DestroyCaret (handle);
+ }
+
+ internal override void DestroyCursor(IntPtr cursor)
+ {
+ display.DestroyCursor (cursor);
+ }
+
+ internal override void DestroyWindow (IntPtr handle) {
+ X11Hwnd hwnd;
+
+ hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd == null) {
+#if DriverDebug || DriverDebugDestroy
+ Console.WriteLine("window {0:X} already destroyed", handle.ToInt32());
+#endif
+ return;
+ }
+
+#if DriverDebug || DriverDebugDestroy
+ Console.WriteLine("Destroying window {0}", XplatUI.Window(hwnd.ClientWindow));
+#endif
+
+ display.DestroyWindow (hwnd);
+ }
+
+ internal override IntPtr DispatchMessage(ref MSG msg)
+ {
+ return display.DispatchMessage (ref msg);
+ }
+
+ internal override void DrawReversibleLine (Point start, Point end, Color backColor)
+ {
+ display.DrawReversibleLine (start, end, backColor);
+ }
+
+ internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
+ {
+ display.FillReversibleRectangle (rectangle, backColor);
+ }
+
+ internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
+ {
+ display.DrawReversibleFrame (rectangle, backColor, style);
+ }
+
+ internal override void DrawReversibleRectangle (IntPtr handle, Rectangle rect, int line_width)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.DrawReversibleRectangle (rect, line_width);
+ }
+
+ internal override void DoEvents ()
+ {
+ X11ThreadQueue queue = ThreadQueue (Thread.CurrentThread);
+ display.DoEvents (queue);
+ }
+
+ internal override void EnableWindow (IntPtr handle, bool Enable)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (hwnd != null)
+ hwnd.Enabled = Enable;
+ }
+
+ internal override void EndLoop (Thread thread)
+ {
+ // This is where we one day will shut down the loop for the thread
+ }
+
+
+ internal override IntPtr GetActive()
+ {
+ X11Hwnd hwnd = display.GetActiveWindow ();
+
+ return (hwnd == null) ? IntPtr.Zero : hwnd.Handle;
+ }
+
+ internal override Region GetClipRegion (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ return (hwnd == null) ? null : hwnd.GetClipRegion ();
+ }
+
+ internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y)
+ {
+ width = 20;
+ height = 20;
+ hotspot_x = 0;
+ hotspot_y = 0;
+ }
+
+ internal override void GetDisplaySize(out Size size)
+ {
+ display.GetDisplaySize (out size);
+ }
+
+ internal override SizeF GetAutoScaleSize (Font font)
+ {
+ return display.GetAutoScaleSize (font);
+ }
+
+ // XXX this should be someplace shareable by all non-win32 backends.. like in Hwnd itself.
+ // maybe a Hwnd.ParentHandle property
+ 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;
+ }
+
+ // This is a nop on win32 and x11
+ internal override IntPtr GetPreviousWindow(IntPtr handle) {
+ return handle;
+ }
+
+ internal override void GetCursorPos (IntPtr handle, out int x, out int y)
+ {
+ display.GetCursorPos ((X11Hwnd)Hwnd.ObjectFromHandle(handle),
+ out x, out y);
+ }
+
+ internal override IntPtr GetFocus()
+ {
+ return display.GetFocus ();
+ }
+
+ // XXX this should be shared amongst non-win32 backends
+ 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;
+ }
+
+
+ // XXX this should be shared amongst non-win32 backends
+ 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 handle, int wFilterMin, int wFilterMax)
+ {
+ return display.GetMessage (queue_id, ref msg, handle, wFilterMin, wFilterMax);
+ }
+
+ internal override bool GetText (IntPtr handle, out string text)
+ {
+ X11Hwnd hwnd = (X11Hwnd) Hwnd.ObjectFromHandle(handle);
+
+ text = "";
+ return hwnd != null && hwnd.GetText (out text);
+ }
+
+ 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)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null) {
+ hwnd.GetPosition (is_toplevel, out x, out y, out width, out height, out client_width, out client_height);
+ }
+ else {
+ // 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 handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd == null)
+ return FormWindowState.Normal; // XXX should we throw an exception here? probably
+
+ return hwnd.GetWindowState ();
+ }
+
+ internal override void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea)
+ {
+ display.GrabInfo (out handle, out GrabConfined, out GrabArea);
+ }
+
+ internal override void GrabWindow (IntPtr handle, IntPtr confine_to_handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+ X11Hwnd confine_to_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(confine_to_handle);
+
+ display.GrabWindow (hwnd, confine_to_hwnd);
+ }
+
+ internal override void UngrabWindow (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ display.UngrabWindow (hwnd);
+ }
+
+ internal override void HandleException(Exception e) {
+ StackTrace st = new StackTrace(e, true);
+ 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)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ hwnd.Invalidate (rc, clear);
+ }
+
+ internal override void InvalidateNC (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ hwnd.InvalidateNC ();
+ }
+
+ internal override bool IsEnabled(IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle);
+
+ return hwnd != null && hwnd.Enabled;
+ }
+
+ internal override bool IsVisible(IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle);
+
+ return hwnd != null && hwnd.Visible;
+ }
+
+ internal override void KillTimer (Timer timer)
+ {
+ X11ThreadQueue queue = (X11ThreadQueue) MessageQueues [timer.thread];
+
+ if (queue == null) {
+ // This isn't really an error, MS doesn't start the timer if
+ // it has no assosciated queue
+ return;
+ }
+ queue.KillTimer (timer);
+ }
+
+ internal override void MenuToScreen (IntPtr handle, ref int x, ref int y)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.MenuToScreen (ref x, ref y);
+ }
+
+ internal override void OverrideCursor (IntPtr cursor)
+ {
+ display.OverrideCursor = cursor;
+ }
+
+ internal override PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client)
+ {
+ return display.PaintEventStart (ref m, handle, client);
+ }
+
+ internal override void PaintEventEnd (ref Message m, IntPtr handle, bool client)
+ {
+ display.PaintEventEnd (ref m, handle, client);
+ }
+
+
+ internal override bool PeekMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
+ {
+ return display.PeekMessage (queue_id, ref msg, hWnd, wFilterMin, wFilterMax, flags);
+ }
+
+ internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam)
+ {
+ return display.PostMessage (handle, message, wparam, lparam);
+ }
+
+ internal override void PostQuitMessage(int exitCode)
+ {
+ display.PostMessage (display.FosterParent.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+ display.Flush ();
+ }
+
+ [MonoTODO]
+ internal override void RequestAdditionalWM_NCMessages (IntPtr handle, bool hover, bool leave)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.RequestAdditionalWM_NCMessages (hover, leave);
+ }
+
+ internal override void RequestNCRecalc (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.RequestNCRecalc ();
+ }
+
+ internal override void ResetMouseHover (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ display.ResetMouseHover (hwnd);
+ }
+
+ internal override void ScreenToClient(IntPtr handle, ref int x, ref int y)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.ScreenToClient (ref x, ref y);
+ }
+
+ internal override void ScreenToMenu (IntPtr handle, ref int x, ref int y)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.ScreenToMenu (ref x, ref y);
+ }
+
+ internal override void ScrollWindow (IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.ScrollWindow (area, XAmount, YAmount, with_children);
+ }
+
+ internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(handle);
+
+ if (hwnd != null) {
+ Rectangle rect;
+
+ rect = hwnd.ClientRect;
+ rect.X = 0;
+ rect.Y = 0;
+ hwnd.ScrollWindow (rect, XAmount, YAmount, with_children);
+ }
+ }
+
+ internal override void SendAsyncMethod (AsyncMethodData method)
+ {
+ display.SendAsyncMethod (method);
+ }
+
+ // XXX this is likely shareable amongst other backends
+ internal override IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ return display.SendMessage (handle, message, wParam, lParam);
+ }
+
+ internal override int SendInput(IntPtr handle, Queue keys) {
+ return display.SendInput(handle, keys);
+ }
+
+
+ internal override void SetAllowDrop (IntPtr handle, bool value)
+ {
+ // We allow drop on all windows
+ }
+
+ internal override DragDropEffects StartDrag (IntPtr handle, object data,
+ DragDropEffects allowed_effects)
+ {
+ return display.StartDrag (handle, data, allowed_effects);
+ }
+
+ internal override void SetBorderStyle (IntPtr handle, FormBorderStyle border_style)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.SetBorderStyle (border_style);
+ }
+
+ internal override void SetCaretPos (IntPtr handle, int x, int y)
+ {
+ display.SetCaretPos (handle, x, y);
+ }
+
+ internal override void SetClipRegion (IntPtr handle, Region region)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.SetClipRegion (region);
+ }
+
+ internal override void SetCursor (IntPtr handle, IntPtr cursor)
+ {
+ display.SetCursor (handle, cursor);
+ }
+
+ internal override void SetCursorPos (IntPtr handle, int x, int y)
+ {
+ if (handle == IntPtr.Zero) {
+ display.SetCursorPos (x, y);
+ }
+ else {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ hwnd.SetCursorPos (x, y);
+ }
+ }
+
+ internal override void SetFocus (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ display.SetFocus (hwnd);
+ }
+
+ internal override void SetIcon(IntPtr handle, Icon icon)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);;
+
+ if (hwnd != null)
+ hwnd.SetIcon (icon);
+ }
+
+ internal override void SetMenu(IntPtr handle, Menu menu)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ hwnd.SetMenu (menu);
+ }
+
+ internal override void SetModal(IntPtr handle, bool Modal)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ display.SetModal (hwnd, Modal);
+ }
+
+ internal override IntPtr SetParent(IntPtr handle, IntPtr parent)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+ X11Hwnd parent_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(parent);
+
+ if (hwnd != null)
+ hwnd.SetParent (parent_hwnd);
+
+ return IntPtr.Zero;
+ }
+
+ internal override void SetTimer (Timer timer)
+ {
+ X11ThreadQueue queue = (X11ThreadQueue) MessageQueues [timer.thread];
+
+ if (queue == null) {
+ // This isn't really an error, MS doesn't start the timer if
+ // it has no assosciated queue
+ return;
+ }
+ queue.SetTimer (timer);
+ }
+
+ internal override bool SetTopmost(IntPtr handle, bool enabled)
+ {
+ X11Hwnd hwnd = (X11Hwnd) Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd == null)
+ return false;
+
+ return hwnd.SetTopmost (enabled);
+ }
+
+ internal override bool SetOwner(IntPtr handle, IntPtr handle_owner)
+ {
+ X11Hwnd hwnd;
+
+ hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd == null)
+ return false;
+
+ X11Hwnd hwnd_owner = (X11Hwnd)Hwnd.ObjectFromHandle(handle_owner);
+
+ return hwnd.SetOwner (hwnd_owner);
+ }
+
+ internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ return hwnd != null && hwnd.SetVisible (visible, activate);
+ }
+
+ internal override void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd == null)
+ return;
+
+ hwnd.SetMinMax (maximized, min, max);
+ }
+
+ internal override void SetWindowPos (IntPtr handle, int x, int y, int width, int height)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.SetPosition (x, y, width, height);
+ }
+
+ internal override void SetWindowState (IntPtr handle, FormWindowState state)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.SetWindowState (state);
+ }
+
+ internal override void SetWindowStyle (IntPtr handle, CreateParams cp)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null) {
+ hwnd.SetHwndStyles (cp);
+ hwnd.SetWMStyles (cp);
+ }
+ }
+
+ internal override double GetWindowTransparency (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ return hwnd.GetWindowTransparency ();
+ else
+ return 0.0;
+ }
+
+ internal override void SetWindowTransparency (IntPtr handle, double transparency, Color key)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.SetWindowTransparency (transparency, key);
+ }
+
+ internal override bool SetZOrder (IntPtr handle, IntPtr after_handle, bool top, bool bottom)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd == null || !hwnd.mapped)
+ return false;
+
+ X11Hwnd after_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(after_handle);
+
+ return hwnd.SetZOrder (after_hwnd, top, bottom);
+ }
+
+ internal override void ShowCursor (bool show)
+ {
+ display.ShowCursor (show);
+ }
+
+ internal override object StartLoop(Thread thread)
+ {
+ return (object) ThreadQueue(thread);
+ }
+
+ internal override TransparencySupport SupportsTransparency()
+ {
+ return display.SupportsTransparency ();
+ }
+
+ internal override bool SystrayAdd (IntPtr handle, string tip, Icon icon, out ToolTip tt)
+ {
+ return display.SystrayAdd (handle, tip, icon, out tt);
+ }
+
+ internal override bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt)
+ {
+ return display.SystrayChange (handle, tip, icon, ref tt);
+ }
+
+ internal override void SystrayRemove (IntPtr handle, ref ToolTip tt)
+ {
+ display.SystrayRemove (handle, ref tt);
+ }
+
+ NotifyIcon.BalloonWindow balloon_window;
+
+ internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
+ {
+ Widget control = Widget.FromHandle(handle);
+
+ if (control == null)
+ return;
+
+ if (balloon_window != null) {
+ balloon_window.Close ();
+ balloon_window.Dispose ();
+ }
+
+ balloon_window = new NotifyIcon.BalloonWindow (handle);
+ balloon_window.Title = title;
+ balloon_window.Text = text;
+ balloon_window.Timeout = timeout;
+ balloon_window.Show ();
+
+ SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW);
+ }
+
+ internal override bool Text (IntPtr handle, string text)
+ {
+ X11Hwnd hwnd = (X11Hwnd) Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.Text = text;
+
+ return true;
+ }
+
+ internal override bool TranslateMessage (ref MSG msg)
+ {
+ return display.TranslateMessage (ref msg);
+ }
+
+ internal override void UpdateWindow (IntPtr handle)
+ {
+ X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null)
+ hwnd.Update ();
+ }
+
+ internal override void CreateOffscreenDrawable (IntPtr handle,
+ int width, int height,
+ out object offscreen_drawable)
+ {
+ display.CreateOffscreenDrawable (handle, width, height,
+ out offscreen_drawable);
+ }
+
+ internal override void DestroyOffscreenDrawable (object offscreen_drawable)
+ {
+ display.DestroyOffscreenDrawable (offscreen_drawable);
+ }
+
+ internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
+ {
+ return display.GetOffscreenGraphics (offscreen_drawable);
+ }
+
+ internal override void BlitFromOffscreen (IntPtr dest_handle,
+ Graphics dest_dc,
+ object offscreen_drawable,
+ Graphics offscreen_dc,
+ Rectangle r)
+ {
+ display.BlitFromOffscreen (dest_handle, dest_dc, offscreen_drawable, offscreen_dc, r);
+ }
+
+ #endregion // Public Static Methods
+
+ #region Events
+ internal override event EventHandler Idle {
+ add {
+ Console.WriteLine ("adding idle handler for thread {0}", Thread.CurrentThread.GetHashCode());
+ X11ThreadQueue queue = ThreadQueue(Thread.CurrentThread);
+ queue.Idle += value;
+ }
+ remove {
+ X11ThreadQueue queue = ThreadQueue(Thread.CurrentThread);
+ queue.Idle += value;
+ }
+ }
+ #endregion // Events
+ }
+}
diff --git a/source/ShiftUI/Internal/XplatUIX11.cs b/source/ShiftUI/Internal/XplatUIX11.cs
new file mode 100644
index 0000000..fd68bab
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUIX11.cs
@@ -0,0 +1,7687 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+//
+//
+
+// NOTE:
+// This driver understands the following environment variables: (Set the var to enable feature)
+//
+// MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered;
+// by default a message is displayed but execution continues
+//
+// MONO_XSYNC = perform all X11 commands synchronous; this is slower but
+// helps in debugging errors
+//
+
+// NOT COMPLETE
+
+// define to log Window handles and relationships to stdout
+#undef DriverDebug
+
+// Extra detailed debug
+#undef DriverDebugExtra
+#undef DriverDebugParent
+#undef DriverDebugCreate
+#undef DriverDebugDestroy
+#undef DriverDebugThreads
+#undef DriverDebugXEmbed
+
+//#define TRACE
+//#define DEBUG
+
+using System;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Text;
+using System.Threading;
+
+// Only do the poll when building with mono for now
+#if __MonoCS__
+using Mono.Unix.Native;
+#endif
+
+/// X11 Version
+namespace ShiftUI {
+ internal class XplatUIX11 : XplatUIDriver {
+ #region Local Variables
+ // General
+ static volatile XplatUIX11 Instance;
+ static int RefCount;
+ static object XlibLock; // Our locking object
+ static bool themes_enabled;
+
+ // General X11
+ static IntPtr DisplayHandle; // X11 handle to display
+ static int ScreenNo; // Screen number used
+ static IntPtr DefaultColormap; // Colormap for screen
+ static IntPtr CustomVisual; // Visual for window creation
+ static IntPtr CustomColormap; // Colormap for window creation
+ static IntPtr RootWindow; // Handle of the root window for the screen/display
+ static IntPtr FosterParent; // Container to hold child windows until their parent exists
+ static XErrorHandler ErrorHandler; // Error handler delegate
+ static bool ErrorExceptions; // Throw exceptions on X errors
+ int render_major_opcode;
+ int render_first_event;
+ int render_first_error;
+
+ // Clipboard
+ static IntPtr ClipMagic;
+ static ClipboardData Clipboard; // Our clipboard
+
+ // Communication
+ static IntPtr PostAtom; // PostMessage atom
+ static IntPtr AsyncAtom; // Support for async messages
+
+ // Message Loop
+ static Hashtable MessageQueues; // Holds our thread-specific XEventQueues
+ static ArrayList unattached_timer_list; // holds timers that are enabled but not attached to a window.
+ #if __MonoCS__ //
+ static Pollfd[] pollfds; // For watching the X11 socket
+ static bool wake_waiting;
+ static object wake_waiting_lock = new object ();
+ #endif //
+ static X11Keyboard Keyboard; //
+ static X11Dnd Dnd;
+ static Socket listen; //
+ static Socket wake; //
+ static Socket wake_receive; //
+ static byte[] network_buffer; //
+ static bool detectable_key_auto_repeat;
+
+ // Focus tracking
+ static IntPtr ActiveWindow; // Handle of the active window
+ static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any)
+
+ // Modality support
+ static Stack ModalWindows; // Stack of our modal windows
+
+ // Systray
+ static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window
+
+ // Cursors
+ static IntPtr LastCursorWindow; // The last window we set the cursor on
+ static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
+ static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
+
+ // Caret
+ static CaretStruct Caret; //
+
+ // Last window containing the pointer
+ static IntPtr LastPointerWindow; // The last window containing the pointer
+
+ // Our atoms
+ static IntPtr WM_PROTOCOLS;
+ static IntPtr WM_DELETE_WINDOW;
+ static IntPtr WM_TAKE_FOCUS;
+ //static IntPtr _NET_SUPPORTED;
+ //static IntPtr _NET_CLIENT_LIST;
+ //static IntPtr _NET_NUMBER_OF_DESKTOPS;
+ static IntPtr _NET_DESKTOP_GEOMETRY;
+ //static IntPtr _NET_DESKTOP_VIEWPORT;
+ static IntPtr _NET_CURRENT_DESKTOP;
+ //static IntPtr _NET_DESKTOP_NAMES;
+ static IntPtr _NET_ACTIVE_WINDOW;
+ static IntPtr _NET_WORKAREA;
+ //static IntPtr _NET_SUPPORTING_WM_CHECK;
+ //static IntPtr _NET_VIRTUAL_ROOTS;
+ //static IntPtr _NET_DESKTOP_LAYOUT;
+ //static IntPtr _NET_SHOWING_DESKTOP;
+ //static IntPtr _NET_CLOSE_WINDOW;
+ //static IntPtr _NET_MOVERESIZE_WINDOW;
+ static IntPtr _NET_WM_MOVERESIZE;
+ //static IntPtr _NET_RESTACK_WINDOW;
+ //static IntPtr _NET_REQUEST_FRAME_EXTENTS;
+ static IntPtr _NET_WM_NAME;
+ //static IntPtr _NET_WM_VISIBLE_NAME;
+ //static IntPtr _NET_WM_ICON_NAME;
+ //static IntPtr _NET_WM_VISIBLE_ICON_NAME;
+ //static IntPtr _NET_WM_DESKTOP;
+ static IntPtr _NET_WM_WINDOW_TYPE;
+ static IntPtr _NET_WM_STATE;
+ //static IntPtr _NET_WM_ALLOWED_ACTIONS;
+ //static IntPtr _NET_WM_STRUT;
+ //static IntPtr _NET_WM_STRUT_PARTIAL;
+ //static IntPtr _NET_WM_ICON_GEOMETRY;
+ static IntPtr _NET_WM_ICON;
+ //static IntPtr _NET_WM_PID;
+ //static IntPtr _NET_WM_HANDLED_ICONS;
+ static IntPtr _NET_WM_USER_TIME;
+ static IntPtr _NET_FRAME_EXTENTS;
+ //static IntPtr _NET_WM_PING;
+ //static IntPtr _NET_WM_SYNC_REQUEST;
+ static IntPtr _NET_SYSTEM_TRAY_S;
+ //static IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
+ static IntPtr _NET_SYSTEM_TRAY_OPCODE;
+ static IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
+ static IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
+ static IntPtr _XEMBED;
+ static IntPtr _XEMBED_INFO;
+ static IntPtr _MOTIF_WM_HINTS;
+ static IntPtr _NET_WM_STATE_SKIP_TASKBAR;
+ static IntPtr _NET_WM_STATE_ABOVE;
+ static IntPtr _NET_WM_STATE_MODAL;
+ static IntPtr _NET_WM_STATE_HIDDEN;
+ static IntPtr _NET_WM_CONTEXT_HELP;
+ static IntPtr _NET_WM_WINDOW_OPACITY;
+ //static IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
+ //static IntPtr _NET_WM_WINDOW_TYPE_DOCK;
+ //static IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
+ //static IntPtr _NET_WM_WINDOW_TYPE_MENU;
+ static IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
+ //static IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
+ // static IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
+ static IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
+ static IntPtr CLIPBOARD;
+ static IntPtr PRIMARY;
+ //static IntPtr DIB;
+ static IntPtr OEMTEXT;
+ static IntPtr UTF8_STRING;
+ static IntPtr UTF16_STRING;
+ static IntPtr RICHTEXTFORMAT;
+ static IntPtr TARGETS;
+
+ // mouse hover message generation
+ static HoverStruct HoverState; //
+
+ // double click message generation
+ static ClickStruct ClickPending; //
+
+ // Support for mouse grab
+ static GrabStruct Grab; //
+
+ // State
+ Point mouse_position; // Last position of mouse, in screen coords
+ internal static MouseButtons MouseState; // Last state of mouse buttons
+ internal static bool in_doevents;
+ // 'Constants'
+ static int DoubleClickInterval; // msec; max interval between clicks to count as double click
+
+ const EventMask SelectInputMask = (EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask |
+ EventMask.KeyPressMask |
+ EventMask.KeyReleaseMask |
+ EventMask.EnterWindowMask |
+ EventMask.LeaveWindowMask |
+ EventMask.ExposureMask |
+ EventMask.FocusChangeMask |
+ EventMask.PointerMotionMask |
+ EventMask.PointerMotionHintMask |
+ EventMask.SubstructureNotifyMask);
+
+ static readonly object lockobj = new object ();
+
+ // messages WaitForHwndMwssage is waiting on
+ static Hashtable messageHold;
+
+ #endregion // Local Variables
+ #region Constructors
+ public XplatUIX11()
+ {
+ // Handle singleton stuff first
+ RefCount = 0;
+ in_doevents = false;
+
+ // Now regular initialization
+ XlibLock = new object ();
+ X11Keyboard.XlibLock = XlibLock;
+ MessageQueues = Hashtable.Synchronized (new Hashtable(7));
+ unattached_timer_list = ArrayList.Synchronized (new ArrayList (3));
+ messageHold = Hashtable.Synchronized (new Hashtable(3));
+ Clipboard = new ClipboardData ();
+ XInitThreads();
+
+ ErrorExceptions = false;
+
+ // X11 Initialization
+ SetDisplay(XOpenDisplay(IntPtr.Zero));
+ X11DesktopColors.Initialize();
+
+
+ // Disable keyboard autorepeat
+ try {
+ XkbSetDetectableAutoRepeat (DisplayHandle, true, IntPtr.Zero);
+ detectable_key_auto_repeat = true;
+ } catch {
+ Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually.");
+ detectable_key_auto_repeat = false;
+ }
+
+ // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does)
+ ErrorHandler = new XErrorHandler(HandleError);
+ XSetErrorHandler(ErrorHandler);
+ }
+
+ ~XplatUIX11() {
+ // Remove our display handle from S.D
+ Graphics.FromHdcInternal (IntPtr.Zero);
+ }
+
+ #endregion // Constructors
+
+ #region Singleton Specific Code
+ public static XplatUIX11 GetInstance() {
+ lock (lockobj) {
+ if (Instance == null) {
+ Instance=new XplatUIX11();
+ }
+ RefCount++;
+ }
+ return Instance;
+ }
+
+ public int Reference {
+ get {
+ return RefCount;
+ }
+ }
+ #endregion
+
+ #region Internal Properties
+ internal static IntPtr Display {
+ get {
+ return DisplayHandle;
+ }
+
+ set {
+ XplatUIX11.GetInstance().SetDisplay(value);
+ }
+ }
+
+ internal static int Screen {
+ get {
+ return ScreenNo;
+ }
+
+ set {
+ ScreenNo = value;
+ }
+ }
+
+ internal static IntPtr RootWindowHandle {
+ get {
+ return RootWindow;
+ }
+
+ set {
+ RootWindow = value;
+ }
+ }
+
+ internal static IntPtr Visual {
+ get {
+ return CustomVisual;
+ }
+
+ set {
+ CustomVisual = value;
+ }
+ }
+
+ internal static IntPtr ColorMap {
+ get {
+ return CustomColormap;
+ }
+
+ set {
+ CustomColormap = value;
+ }
+ }
+
+#if DEBUG_shana
+ internal static IntPtr DefaultColorMap {
+ get {
+ return DefaultColormap;
+ }
+ }
+#endif
+ #endregion
+
+ #region XExceptionClass
+ internal class XException : ApplicationException {
+ IntPtr Display;
+ IntPtr ResourceID;
+ IntPtr Serial;
+ XRequest RequestCode;
+ byte ErrorCode;
+ byte MinorCode;
+
+ public XException(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
+ this.Display = Display;
+ this.ResourceID = ResourceID;
+ this.Serial = Serial;
+ this.RequestCode = RequestCode;
+ this.ErrorCode = ErrorCode;
+ this.MinorCode = MinorCode;
+ }
+
+ public override string Message {
+ get {
+ return GetMessage(Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode);
+ }
+ }
+
+ public static string GetMessage(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
+ StringBuilder sb;
+ string x_error_text;
+ string error;
+ string hwnd_text;
+ string Widget_text;
+ Hwnd hwnd;
+ Widget c;
+
+ sb = new StringBuilder(160);
+ XGetErrorText(Display, ErrorCode, sb, sb.Capacity);
+ x_error_text = sb.ToString();
+ hwnd = Hwnd.ObjectFromHandle(ResourceID);
+ if (hwnd != null) {
+ hwnd_text = hwnd.ToString();
+ c = Widget.FromHandle(hwnd.Handle);
+ if (c != null) {
+ Widget_text = c.ToString();
+ } else {
+ Widget_text = String.Format("<handle {0:X} non-existant>", hwnd.Handle.ToInt32());
+ }
+ } else {
+ hwnd_text = "<null>";
+ Widget_text = "<null>";
+ }
+
+
+ error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:X}\n Serial: {4}\n Hwnd: {5}\n Widget: {6}", x_error_text, RequestCode, MinorCode, ResourceID.ToInt32(), Serial, hwnd_text, Widget_text);
+ return error;
+ }
+ }
+ #endregion // XExceptionClass
+
+ #region Internal Methods
+ internal void SetDisplay(IntPtr display_handle)
+ {
+ if (display_handle != IntPtr.Zero) {
+ Hwnd hwnd;
+
+ if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) {
+ hwnd = Hwnd.ObjectFromHandle(FosterParent);
+ XDestroyWindow(DisplayHandle, FosterParent);
+ hwnd.Dispose();
+ }
+
+ if (DisplayHandle != IntPtr.Zero) {
+ XCloseDisplay(DisplayHandle);
+ }
+
+ DisplayHandle=display_handle;
+
+ // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has
+ // been hacked to do this for us.
+ Graphics.FromHdcInternal (DisplayHandle);
+
+ // query for the render extension so
+ // we can ignore the spurious
+ // BadPicture errors that are
+ // generated by cairo/render.
+ XQueryExtension (DisplayHandle, "RENDER",
+ ref render_major_opcode, ref render_first_event, ref render_first_error);
+
+ // Debugging support
+ if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
+ XSynchronize(DisplayHandle, true);
+ }
+
+ if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
+ ErrorExceptions = true;
+ }
+
+ // Generic X11 setup
+ ScreenNo = XDefaultScreen(DisplayHandle);
+ RootWindow = XRootWindow(DisplayHandle, ScreenNo);
+ DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
+
+ // Create the foster parent
+ // it is important that border_width is kept in synch with the other XCreateWindow calls
+ FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 0, UIntPtr.Zero, UIntPtr.Zero);
+ if (FosterParent==IntPtr.Zero) {
+ Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
+ }
+
+ DebugHelper.WriteLine ("FosterParent created 0x{0:x}", FosterParent.ToInt32());
+
+ hwnd = new Hwnd();
+ hwnd.Queue = ThreadQueue(Thread.CurrentThread);
+ hwnd.WholeWindow = FosterParent;
+ hwnd.ClientWindow = FosterParent;
+
+ // Create a HWND for RootWIndow as well, so our queue doesn't eat the events
+ hwnd = new Hwnd();
+ hwnd.Queue = ThreadQueue(Thread.CurrentThread);
+ hwnd.whole_window = RootWindow;
+ hwnd.ClientWindow = RootWindow;
+
+ // For sleeping on the X11 socket
+ listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
+ IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0);
+ listen.Bind(ep);
+ listen.Listen(1);
+
+ // To wake up when a timer is ready
+ network_buffer = new byte[10];
+
+ wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
+ wake.Connect(listen.LocalEndPoint);
+
+ // Make this non-blocking, so it doesn't
+ // deadlock if too many wakes are sent
+ // before the wake_receive end is polled
+ wake.Blocking = false;
+
+ wake_receive = listen.Accept();
+
+ #if __MonoCS__
+ pollfds = new Pollfd [2];
+ pollfds [0] = new Pollfd ();
+ pollfds [0].fd = XConnectionNumber (DisplayHandle);
+ pollfds [0].events = PollEvents.POLLIN;
+
+ pollfds [1] = new Pollfd ();
+ pollfds [1].fd = wake_receive.Handle.ToInt32 ();
+ pollfds [1].events = PollEvents.POLLIN;
+ #endif
+
+ Keyboard = new X11Keyboard(DisplayHandle, FosterParent);
+ Dnd = new X11Dnd (DisplayHandle, Keyboard);
+
+ DoubleClickInterval = 500;
+
+ HoverState.Interval = 500;
+ HoverState.Timer = new Timer();
+ HoverState.Timer.Enabled = false;
+ HoverState.Timer.Interval = HoverState.Interval;
+ HoverState.Timer.Tick += new EventHandler(MouseHover);
+ HoverState.Size = new Size(4, 4);
+ HoverState.X = -1;
+ HoverState.Y = -1;
+
+ ActiveWindow = IntPtr.Zero;
+ FocusWindow = IntPtr.Zero;
+ ModalWindows = new Stack(3);
+
+ MouseState = MouseButtons.None;
+ mouse_position = new Point(0, 0);
+
+ Caret.Timer = new Timer();
+ Caret.Timer.Interval = 500; // FIXME - where should this number come from?
+ Caret.Timer.Tick += new EventHandler(CaretCallback);
+
+ SetupAtoms();
+
+ // Grab atom changes off the root window to catch certain WM events
+ XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int) (EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
+
+ // Handle any upcoming errors
+ ErrorHandler = new XErrorHandler(HandleError);
+ XSetErrorHandler(ErrorHandler);
+ } else {
+ throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)");
+ }
+ }
+ #endregion // Internal Methods
+
+ #region Methods
+ [Conditional ("DriverDebug")]
+ static void DriverDebug (string format, params object [] args)
+ {
+ Console.WriteLine (String.Format (format, args));
+ }
+
+ int unixtime() {
+ TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
+
+ return (int) t.TotalSeconds;
+ }
+
+ static void SetupAtoms() {
+ // make sure this array stays in sync with the statements below
+ string [] atom_names = new string[] {
+ "WM_PROTOCOLS",
+ "WM_DELETE_WINDOW",
+ "WM_TAKE_FOCUS",
+ //"_NET_SUPPORTED",
+ //"_NET_CLIENT_LIST",
+ //"_NET_NUMBER_OF_DESKTOPS",
+ "_NET_DESKTOP_GEOMETRY",
+ //"_NET_DESKTOP_VIEWPORT",
+ "_NET_CURRENT_DESKTOP",
+ //"_NET_DESKTOP_NAMES",
+ "_NET_ACTIVE_WINDOW",
+ "_NET_WORKAREA",
+ //"_NET_SUPPORTING_WM_CHECK",
+ //"_NET_VIRTUAL_ROOTS",
+ //"_NET_DESKTOP_LAYOUT",
+ //"_NET_SHOWING_DESKTOP",
+ //"_NET_CLOSE_WINDOW",
+ //"_NET_MOVERESIZE_WINDOW",
+ "_NET_WM_MOVERESIZE",
+ //"_NET_RESTACK_WINDOW",
+ //"_NET_REQUEST_FRAME_EXTENTS",
+ "_NET_WM_NAME",
+ //"_NET_WM_VISIBLE_NAME",
+ //"_NET_WM_ICON_NAME",
+ //"_NET_WM_VISIBLE_ICON_NAME",
+ //"_NET_WM_DESKTOP",
+ "_NET_WM_WINDOW_TYPE",
+ "_NET_WM_STATE",
+ //"_NET_WM_ALLOWED_ACTIONS",
+ //"_NET_WM_STRUT",
+ //"_NET_WM_STRUT_PARTIAL",
+ //"_NET_WM_ICON_GEOMETRY",
+ "_NET_WM_ICON",
+ //"_NET_WM_PID",
+ //"_NET_WM_HANDLED_ICONS",
+ "_NET_WM_USER_TIME",
+ "_NET_FRAME_EXTENTS",
+ //"_NET_WM_PING",
+ //"_NET_WM_SYNC_REQUEST",
+ "_NET_SYSTEM_TRAY_OPCODE",
+ //"_NET_SYSTEM_TRAY_ORIENTATION",
+ "_NET_WM_STATE_MAXIMIZED_HORZ",
+ "_NET_WM_STATE_MAXIMIZED_VERT",
+ "_NET_WM_STATE_HIDDEN",
+ "_XEMBED",
+ "_XEMBED_INFO",
+ "_MOTIF_WM_HINTS",
+ "_NET_WM_STATE_SKIP_TASKBAR",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_MODAL",
+ "_NET_WM_CONTEXT_HELP",
+ "_NET_WM_WINDOW_OPACITY",
+ //"_NET_WM_WINDOW_TYPE_DESKTOP",
+ //"_NET_WM_WINDOW_TYPE_DOCK",
+ //"_NET_WM_WINDOW_TYPE_TOOLBAR",
+ //"_NET_WM_WINDOW_TYPE_MENU",
+ "_NET_WM_WINDOW_TYPE_UTILITY",
+ // "_NET_WM_WINDOW_TYPE_DIALOG",
+ //"_NET_WM_WINDOW_TYPE_SPLASH",
+ "_NET_WM_WINDOW_TYPE_NORMAL",
+ "CLIPBOARD",
+ "PRIMARY",
+ "COMPOUND_TEXT",
+ "UTF8_STRING",
+ "UTF16_STRING",
+ "RICHTEXTFORMAT",
+ "TARGETS",
+ "_SWF_AsyncAtom",
+ "_SWF_PostMessageAtom",
+ "_SWF_HoverAtom" };
+
+ IntPtr[] atoms = new IntPtr [atom_names.Length];;
+
+ XInternAtoms (DisplayHandle, atom_names, atom_names.Length, false, atoms);
+
+ int off = 0;
+ WM_PROTOCOLS = atoms [off++];
+ WM_DELETE_WINDOW = atoms [off++];
+ WM_TAKE_FOCUS = atoms [off++];
+ //_NET_SUPPORTED = atoms [off++];
+ //_NET_CLIENT_LIST = atoms [off++];
+ //_NET_NUMBER_OF_DESKTOPS = atoms [off++];
+ _NET_DESKTOP_GEOMETRY = atoms [off++];
+ //_NET_DESKTOP_VIEWPORT = atoms [off++];
+ _NET_CURRENT_DESKTOP = atoms [off++];
+ //_NET_DESKTOP_NAMES = atoms [off++];
+ _NET_ACTIVE_WINDOW = atoms [off++];
+ _NET_WORKAREA = atoms [off++];
+ //_NET_SUPPORTING_WM_CHECK = atoms [off++];
+ //_NET_VIRTUAL_ROOTS = atoms [off++];
+ //_NET_DESKTOP_LAYOUT = atoms [off++];
+ //_NET_SHOWING_DESKTOP = atoms [off++];
+ //_NET_CLOSE_WINDOW = atoms [off++];
+ //_NET_MOVERESIZE_WINDOW = atoms [off++];
+ _NET_WM_MOVERESIZE = atoms [off++];
+ //_NET_RESTACK_WINDOW = atoms [off++];
+ //_NET_REQUEST_FRAME_EXTENTS = atoms [off++];
+ _NET_WM_NAME = atoms [off++];
+ //_NET_WM_VISIBLE_NAME = atoms [off++];
+ //_NET_WM_ICON_NAME = atoms [off++];
+ //_NET_WM_VISIBLE_ICON_NAME = atoms [off++];
+ //_NET_WM_DESKTOP = atoms [off++];
+ _NET_WM_WINDOW_TYPE = atoms [off++];
+ _NET_WM_STATE = atoms [off++];
+ //_NET_WM_ALLOWED_ACTIONS = atoms [off++];
+ //_NET_WM_STRUT = atoms [off++];
+ //_NET_WM_STRUT_PARTIAL = atoms [off++];
+ //_NET_WM_ICON_GEOMETRY = atoms [off++];
+ _NET_WM_ICON = atoms [off++];
+ //_NET_WM_PID = atoms [off++];
+ //_NET_WM_HANDLED_ICONS = atoms [off++];
+ _NET_WM_USER_TIME = atoms [off++];
+ _NET_FRAME_EXTENTS = atoms [off++];
+ //_NET_WM_PING = atoms [off++];
+ //_NET_WM_SYNC_REQUEST = atoms [off++];
+ _NET_SYSTEM_TRAY_OPCODE = atoms [off++];
+ //_NET_SYSTEM_TRAY_ORIENTATION = atoms [off++];
+ _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++];
+ _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++];
+ _NET_WM_STATE_HIDDEN = atoms [off++];
+ _XEMBED = atoms [off++];
+ _XEMBED_INFO = atoms [off++];
+ _MOTIF_WM_HINTS = atoms [off++];
+ _NET_WM_STATE_SKIP_TASKBAR = atoms [off++];
+ _NET_WM_STATE_ABOVE = atoms [off++];
+ _NET_WM_STATE_MODAL = atoms [off++];
+ _NET_WM_CONTEXT_HELP = atoms [off++];
+ _NET_WM_WINDOW_OPACITY = atoms [off++];
+ //_NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++];
+ //_NET_WM_WINDOW_TYPE_DOCK = atoms [off++];
+ //_NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++];
+ //_NET_WM_WINDOW_TYPE_MENU = atoms [off++];
+ _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++];
+ // _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++];
+ //_NET_WM_WINDOW_TYPE_SPLASH = atoms [off++];
+ _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++];
+ CLIPBOARD = atoms [off++];
+ PRIMARY = atoms [off++];
+ OEMTEXT = atoms [off++];
+ UTF8_STRING = atoms [off++];
+ UTF16_STRING = atoms [off++];
+ RICHTEXTFORMAT = atoms [off++];
+ TARGETS = atoms [off++];
+ AsyncAtom = atoms [off++];
+ PostAtom = atoms [off++];
+ HoverState.Atom = atoms [off++];
+
+ //DIB = (IntPtr)Atom.XA_PIXMAP;
+ _NET_SYSTEM_TRAY_S = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString(), false);
+ }
+
+ void GetSystrayManagerWindow() {
+ XGrabServer(DisplayHandle);
+ SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, _NET_SYSTEM_TRAY_S);
+ XUngrabServer(DisplayHandle);
+ XFlush(DisplayHandle);
+ }
+
+ void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
+ SendNetWMMessage (window, message_type, l0, l1, l2, IntPtr.Zero);
+ }
+
+ void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2, IntPtr l3) {
+ XEvent xev;
+
+ xev = new XEvent();
+ xev.ClientMessageEvent.type = XEventName.ClientMessage;
+ xev.ClientMessageEvent.send_event = true;
+ xev.ClientMessageEvent.window = window;
+ xev.ClientMessageEvent.message_type = message_type;
+ xev.ClientMessageEvent.format = 32;
+ xev.ClientMessageEvent.ptr1 = l0;
+ xev.ClientMessageEvent.ptr2 = l1;
+ xev.ClientMessageEvent.ptr3 = l2;
+ xev.ClientMessageEvent.ptr4 = l3;
+ XSendEvent(DisplayHandle, RootWindow, false, new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
+ }
+
+ void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
+ XEvent xev;
+
+ xev = new XEvent();
+ xev.ClientMessageEvent.type = XEventName.ClientMessage;
+ xev.ClientMessageEvent.send_event = true;
+ xev.ClientMessageEvent.window = window;
+ xev.ClientMessageEvent.message_type = message_type;
+ xev.ClientMessageEvent.format = 32;
+ xev.ClientMessageEvent.ptr1 = l0;
+ xev.ClientMessageEvent.ptr2 = l1;
+ xev.ClientMessageEvent.ptr3 = l2;
+ XSendEvent(DisplayHandle, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev);
+ }
+
+ // For WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN
+ // WM_CREATE and WM_DESTROY causes
+ 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);
+ }
+
+ bool StyleSet (int s, WindowStyles ws)
+ {
+ return (s & (int)ws) == (int)ws;
+ }
+
+ bool ExStyleSet (int ex, WindowExStyles exws)
+ {
+ return (ex & (int)exws) == (int)exws;
+ }
+
+ internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd)
+ {
+ return TranslateClientRectangleToXClientRectangle (hwnd, Widget.FromHandle (hwnd.Handle));
+ }
+
+ internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd, Widget ctrl)
+ {
+ /*
+ * 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 xrect = rect;
+
+ xrect.Y -= borders.top;
+ xrect.X -= borders.left;
+ xrect.Width += borders.left + borders.right;
+ xrect.Height += borders.top + borders.bottom;
+
+ rect = xrect;
+ }
+
+ if (rect.Width < 1 || rect.Height < 1) {
+ rect.Width = 1;
+ rect.Height = 1;
+ rect.X = -5;
+ rect.Y = -5;
+ }
+
+ return rect;
+ }
+
+ internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp)
+ {
+ return TranslateWindowSizeToXWindowSize (cp, new Size (cp.Width, cp.Height));
+ }
+
+ internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp, Size size)
+ {
+ /*
+ * 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 xrect = size;
+
+ xrect.Width -= borders.left + borders.right;
+ xrect.Height -= borders.top + borders.bottom;
+
+ size = xrect;
+ }
+ if (size.Height == 0)
+ size.Height = 1;
+ if (size.Width == 0)
+ size.Width = 1;
+ return size;
+ }
+
+ internal static Size TranslateXWindowSizeToWindowSize (CreateParams cp, int xWidth, int xHeight)
+ {
+ /*
+ * 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 rect = new Size (xWidth, xHeight);
+ 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 xrect = rect;
+
+ xrect.Width += borders.left + borders.right;
+ xrect.Height += borders.top + borders.bottom;
+
+ rect = xrect;
+ }
+ return rect;
+ }
+
+ internal static Point GetTopLevelWindowLocation (Hwnd hwnd)
+ {
+ IntPtr dummy;
+ int x, y;
+ Hwnd.Borders frame;
+
+ XTranslateCoordinates (DisplayHandle, hwnd.whole_window, RootWindow, 0, 0, out x, out y, out dummy);
+ frame = FrameExtents (hwnd.whole_window);
+
+ x -= frame.left;
+ y -= frame.top;
+
+ return new Point (x, y);
+ }
+
+ 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 = 19;
+ 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 = 19;
+ 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 = 19;
+
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+ 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);
+ }
+
+ void SetWMStyles(Hwnd hwnd, CreateParams cp) {
+ MotifWmHints mwmHints;
+ MotifFunctions functions;
+ MotifDecorations decorations;
+ int[] atoms;
+ int atom_count;
+ Rectangle client_rect;
+ Form form;
+ IntPtr window_type;
+ bool hide_from_taskbar;
+ IntPtr transient_for_parent;
+
+ // Windows we manage ourselves don't need WM window styles.
+ if (cp.HasWindowManager && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
+ return;
+ }
+
+ atoms = new int[8];
+ mwmHints = new MotifWmHints();
+ functions = 0;
+ decorations = 0;
+ window_type = _NET_WM_WINDOW_TYPE_NORMAL;
+ transient_for_parent = IntPtr.Zero;
+
+ mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
+ mwmHints.functions = (IntPtr)0;
+ mwmHints.decorations = (IntPtr)0;
+
+ form = cp.control as Form;
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
+ /* tool windows get no window manager
+ decorations.
+ */
+
+ /* just because the window doesn't get any decorations doesn't
+ mean we should disable the functions. for instance, without
+ MotifFunctions.Maximize, changing the windowstate to Maximized
+ is ignored by metacity. */
+ functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
+ } else if (form != null && form.FormBorderStyle == FormBorderStyle.None) {
+ /* allow borderless window to be maximized */
+ functions |= MotifFunctions.All | MotifFunctions.Resize;
+ } else {
+ if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
+ functions |= MotifFunctions.Move;
+ decorations |= MotifDecorations.Title | MotifDecorations.Menu;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) {
+ functions |= MotifFunctions.Move | MotifFunctions.Resize;
+ decorations |= MotifDecorations.Border | MotifDecorations.ResizeH;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) {
+ functions |= MotifFunctions.Minimize;
+ decorations |= MotifDecorations.Minimize;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) {
+ functions |= MotifFunctions.Maximize;
+ decorations |= MotifDecorations.Maximize;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) {
+ functions |= MotifFunctions.Resize;
+ decorations |= MotifDecorations.ResizeH;
+ }
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
+ decorations |= MotifDecorations.Border;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) {
+ decorations |= MotifDecorations.Border;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) {
+ decorations |= MotifDecorations.Border;
+ }
+
+ if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) {
+ functions |= MotifFunctions.Close;
+ }
+ else {
+ functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close);
+ decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize);
+ if (cp.Caption == "") {
+ functions &= ~MotifFunctions.Move;
+ decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH);
+ }
+ }
+ }
+
+ if ((functions & MotifFunctions.Resize) == 0) {
+ hwnd.fixed_size = true;
+ Rectangle fixed_rectangle = new Rectangle (cp.X, cp.Y, cp.Width, cp.Height);
+ SetWindowMinMax(hwnd.Handle, fixed_rectangle, fixed_rectangle.Size, fixed_rectangle.Size, cp);
+ } else {
+ hwnd.fixed_size = false;
+ }
+
+ mwmHints.functions = (IntPtr)functions;
+ mwmHints.decorations = (IntPtr)decorations;
+
+ DriverDebug ("SetWMStyles ({0}, {1}) functions = {2}, decorations = {3}", hwnd, cp, functions, decorations);
+
+ if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
+ // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
+ // and get those windows in front of their parents
+ window_type = _NET_WM_WINDOW_TYPE_UTILITY;
+ } else {
+ window_type = _NET_WM_WINDOW_TYPE_NORMAL;
+ }
+
+ if (!cp.IsSet (WindowExStyles.WS_EX_APPWINDOW)) {
+ hide_from_taskbar = true;
+ } else if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW) && form != null && form.Parent != null && !form.ShowInTaskbar) {
+ hide_from_taskbar = true;
+ } else {
+ hide_from_taskbar = false;
+ }
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
+ if (form != null && !hwnd.reparented) {
+ if (form.Owner != null && form.Owner.Handle != IntPtr.Zero) {
+ Hwnd owner_hwnd = Hwnd.ObjectFromHandle (form.Owner.Handle);
+ if (owner_hwnd != null)
+ transient_for_parent = owner_hwnd.whole_window;
+ }
+ }
+ }
+ if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
+ transient_for_parent = hwnd.parent.whole_window;
+ }
+
+ FormWindowState current_state = GetWindowState (hwnd.Handle);
+ if (current_state == (FormWindowState)(-1))
+ current_state = FormWindowState.Normal;
+
+ client_rect = TranslateClientRectangleToXClientRectangle (hwnd);
+
+ lock (XlibLock) {
+ atom_count = 0;
+
+ atoms [0] = window_type.ToInt32 ();
+ XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
+
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref mwmHints, 5);
+
+ if (transient_for_parent != IntPtr.Zero) {
+ XSetTransientForHint (DisplayHandle, hwnd.whole_window, transient_for_parent);
+ }
+
+ MoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
+
+ if (hide_from_taskbar) {
+ /* this line keeps the window from showing up in gnome's taskbar */
+ atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
+ }
+ /* we need to add these atoms in the
+ * event we're maximized, since we're
+ * replacing the existing
+ * _NET_WM_STATE here. If we don't
+ * add them, future calls to
+ * GetWindowState will return Normal
+ * for a window which is maximized. */
+ if (current_state == FormWindowState.Maximized) {
+ atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_HORZ.ToInt32();
+ atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_VERT.ToInt32();
+ }
+
+ if (form != null && form.Modal) {
+ atoms[atom_count++] = _NET_WM_STATE_MODAL.ToInt32 ();
+ }
+
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
+
+ atom_count = 0;
+ IntPtr[] atom_ptrs = new IntPtr[2];
+ atom_ptrs[atom_count++] = WM_DELETE_WINDOW;
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP)) {
+ atom_ptrs[atom_count++] = _NET_WM_CONTEXT_HELP;
+ }
+
+ XSetWMProtocols(DisplayHandle, hwnd.whole_window, atom_ptrs, atom_count);
+ }
+ }
+
+ void SetIcon(Hwnd hwnd, Icon icon)
+ {
+ if (icon == null) {
+ // XXX
+
+ // This really needs to do whatever it
+ // takes to remove the window manager
+ // menu, not just delete the ICON
+ // property. This will cause metacity
+ // to use the "no icon set" icon, and
+ // we'll still have an icon.
+ XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_ICON);
+ }
+ else {
+ Bitmap bitmap;
+ int size;
+ IntPtr[] data;
+ int index;
+
+ bitmap = icon.ToBitmap();
+ index = 0;
+ size = bitmap.Width * bitmap.Height + 2;
+ data = new IntPtr[size];
+
+ data[index++] = (IntPtr)bitmap.Width;
+ data[index++] = (IntPtr)bitmap.Height;
+
+ for (int y = 0; y < bitmap.Height; y++) {
+ for (int x = 0; x < bitmap.Width; x++) {
+ data[index++] = (IntPtr)bitmap.GetPixel (x, y).ToArgb ();
+ }
+ }
+
+ XChangeProperty (DisplayHandle, hwnd.whole_window,
+ _NET_WM_ICON, (IntPtr)Atom.XA_CARDINAL, 32,
+ PropertyMode.Replace, data, size);
+ }
+ }
+
+ void WakeupMain () {
+ try {
+ wake.Send (new byte [] { 0xFF });
+ } catch (SocketException ex) {
+ if (ex.SocketErrorCode != SocketError.WouldBlock) {
+ throw;
+ }
+ }
+ }
+
+ XEventQueue ThreadQueue(Thread thread) {
+ XEventQueue queue;
+
+ queue = (XEventQueue)MessageQueues[thread];
+ if (queue == null) {
+ queue = new XEventQueue(thread);
+ MessageQueues[thread] = queue;
+ }
+
+ return queue;
+ }
+
+ void TranslatePropertyToClipboard(IntPtr property) {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Clipboard.Item = null;
+
+ XGetWindowProperty(DisplayHandle, FosterParent, property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if ((long)nitems > 0) {
+ if (property == (IntPtr)Atom.XA_STRING) {
+ // Xamarin-5116: PtrToStringAnsi expects to get UTF-8, but we might have
+ // Latin-1 instead, in which case it will return null.
+ var s = Marshal.PtrToStringAnsi (prop);
+ if (string.IsNullOrEmpty (s)) {
+ var sb = new StringBuilder ();
+ for (int i = 0; i < (int)nitems; i++) {
+ var b = Marshal.ReadByte (prop, i);
+ sb.Append ((char)b);
+ }
+ s = sb.ToString ();
+ }
+ // Some X managers/apps pass unicode chars as escaped strings, so
+ // we may need to unescape them.
+ Clipboard.Item = UnescapeUnicodeFromAnsi (s);
+ } else if (property == (IntPtr)Atom.XA_BITMAP) {
+ // FIXME - convert bitmap to image
+ } else if (property == (IntPtr)Atom.XA_PIXMAP) {
+ // FIXME - convert pixmap to image
+ } else if (property == OEMTEXT) {
+ Clipboard.Item = UnescapeUnicodeFromAnsi (Marshal.PtrToStringAnsi(prop));
+ } else if (property == UTF8_STRING) {
+ byte [] buffer = new byte [(int)nitems];
+ for (int i = 0; i < (int)nitems; i++)
+ buffer [i] = Marshal.ReadByte (prop, i);
+ Clipboard.Item = Encoding.UTF8.GetString (buffer);
+ } else if (property == UTF16_STRING) {
+ byte [] buffer = new byte [(int)nitems];
+ for (int i = 0; i < (int)nitems; i++)
+ buffer [i] = Marshal.ReadByte (prop, i);
+ Clipboard.Item = Encoding.Unicode.GetString (buffer);
+ } else if (property == RICHTEXTFORMAT)
+ Clipboard.Item = Marshal.PtrToStringAnsi(prop);
+ else if (DataFormats.ContainsFormat (property.ToInt32 ())) {
+ if (DataFormats.GetFormat (property.ToInt32 ()).is_serializable) {
+ MemoryStream memory_stream = new MemoryStream ((int)nitems);
+ for (int i = 0; i < (int)nitems; i++)
+ memory_stream.WriteByte (Marshal.ReadByte (prop, i));
+
+ memory_stream.Position = 0;
+ BinaryFormatter formatter = new BinaryFormatter ();
+ Clipboard.Item = formatter.Deserialize (memory_stream);
+ memory_stream.Close ();
+ }
+ }
+
+ XFree(prop);
+ }
+ }
+
+ string UnescapeUnicodeFromAnsi (string value)
+ {
+ if (value == null || value.IndexOf ("\\u") == -1)
+ return value;
+
+ StringBuilder sb = new StringBuilder (value.Length);
+ int start, pos;
+
+ start = pos = 0;
+ while (start < value.Length) {
+ pos = value.IndexOf ("\\u", start);
+ if (pos == -1)
+ break;
+
+ sb.Append (value, start, pos - start);
+ pos += 2;
+ start = pos;
+
+ int length = 0;
+ while (pos < value.Length && length < 4) {
+ if (!ValidHexDigit (value [pos]))
+ break;
+ length++;
+ pos++;
+ }
+
+ int res;
+ if (!Int32.TryParse (value.Substring (start, length), System.Globalization.NumberStyles.HexNumber,
+ null, out res))
+ return value; // Error, return the unescaped original value.
+
+ sb.Append ((char)res);
+ start = pos;
+ }
+
+ // Append any remaining data.
+ if (start < value.Length)
+ sb.Append (value, start, value.Length - start);
+
+ return sb.ToString ();
+ }
+
+ private static bool ValidHexDigit (char e)
+ {
+ return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
+ }
+
+ 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) {
+ if (!hwnd.nc_expose_pending) {
+ hwnd.Queue.Paint.Enqueue(hwnd);
+ }
+ hwnd.expose_pending = true;
+ }
+ } else {
+ hwnd.AddNcInvalidArea (x, y, width, height);
+
+ if (!hwnd.nc_expose_pending) {
+ if (!hwnd.expose_pending) {
+ hwnd.Queue.Paint.Enqueue(hwnd);
+ }
+ hwnd.nc_expose_pending = true;
+ }
+ }
+ }
+
+ static Hwnd.Borders FrameExtents (IntPtr window)
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ Hwnd.Borders rect = new Hwnd.Borders ();
+
+ XGetWindowProperty (DisplayHandle, window, _NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if (prop != IntPtr.Zero) {
+ if (nitems.ToInt32 () == 4) {
+ rect.left = Marshal.ReadInt32 (prop, 0);
+ rect.right = Marshal.ReadInt32 (prop, IntPtr.Size);
+ rect.top = Marshal.ReadInt32 (prop, 2 * IntPtr.Size);
+ rect.bottom = Marshal.ReadInt32 (prop, 3 * IntPtr.Size);
+ }
+ XFree (prop);
+ }
+
+ return rect;
+ }
+
+ void AddConfigureNotify (XEvent xevent) {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window);
+
+ // Don't waste time
+ if (hwnd == null || hwnd.zombie) {
+ return;
+ }
+ if ((xevent.ConfigureEvent.window == hwnd.whole_window)/* && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)*/) {
+ if (hwnd.parent == null) {
+ // The location given by the event is not reliable between different wm's,
+ // so use an alternative way of getting it.
+ Point location = GetTopLevelWindowLocation (hwnd);
+ hwnd.x = location.X;
+ hwnd.y = location.Y;
+ }
+
+ // XXX this sucks. this isn't thread safe
+ Widget ctrl = Widget.FromHandle (hwnd.Handle);
+ Size TranslatedSize;
+ if (ctrl != null) {
+ TranslatedSize = TranslateXWindowSizeToWindowSize (ctrl.GetCreateParams (), xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
+ } else {
+ TranslatedSize = new Size (xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
+ }
+ hwnd.width = TranslatedSize.Width;
+ hwnd.height = TranslatedSize.Height;
+ hwnd.ClientRect = Rectangle.Empty;
+
+ DriverDebug ("AddConfigureNotify (hwnd.Handle = {1}, final hwnd.rect = {0}, reported rect={2})",
+ new Rectangle (hwnd.x, hwnd.y, hwnd.width, hwnd.height), hwnd.Handle,
+ new Rectangle (xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.width));
+ lock (hwnd.configure_lock) {
+ if (!hwnd.configure_pending) {
+ hwnd.Queue.EnqueueLocked (xevent);
+ hwnd.configure_pending = true;
+ }
+ }
+ }
+ // We drop configure events for Client windows
+ }
+
+ void ShowCaret() {
+ if ((Caret.gc == IntPtr.Zero) || Caret.On) {
+ return;
+ }
+ Caret.On = true;
+
+ lock (XlibLock) {
+ XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+ }
+
+ void HideCaret() {
+ if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
+ return;
+ }
+ Caret.On = false;
+
+ lock (XlibLock) {
+ XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+ }
+
+ int NextTimeout (ArrayList timers, DateTime now) {
+ int timeout = 0;
+
+ foreach (Timer timer in timers) {
+ int next = (int) (timer.Expires - now).TotalMilliseconds;
+ if (next < 0) {
+ return 0; // Have a timer that has already expired
+ }
+
+ if (next < timeout) {
+ timeout = next;
+ }
+ }
+ if (timeout < Timer.Minimum) {
+ timeout = Timer.Minimum;
+ }
+
+ if (timeout > 1000)
+ timeout = 1000;
+ return timeout;
+ }
+
+ void CheckTimers (ArrayList timers, DateTime now) {
+ int count;
+
+ count = timers.Count;
+
+ if (count == 0)
+ return;
+
+ for (int i = 0; i < timers.Count; i++) {
+ Timer timer;
+
+ timer = (Timer) timers [i];
+
+ if (timer.Enabled && timer.Expires <= now && !timer.Busy) {
+ // 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.Busy = true;
+ timer.Update (now);
+ timer.FireTick ();
+ timer.Busy = false;
+ }
+ }
+ }
+ }
+
+ void WaitForHwndMessage (Hwnd hwnd, Msg message) {
+ WaitForHwndMessage (hwnd, message, false);
+
+ }
+
+ void WaitForHwndMessage (Hwnd hwnd, Msg message, bool process) {
+ MSG msg = new MSG ();
+ XEventQueue queue;
+
+ queue = ThreadQueue(Thread.CurrentThread);
+
+ queue.DispatchIdle = false;
+
+ bool done = false;
+ string key = hwnd.Handle + ":" + message;
+ if (!messageHold.ContainsKey (key))
+ messageHold.Add (key, 1);
+ else
+ messageHold[key] = ((int)messageHold[key]) + 1;
+
+
+ do {
+
+ DebugHelper.WriteLine ("Waiting for message " + message + " on hwnd " + String.Format("0x{0:x}", hwnd.Handle.ToInt32 ()));
+ DebugHelper.Indent ();
+
+ if (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
+ if ((Msg)msg.message == Msg.WM_QUIT) {
+ PostQuitMessage (0);
+ done = true;
+ }
+ else {
+
+ DebugHelper.WriteLine ("PeekMessage got " + msg);
+
+ if (msg.hwnd == hwnd.Handle) {
+ if ((Msg)msg.message == message) {
+ if (process) {
+ TranslateMessage (ref msg);
+ DispatchMessage (ref msg);
+ }
+ break;
+ }
+ else if ((Msg)msg.message == Msg.WM_DESTROY)
+ done = true;
+ }
+
+ TranslateMessage (ref msg);
+ DispatchMessage (ref msg);
+ }
+ }
+
+ done = !messageHold.ContainsKey (key) || ((int)messageHold[key] < 1) || done;
+ } while (!done);
+
+ messageHold.Remove (key);
+
+ DebugHelper.Unindent ();
+ DebugHelper.WriteLine ("Finished waiting for " + key);
+
+ queue.DispatchIdle = true;
+
+ }
+
+ void MapWindow(Hwnd hwnd, WindowType windows) {
+ if (!hwnd.mapped) {
+ Form f = Widget.FromHandle(hwnd.Handle) as Form;
+ if (f != null) {
+ if (f.WindowState == FormWindowState.Normal) {
+ f.waiting_showwindow = true;
+ SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
+ }
+ }
+
+ // it's possible that our Hwnd is no
+ // longer valid after making that
+ // SendMessage call, so check here.
+ if (hwnd.zombie)
+ return;
+
+ if (hwnd.topmost) {
+ // Most window managers will respect the _NET_WM_STATE property.
+ // If not, use XMapRaised to map the window at the top level as
+ // a last ditch effort.
+ if ((windows & WindowType.Whole) != 0) {
+ XMapRaised(DisplayHandle, hwnd.whole_window);
+ }
+ if ((windows & WindowType.Client) != 0) {
+ XMapRaised(DisplayHandle, hwnd.client_window);
+ }
+ } else {
+ if ((windows & WindowType.Whole) != 0) {
+ XMapWindow(DisplayHandle, hwnd.whole_window);
+ }
+ if ((windows & WindowType.Client) != 0) {
+ XMapWindow(DisplayHandle, hwnd.client_window);
+ }
+ }
+
+ hwnd.mapped = true;
+
+ if (f != null) {
+ if (f.waiting_showwindow) {
+ WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
+ CreateParams cp = f.GetCreateParams();
+ if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_MDICHILD) &&
+ !StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
+ WaitForHwndMessage (hwnd, Msg.WM_ACTIVATE, true);
+ }
+ }
+ }
+ }
+ }
+
+ void UnmapWindow(Hwnd hwnd, WindowType windows) {
+ if (hwnd.mapped) {
+ Form f = null;
+ if (Widget.FromHandle(hwnd.Handle) is Form) {
+ f = Widget.FromHandle(hwnd.Handle) as Form;
+ if (f.WindowState == FormWindowState.Normal) {
+ f.waiting_showwindow = true;
+ SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ // it's possible that our Hwnd is no
+ // longer valid after making that
+ // SendMessage call, so check here.
+ // FIXME: it is likely wrong, as it has already sent WM_SHOWWINDOW
+ if (hwnd.zombie)
+ return;
+
+ if ((windows & WindowType.Client) != 0) {
+ XUnmapWindow(DisplayHandle, hwnd.client_window);
+ }
+ if ((windows & WindowType.Whole) != 0) {
+ XUnmapWindow(DisplayHandle, hwnd.whole_window);
+ }
+
+ hwnd.mapped = false;
+
+ if (f != null) {
+ if (f.waiting_showwindow) {
+ WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
+ CreateParams cp = f.GetCreateParams();
+ if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_MDICHILD) &&
+ !StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
+ WaitForHwndMessage (hwnd, Msg.WM_ACTIVATE, true);
+ }
+ }
+ }
+ }
+ }
+
+ void UpdateMessageQueue (XEventQueue queue) {
+ UpdateMessageQueue(queue, true);
+ }
+
+ void UpdateMessageQueue (XEventQueue queue, bool allowIdle) {
+ DateTime now;
+ int pending;
+ Hwnd hwnd;
+
+ now = DateTime.UtcNow;
+
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+
+ if (pending == 0 && allowIdle) {
+ if ((queue == null || queue.DispatchIdle) && Idle != null) {
+ Idle (this, EventArgs.Empty);
+ }
+
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+
+ if (pending == 0) {
+ int timeout = 0;
+
+ if (queue != null) {
+ if (queue.Paint.Count > 0)
+ return;
+
+ timeout = NextTimeout (queue.timer_list, now);
+ }
+
+ if (timeout > 0) {
+ #if __MonoCS__
+ int length = pollfds.Length - 1;
+ lock (wake_waiting_lock) {
+ if (wake_waiting == false) {
+ length ++;
+ wake_waiting = true;
+ }
+ }
+
+ Syscall.poll (pollfds, (uint)length, timeout);
+ // Clean out buffer, so we're not busy-looping on the same data
+ if (length == pollfds.Length) {
+ if (pollfds[1].revents != 0)
+ wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
+ lock (wake_waiting_lock) {
+ wake_waiting = false;
+ }
+ }
+ #endif
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+ }
+
+ if (queue != null)
+ CheckTimers (queue.timer_list, now);
+
+ while (true) {
+ XEvent xevent = new XEvent ();
+
+ lock (XlibLock) {
+ if (XPending (DisplayHandle) == 0)
+ break;
+
+ XNextEvent (DisplayHandle, ref xevent);
+
+ if (xevent.AnyEvent.type == XEventName.KeyPress ||
+ xevent.AnyEvent.type == XEventName.KeyRelease) {
+ // PreFilter() handles "shift key state updates.
+ Keyboard.PreFilter (xevent);
+ if (XFilterEvent (ref xevent, Keyboard.ClientWindow)) {
+ // probably here we could raise WM_IME_KEYDOWN and
+ // WM_IME_KEYUP, but I'm not sure it is worthy.
+ continue;
+ }
+ }
+ else if (XFilterEvent (ref xevent, IntPtr.Zero))
+ continue;
+ }
+
+ hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
+ if (hwnd == null)
+ continue;
+
+ DebugHelper.WriteLine ("UpdateMessageQueue got Event: " + xevent.ToString ());
+
+ switch (xevent.type) {
+ case XEventName.Expose:
+ AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ break;
+
+ case XEventName.SelectionClear: {
+ // Should we do something?
+ break;
+ }
+
+ case XEventName.SelectionRequest: {
+ if (Dnd.HandleSelectionRequestEvent (ref xevent))
+ break;
+ XEvent sel_event;
+
+ sel_event = new XEvent();
+ sel_event.SelectionEvent.type = XEventName.SelectionNotify;
+ sel_event.SelectionEvent.send_event = true;
+ sel_event.SelectionEvent.display = DisplayHandle;
+ sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
+ sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
+ sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
+ sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
+ sel_event.SelectionEvent.property = IntPtr.Zero;
+
+ IntPtr format_atom = xevent.SelectionRequestEvent.target;
+
+ // Seems that some apps support asking for supported types
+ if (format_atom == TARGETS) {
+ int[] atoms;
+ int atom_count;
+
+ atoms = new int[5];
+ atom_count = 0;
+
+ if (Clipboard.IsSourceText) {
+ atoms[atom_count++] = (int)Atom.XA_STRING;
+ atoms[atom_count++] = (int)OEMTEXT;
+ atoms[atom_count++] = (int)UTF8_STRING;
+ atoms[atom_count++] = (int)UTF16_STRING;
+ atoms[atom_count++] = (int)RICHTEXTFORMAT;
+ } else if (Clipboard.IsSourceImage) {
+ atoms[atom_count++] = (int)Atom.XA_PIXMAP;
+ atoms[atom_count++] = (int)Atom.XA_BITMAP;
+ } else {
+ // FIXME - handle other types
+ }
+
+ XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property,
+ (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
+ sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
+ } else if (format_atom == (IntPtr)RICHTEXTFORMAT) {
+ string rtf_text = Clipboard.GetRtfText ();
+ if (rtf_text != null) {
+ // The RTF spec mentions that ascii is enough to contain it
+ Byte [] bytes = Encoding.ASCII.GetBytes (rtf_text);
+ int buflen = bytes.Length;
+ IntPtr buffer = Marshal.AllocHGlobal (buflen);
+
+ for (int i = 0; i < buflen; i++)
+ Marshal.WriteByte (buffer, i, bytes[i]);
+
+ XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property,
+ (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
+ sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
+ Marshal.FreeHGlobal(buffer);
+ }
+ } else if (Clipboard.IsSourceText &&
+ (format_atom == (IntPtr)Atom.XA_STRING
+ || format_atom == OEMTEXT
+ || format_atom == UTF16_STRING
+ || format_atom == UTF8_STRING)) {
+ IntPtr buffer = IntPtr.Zero;
+ int buflen;
+ Encoding encoding = null;
+
+ buflen = 0;
+
+ // Select an encoding depending on the target
+ IntPtr target_atom = xevent.SelectionRequestEvent.target;
+ if (target_atom == (IntPtr)Atom.XA_STRING || target_atom == OEMTEXT)
+ // FIXME - EOMTEXT should encode into ISO2022
+ encoding = Encoding.ASCII;
+ else if (target_atom == UTF16_STRING)
+ encoding = Encoding.Unicode;
+ else if (target_atom == UTF8_STRING)
+ encoding = Encoding.UTF8;
+
+ Byte [] bytes;
+
+ bytes = encoding.GetBytes (Clipboard.GetPlainText ());
+ buffer = Marshal.AllocHGlobal (bytes.Length);
+ buflen = bytes.Length;
+
+ for (int i = 0; i < buflen; i++)
+ Marshal.WriteByte (buffer, i, bytes [i]);
+
+ if (buffer != IntPtr.Zero) {
+ XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
+ sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
+ Marshal.FreeHGlobal(buffer);
+ }
+ } else if (Clipboard.GetSource (format_atom.ToInt32 ()) != null) { // check if we have an available value of this format
+ if (DataFormats.GetFormat (format_atom.ToInt32 ()).is_serializable) {
+ object serializable = Clipboard.GetSource (format_atom.ToInt32 ());
+
+ BinaryFormatter formatter = new BinaryFormatter ();
+ MemoryStream memory_stream = new MemoryStream ();
+ formatter.Serialize (memory_stream, serializable);
+
+ int buflen = (int)memory_stream.Length;
+ IntPtr buffer = Marshal.AllocHGlobal (buflen);
+ memory_stream.Position = 0;
+ for (int i = 0; i < buflen; i++)
+ Marshal.WriteByte (buffer, i, (byte)memory_stream.ReadByte ());
+ memory_stream.Close ();
+
+ XChangeProperty (DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target,
+ 8, PropertyMode.Replace, buffer, buflen);
+ sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
+ Marshal.FreeHGlobal (buffer);
+ }
+
+ } else if (Clipboard.IsSourceImage) {
+ if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
+ // FIXME - convert image and store as property
+ } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
+ // FIXME - convert image and store as property
+ }
+ }
+
+ XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event);
+ break;
+ }
+
+ case XEventName.SelectionNotify: {
+ if (Clipboard.Enumerating) {
+ Clipboard.Enumerating = false;
+ if (xevent.SelectionEvent.property != IntPtr.Zero) {
+ XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property);
+ if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) {
+ Clipboard.Formats.Add(xevent.SelectionEvent.property);
+ DriverDebug("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
+ }
+ }
+ } else if (Clipboard.Retrieving) {
+ Clipboard.Retrieving = false;
+ if (xevent.SelectionEvent.property != IntPtr.Zero) {
+ TranslatePropertyToClipboard(xevent.SelectionEvent.property);
+ } else {
+ Clipboard.ClearSources ();
+ Clipboard.Item = null;
+ }
+ } else {
+ Dnd.HandleSelectionNotifyEvent (ref xevent);
+ }
+ break;
+ }
+
+ case XEventName.KeyRelease:
+ if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) {
+ XEvent nextevent = new XEvent ();
+
+ XPeekEvent (DisplayHandle, ref nextevent);
+
+ if (nextevent.type == XEventName.KeyPress &&
+ nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
+ nextevent.KeyEvent.time == xevent.KeyEvent.time) {
+ continue;
+ }
+ }
+ goto case XEventName.KeyPress;
+
+ case XEventName.MotionNotify: {
+ XEvent peek;
+
+ /* we can't do motion compression across threads, so just punt if we don't match up */
+ if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) {
+ peek = hwnd.Queue.Peek();
+ if (peek.AnyEvent.type == XEventName.MotionNotify) {
+ continue;
+ }
+ }
+ goto case XEventName.KeyPress;
+ }
+
+ case XEventName.KeyPress:
+ hwnd.Queue.EnqueueLocked (xevent);
+ /* Process KeyPresses immediately. Otherwise multiple Compose messages as a result of a
+ * single physical keypress are not processed correctly */
+ return;
+ case XEventName.ButtonPress:
+ case XEventName.ButtonRelease:
+ case XEventName.EnterNotify:
+ case XEventName.LeaveNotify:
+ case XEventName.CreateNotify:
+ case XEventName.DestroyNotify:
+ case XEventName.FocusIn:
+ case XEventName.FocusOut:
+ case XEventName.ClientMessage:
+ case XEventName.ReparentNotify:
+ case XEventName.MapNotify:
+ case XEventName.UnmapNotify:
+ hwnd.Queue.EnqueueLocked (xevent);
+ break;
+
+ case XEventName.ConfigureNotify:
+ AddConfigureNotify(xevent);
+ break;
+
+ case XEventName.PropertyNotify:
+ DriverDebug ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
+ if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr prev_active;
+
+ prev_active = ActiveWindow;
+ XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
+ ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop));
+ XFree(prop);
+
+ DebugHelper.WriteLine ("PropertyNotify: _NET_ACTIVE_WINDOW: previous = 0x{0:x}, new = 0x{1:x}", prev_active.ToInt32 (), ActiveWindow.ToInt32 ());
+
+ if (prev_active != ActiveWindow) {
+ if (prev_active != IntPtr.Zero) {
+ PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
+ }
+ if (ActiveWindow != IntPtr.Zero) {
+ PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
+ }
+ }
+ if (ModalWindows.Count == 0) {
+ break;
+ } else {
+ // Modality Handling
+ //
+ // If there is a modal window on the stack and the new active
+ // window is MWF window, but not the modal one and not a non-modal
+ // child of the modal one, switch back to the modal window.
+ //
+ // To identify if a non-modal form is child of a modal form
+ // we match their ApplicationContexts, which will be the same.
+ // This is because each modal form runs the loop with a
+ // new ApplicationContext, which is inherited by the non-modal
+ // forms.
+
+ Form activeForm = Widget.FromHandle (ActiveWindow) as Form;
+ if (activeForm != null) {
+ Form modalForm = Widget.FromHandle ((IntPtr)ModalWindows.Peek()) as Form;
+ if (ActiveWindow != (IntPtr)ModalWindows.Peek() &&
+ (modalForm == null || activeForm.context == modalForm.context)) {
+ Activate((IntPtr)ModalWindows.Peek());
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if (xevent.PropertyEvent.atom == _NET_WM_STATE) {
+ // invalidate our cache - we'll query again the next time someone does GetWindowState.
+ hwnd.cached_window_state = (FormWindowState)(-1);
+ PostMessage (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ }
+ break;
+
+ }
+ }
+ }
+
+ 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;
+ }
+ IntPtr XGetParent(IntPtr handle) {
+ IntPtr Root;
+ IntPtr Parent;
+ IntPtr Children;
+ int ChildCount;
+
+ lock (XlibLock) {
+ XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount);
+ }
+
+ if (Children!=IntPtr.Zero) {
+ lock (XlibLock) {
+ XFree(Children);
+ }
+ }
+ return Parent;
+ }
+
+ int HandleError (IntPtr display, ref XErrorEvent error_event)
+ {
+ // we need to workaround a problem with the
+ // ordering of destruction of Drawables and
+ // Pictures that exists between cairo and
+ // RENDER on the server.
+ if (error_event.request_code == (XRequest)render_major_opcode
+ && error_event.minor_code == 7 /* X_RenderFreePicture from render.h */
+ && error_event.error_code == render_first_error + 1 /* BadPicture from render.h */) {
+ return 0;
+ }
+
+ if (ErrorExceptions) {
+ XUngrabPointer (display, IntPtr.Zero);
+ throw new XException (error_event.display, error_event.resourceid,
+ error_event.serial, error_event.error_code,
+ error_event.request_code, error_event.minor_code);
+ } else {
+ Console.WriteLine("X11 Error encountered: {0}{1}\n",
+ XException.GetMessage (error_event.display, error_event.resourceid,
+ error_event.serial, error_event.error_code,
+ error_event.request_code, error_event.minor_code),
+ Environment.StackTrace);
+ }
+ return 0;
+ }
+
+ void AccumulateDestroyedHandles (Widget c, ArrayList list)
+ {
+ DebugHelper.Enter ();
+ if (c != null) {
+
+ Widget[] Widgets = c.Widgets.GetAllWidgets ();
+
+ DebugHelper.WriteLine ("Checking Widget:0x{0:x}", c.IsHandleCreated ? c.Handle.ToInt32() : 0);
+
+ if (c.IsHandleCreated && !c.IsDisposed) {
+ Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle);
+
+ DriverDebug (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
+ DriverDebug (" + parent X window is {0:X}", XGetParent (hwnd.whole_window).ToInt32());
+
+ list.Add (hwnd);
+ CleanupCachedWindows (hwnd);
+ }
+
+ for (int i = 0; i < Widgets.Length; i ++) {
+ AccumulateDestroyedHandles (Widgets[i], list);
+ }
+ }
+ DebugHelper.Leave ();
+ }
+
+ 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);
+ }
+
+ 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 = TranslateClientRectangleToXClientRectangle (hwnd);
+
+ if (hwnd.visible) {
+ MoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
+ }
+
+ AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
+ }
+ #endregion // Methods
+
+ #region Callbacks
+ void MouseHover(object sender, EventArgs e) {
+ XEvent xevent;
+ Hwnd hwnd;
+
+ HoverState.Timer.Enabled = false;
+
+ if (HoverState.Window != IntPtr.Zero) {
+ hwnd = Hwnd.GetObjectFromWindow(HoverState.Window);
+ if (hwnd != null) {
+ xevent = new XEvent ();
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = DisplayHandle;
+ xevent.ClientMessageEvent.window = HoverState.Window;
+ xevent.ClientMessageEvent.message_type = HoverState.Atom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
+
+ hwnd.Queue.EnqueueLocked (xevent);
+
+ WakeupMain ();
+ }
+ }
+ }
+
+ void CaretCallback(object sender, EventArgs e) {
+ if (Caret.Paused) {
+ return;
+ }
+ Caret.On = !Caret.On;
+
+ XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+ #endregion // Callbacks
+
+ #region Public Properties
+
+ internal override int CaptionHeight {
+ get {
+ return 19;
+ }
+ }
+
+ internal override Size CursorSize {
+ get {
+ int x;
+ int y;
+
+ if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) {
+ return new Size(x, y);
+ } else {
+ return new Size(16, 16);
+ }
+ }
+ }
+
+ internal override bool DragFullWindows {
+ get {
+ return true;
+ }
+ }
+
+ internal override Size DragSize {
+ get {
+ return new Size(4, 4);
+ }
+ }
+
+ internal override Size FrameBorderSize {
+ get {
+ return new Size (4, 4);
+ }
+ }
+
+ internal override Size IconSize {
+ get {
+ IntPtr list;
+ XIconSize size;
+ int count;
+
+ if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
+ long current;
+ int largest;
+
+ current = (long)list;
+ largest = 0;
+
+ size = new XIconSize();
+
+ for (int i = 0; i < count; i++) {
+ size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
+ current += Marshal.SizeOf(size);
+
+ // Look for our preferred size
+ if (size.min_width == 32) {
+ XFree(list);
+ return new Size(32, 32);
+ }
+
+ if (size.max_width == 32) {
+ XFree(list);
+ return new Size(32, 32);
+ }
+
+ if (size.min_width < 32 && size.max_width > 32) {
+ int x;
+
+ // check if we can fit one
+ x = size.min_width;
+ while (x < size.max_width) {
+ x += size.width_inc;
+ if (x == 32) {
+ XFree(list);
+ return new Size(32, 32);
+ }
+ }
+ }
+
+ if (largest < size.max_width) {
+ largest = size.max_width;
+ }
+ }
+
+ // We didn't find a match or we wouldn't be here
+ return new Size(largest, largest);
+
+ } else {
+ return new Size(32, 32);
+ }
+ }
+ }
+
+ internal override int KeyboardSpeed {
+ get{
+ //
+ // A lot harder: need to do:
+ // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
+ // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
+ // XkbGetWidgets(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
+ //
+ // And from that we can tell the repetition rate
+ //
+ // Notice, the values must map to:
+ // [0, 31] which maps to 2.5 to 30 repetitions per second.
+ //
+ return 0;
+ }
+ }
+
+ internal override int KeyboardDelay {
+ get {
+ //
+ // Return values must range from 0 to 4, 0 meaning 250ms,
+ // and 4 meaning 1000 ms.
+ //
+ return 1; // ie, 500 ms
+ }
+ }
+
+ internal override Size MaxWindowTrackSize {
+ get {
+ return new Size (WorkingArea.Width, WorkingArea.Height);
+ }
+ }
+
+ internal override bool MenuAccessKeysUnderlined {
+ get {
+ return false;
+ }
+ }
+
+ internal override Size MinimizedWindowSpacingSize {
+ get {
+ return new Size(1, 1);
+ }
+ }
+
+ internal override Size MinimumWindowSize {
+ get {
+ return new Size(110, 22);
+ }
+ }
+
+ internal override Size MinimumFixedToolWindowSize {
+ get { return new Size (27, 22); }
+ }
+
+ internal override Size MinimumSizeableToolWindowSize {
+ get { return new Size (37, 22); }
+ }
+
+ internal override Size MinimumNoBorderWindowSize {
+ get { return new Size (2, 2); }
+ }
+
+ internal override Keys ModifierKeys {
+ get {
+ return Keyboard.ModifierKeys;
+ }
+ }
+
+ internal override Size SmallIconSize {
+ get {
+ IntPtr list;
+ XIconSize size;
+ int count;
+
+ if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
+ long current;
+ int smallest;
+
+ current = (long)list;
+ smallest = 0;
+
+ size = new XIconSize();
+
+ for (int i = 0; i < count; i++) {
+ size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
+ current += Marshal.SizeOf(size);
+
+ // Look for our preferred size
+ if (size.min_width == 16) {
+ XFree(list);
+ return new Size(16, 16);
+ }
+
+ if (size.max_width == 16) {
+ XFree(list);
+ return new Size(16, 16);
+ }
+
+ if (size.min_width < 16 && size.max_width > 16) {
+ int x;
+
+ // check if we can fit one
+ x = size.min_width;
+ while (x < size.max_width) {
+ x += size.width_inc;
+ if (x == 16) {
+ XFree(list);
+ return new Size(16, 16);
+ }
+ }
+ }
+
+ if (smallest == 0 || smallest > size.min_width) {
+ smallest = size.min_width;
+ }
+ }
+
+ // We didn't find a match or we wouldn't be here
+ return new Size(smallest, smallest);
+
+ } else {
+ return new Size(16, 16);
+ }
+ }
+ }
+
+ internal override int MouseButtonCount {
+ get {
+ return 3;
+ }
+ }
+
+ internal override bool MouseButtonsSwapped {
+ get {
+ return false; // FIXME - how to detect?
+ }
+ }
+
+ internal override Point MousePosition {
+ get {
+ return mouse_position;
+ }
+ }
+
+ internal override Size MouseHoverSize {
+ get {
+ return new Size (1, 1);
+ }
+ }
+
+ internal override int MouseHoverTime {
+ get {
+ return HoverState.Interval;
+ }
+ }
+
+
+
+ internal override bool MouseWheelPresent {
+ get {
+ return true; // FIXME - how to detect?
+ }
+ }
+
+ internal override MouseButtons MouseButtons {
+ get {
+ return MouseState;
+ }
+ }
+
+ internal override Rectangle VirtualScreen {
+ get {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ int width;
+ int height;
+
+ XGetWindowProperty(DisplayHandle, RootWindow, _NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((long)nitems < 2)
+ goto failsafe;
+
+ width = Marshal.ReadIntPtr(prop, 0).ToInt32();
+ height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
+
+ XFree(prop);
+
+ return new Rectangle(0, 0, width, height);
+
+ failsafe:
+ XWindowAttributes attributes=new XWindowAttributes();
+
+ lock (XlibLock) {
+ XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
+ }
+
+ return new Rectangle(0, 0, attributes.width, attributes.height);
+ }
+ }
+
+ internal override Rectangle WorkingArea {
+ get {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ int width;
+ int height;
+ int current_desktop;
+ int x;
+ int y;
+
+ XGetWindowProperty(DisplayHandle, RootWindow, _NET_CURRENT_DESKTOP, IntPtr.Zero, new IntPtr(1), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((long)nitems < 1) {
+ goto failsafe;
+ }
+
+ current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
+ XFree(prop);
+
+ XGetWindowProperty(DisplayHandle, RootWindow, _NET_WORKAREA, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((long)nitems < 4 * (current_desktop + 1)) {
+ goto failsafe;
+ }
+
+ x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
+ y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
+ width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
+ height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
+ XFree(prop);
+
+ return new Rectangle(x, y, width, height);
+
+ failsafe:
+ XWindowAttributes attributes=new XWindowAttributes();
+
+ lock (XlibLock) {
+ XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
+ }
+
+ return new Rectangle(0, 0, attributes.width, attributes.height);
+ }
+ }
+
+ internal override Screen[] AllScreens {
+ get {
+ if (!XineramaIsActive (DisplayHandle))
+ return null;
+ int nScreens;
+ IntPtr xineramaScreens = XineramaQueryScreens (DisplayHandle, out nScreens);
+ var screens = new Screen [nScreens];
+ IntPtr current = xineramaScreens;
+ for (int i = 0; i < nScreens; i++) {
+ var screen = (XineramaScreenInfo)Marshal.PtrToStructure (current,
+ typeof (XineramaScreenInfo));
+ var screenRect = new Rectangle (screen.x_org, screen.y_org, screen.width,
+ screen.height);
+ var name = string.Format ("Display {0}", screen.screen_number);
+ screens [i] = new Screen (i == 0, name, screenRect, screenRect);
+ current = (IntPtr)( (ulong)current + (ulong)Marshal.SizeOf(typeof (XineramaScreenInfo)));
+ }
+ XFree (xineramaScreens);
+ return screens;
+ }
+ }
+
+ internal override bool ThemesEnabled {
+ get {
+ return XplatUIX11.themes_enabled;
+ }
+ }
+
+
+ #endregion // Public properties
+
+ #region Public Static Methods
+ internal override void RaiseIdle (EventArgs e)
+ {
+ if (Idle != null)
+ Idle (this, e);
+ }
+
+ internal override IntPtr InitializeDriver()
+ {
+ lock (this) {
+ if (DisplayHandle==IntPtr.Zero) {
+ SetDisplay(XOpenDisplay(IntPtr.Zero));
+ }
+ }
+ return IntPtr.Zero;
+ }
+
+ internal override void ShutdownDriver(IntPtr token)
+ {
+ lock (this) {
+ if (DisplayHandle!=IntPtr.Zero) {
+ XCloseDisplay(DisplayHandle);
+ DisplayHandle=IntPtr.Zero;
+ }
+ }
+ }
+
+ internal override void EnableThemes()
+ {
+ themes_enabled = true;
+ }
+
+
+ internal override void Activate(IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd != null) {
+ lock (XlibLock) {
+ if (true /* the window manager supports NET_ACTIVE_WINDOW */) {
+ SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
+ XEventQueue q = null;
+ lock (unattached_timer_list) {
+ foreach (Timer t in unattached_timer_list) {
+ if (q == null)
+ q= (XEventQueue) MessageQueues [Thread.CurrentThread];
+ t.thread = q.Thread;
+ q.timer_list.Add (t);
+ }
+ unattached_timer_list.Clear ();
+ }
+ }
+// else {
+// XRaiseWindow(DisplayHandle, handle);
+// }
+ }
+ }
+ }
+
+ internal override void AudibleAlert(AlertType alert)
+ {
+ XBell(DisplayHandle, 0);
+ return;
+ }
+
+
+ internal override void CaretVisible(IntPtr handle, bool visible)
+ {
+ if (Caret.Hwnd == handle) {
+ if (visible) {
+ if (!Caret.Visible) {
+ Caret.Visible = true;
+ ShowCaret();
+ Caret.Timer.Start();
+ }
+ } else {
+ Caret.Visible = false;
+ 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)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates(handle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ internal override int[] ClipboardAvailableFormats(IntPtr handle)
+ {
+ DataFormats.Format f;
+ int[] result;
+
+ f = DataFormats.Format.List;
+
+ if (XGetSelectionOwner(DisplayHandle, CLIPBOARD) == IntPtr.Zero) {
+ return null;
+ }
+
+ Clipboard.Formats = new ArrayList();
+
+ while (f != null) {
+ XConvertSelection(DisplayHandle, CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent, IntPtr.Zero);
+
+ var timeToWaitForSelectionFormats = TimeSpan.FromSeconds(4);
+ var startTime = DateTime.Now;
+ Clipboard.Enumerating = true;
+ while (Clipboard.Enumerating) {
+ UpdateMessageQueue(null, false);
+
+ if (DateTime.Now - startTime > timeToWaitForSelectionFormats)
+ break;
+ }
+ f = f.Next;
+ }
+
+ result = new int[Clipboard.Formats.Count];
+
+ for (int i = 0; i < Clipboard.Formats.Count; i++) {
+ result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
+ }
+
+ Clipboard.Formats = null;
+ return result;
+ }
+
+ internal override void ClipboardClose(IntPtr handle)
+ {
+ if (handle != ClipMagic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+ return;
+ }
+
+ internal override int ClipboardGetID(IntPtr handle, string format)
+ {
+ if (handle != ClipMagic) {
+ throw new ArgumentException("handle is not a valid clipboard handle");
+ }
+
+ if (format == "Text" ) return (int)Atom.XA_STRING;
+ else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP;
+ //else if (format == "MetaFilePict" ) return 3;
+ //else if (format == "SymbolicLink" ) return 4;
+ //else if (format == "DataInterchangeFormat" ) return 5;
+ //else if (format == "Tiff" ) return 6;
+ else if (format == "OEMText" ) return OEMTEXT.ToInt32();
+ else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP;
+ else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless
+ //else if (format == "PenData" ) return 10;
+ //else if (format == "RiffAudio" ) return 11;
+ //else if (format == "WaveAudio" ) return 12;
+ else if (format == "UnicodeText" ) return UTF16_STRING.ToInt32();
+ //else if (format == "EnhancedMetafile" ) return 14;
+ //else if (format == "FileDrop" ) return 15;
+ //else if (format == "Locale" ) return 16;
+ else if (format == "Rich Text Format") return RICHTEXTFORMAT.ToInt32 ();
+
+ return XInternAtom(DisplayHandle, format, false).ToInt32();
+ }
+
+ internal override IntPtr ClipboardOpen(bool primary_selection)
+ {
+ if (!primary_selection)
+ ClipMagic = CLIPBOARD;
+ else
+ ClipMagic = PRIMARY;
+ return ClipMagic;
+ }
+
+ internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter)
+ {
+ XConvertSelection(DisplayHandle, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
+
+ Clipboard.Retrieving = true;
+ while (Clipboard.Retrieving) {
+ UpdateMessageQueue(null, false);
+ }
+
+ return Clipboard.Item;
+ }
+
+ internal override void ClipboardStore (IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy)
+ {
+ Clipboard.Converter = converter;
+
+ if (obj != null) {
+ Clipboard.AddSource (type, obj);
+ XSetSelectionOwner (DisplayHandle, CLIPBOARD, FosterParent, IntPtr.Zero);
+
+ if (copy) {
+ try {
+ var clipboardAtom = gdk_atom_intern ("CLIPBOARD", true);
+ var clipboard = gtk_clipboard_get (clipboardAtom);
+ if (clipboard != null) {
+ // for now we only store text
+ var text = Clipboard.GetRtfText ();
+ if (string.IsNullOrEmpty (text))
+ text = Clipboard.GetPlainText ();
+ if (!string.IsNullOrEmpty (text)) {
+ gtk_clipboard_set_text (clipboard, text, text.Length);
+ gtk_clipboard_store (clipboard);
+ }
+ }
+ } catch {
+ // ignore any errors - most likely because gtk isn't installed?
+ }
+ }
+ } else {
+ // Clearing the selection
+ Clipboard.ClearSources ();
+ XSetSelectionOwner (DisplayHandle, CLIPBOARD, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ internal override void CreateCaret (IntPtr handle, int width, int height)
+ {
+ XGCValues gc_values;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (Caret.Hwnd != IntPtr.Zero) {
+ DestroyCaret(Caret.Hwnd);
+ }
+
+ Caret.Hwnd = handle;
+ Caret.Window = hwnd.client_window;
+ Caret.Width = width;
+ Caret.Height = height;
+ Caret.Visible = false;
+ Caret.On = false;
+
+ gc_values = new XGCValues();
+ gc_values.line_width = width;
+
+ Caret.gc = XCreateGC(DisplayHandle, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
+ if (Caret.gc == IntPtr.Zero) {
+ Caret.Hwnd = IntPtr.Zero;
+ return;
+ }
+
+ XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert);
+ }
+
+ internal override IntPtr CreateWindow (CreateParams cp)
+ {
+ XSetWindowAttributes Attributes;
+ Hwnd hwnd;
+ Hwnd parent_hwnd = null;
+ int X;
+ int Y;
+ int Width;
+ int Height;
+ IntPtr ParentHandle;
+ IntPtr WholeWindow;
+ IntPtr ClientWindow;
+ SetWindowValuemask ValueMask;
+
+ hwnd = new Hwnd();
+
+ Attributes = new XSetWindowAttributes();
+ X = cp.X;
+ Y = cp.Y;
+ Width = cp.Width;
+ Height = cp.Height;
+
+ 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)) {
+ // We need to use our foster parent window until this poor child gets it's parent assigned
+ ParentHandle=FosterParent;
+ } else {
+ ParentHandle=RootWindow;
+ }
+ }
+
+ // Set the default location location for forms.
+ Point next;
+ if (cp.control is Form) {
+ next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd);
+ X = next.X;
+ Y = next.Y;
+ }
+ ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
+
+ Attributes.bit_gravity = Gravity.NorthWestGravity;
+ Attributes.win_gravity = Gravity.NorthWestGravity;
+
+ // Save what's under the toolwindow
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
+ Attributes.save_under = true;
+ ValueMask |= SetWindowValuemask.SaveUnder;
+ }
+
+
+ // If we're a popup without caption we override the WM
+ if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
+ Attributes.override_redirect = true;
+ ValueMask |= SetWindowValuemask.OverrideRedirect;
+ }
+
+ 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;
+
+ if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) {
+ hwnd.enabled = false;
+ }
+
+ ClientWindow = IntPtr.Zero;
+
+ Size XWindowSize = TranslateWindowSizeToXWindowSize (cp);
+ Rectangle XClientRect = TranslateClientRectangleToXClientRectangle (hwnd, cp.control);
+
+ lock (XlibLock) {
+ WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, XWindowSize.Width, XWindowSize.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes);
+ if (WholeWindow != IntPtr.Zero) {
+ ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
+
+ if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) {
+ ValueMask = SetWindowValuemask.ColorMap;
+ Attributes.colormap = CustomColormap;
+ }
+ ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, XClientRect.X, XClientRect.Y, XClientRect.Width, XClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes);
+ }
+ }
+
+ if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) {
+ throw new Exception("Could not create X11 windows");
+ }
+
+ hwnd.Queue = ThreadQueue(Thread.CurrentThread);
+ hwnd.WholeWindow = WholeWindow;
+ hwnd.ClientWindow = ClientWindow;
+
+ DriverDebug("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle);
+
+ if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
+ if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
+ XSizeHints hints;
+
+ hints = new XSizeHints();
+ hints.x = X;
+ hints.y = Y;
+ hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition);
+ XSetWMNormalHints(DisplayHandle, WholeWindow, ref hints);
+ }
+ }
+
+ lock (XlibLock) {
+ XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
+ if (hwnd.whole_window != hwnd.client_window)
+ XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | Keyboard.KeyEventMask)));
+ }
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST))
+ SetTopmost(hwnd.whole_window, true);
+
+ SetWMStyles(hwnd, cp);
+
+ // set the group leader
+ XWMHints wm_hints = new XWMHints ();
+
+ wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint);
+ wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
+ wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState;
+
+ if (ParentHandle != RootWindow) {
+ wm_hints.window_group = hwnd.whole_window;
+ } else {
+ wm_hints.window_group = ParentHandle;
+ }
+
+ lock (XlibLock) {
+ XSetWMHints(DisplayHandle, hwnd.whole_window, ref wm_hints );
+ }
+
+ 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);
+ }
+
+ // for now make all windows dnd enabled
+ Dnd.SetAllowDrop (hwnd, true);
+
+ // Set caption/window title
+ 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)) {
+ hwnd.visible = true;
+ MapWindow(hwnd, WindowType.Both);
+ if (!(Widget.FromHandle(hwnd.Handle) is Form))
+ SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
+ }
+
+ 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 IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
+ {
+ IntPtr cursor;
+ Bitmap cursor_bitmap;
+ Bitmap cursor_mask;
+ Byte[] cursor_bits;
+ Byte[] mask_bits;
+ Color c_pixel;
+ Color m_pixel;
+ int width;
+ int height;
+ IntPtr cursor_pixmap;
+ IntPtr mask_pixmap;
+ XColor fg;
+ XColor bg;
+ bool and;
+ bool xor;
+
+ if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) {
+ return IntPtr.Zero;
+ }
+
+ // Win32 only allows creation cursors of a certain size
+ if ((bitmap.Width != width) || (bitmap.Width != height)) {
+ cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
+ cursor_mask = new Bitmap(mask, new Size(width, height));
+ } else {
+ cursor_bitmap = bitmap;
+ cursor_mask = mask;
+ }
+
+ width = cursor_bitmap.Width;
+ height = cursor_bitmap.Height;
+
+ cursor_bits = new Byte[(width / 8) * height];
+ mask_bits = new Byte[(width / 8) * height];
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ c_pixel = cursor_bitmap.GetPixel(x, y);
+ m_pixel = cursor_mask.GetPixel(x, y);
+
+ and = c_pixel == cursor_pixel;
+ xor = m_pixel == mask_pixel;
+
+ if (!and && !xor) {
+ // Black
+ // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
+ mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+ } else if (and && !xor) {
+ // White
+ cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+ mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+#if notneeded
+ } else if (and && !xor) {
+ // Screen
+ } else if (and && xor) {
+ // Inverse Screen
+
+ // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
+ // we want both to be 0 so nothing to be done
+ //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
+ //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
+#endif
+ }
+ }
+ }
+
+ cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
+ mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
+ fg = new XColor();
+ bg = new XColor();
+
+ fg.pixel = XWhitePixel(DisplayHandle, ScreenNo);
+ fg.red = (ushort)65535;
+ fg.green = (ushort)65535;
+ fg.blue = (ushort)65535;
+
+ bg.pixel = XBlackPixel(DisplayHandle, ScreenNo);
+
+ cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
+
+ XFreePixmap(DisplayHandle, cursor_pixmap);
+ XFreePixmap(DisplayHandle, mask_pixmap);
+
+ return cursor;
+ }
+
+ internal override Bitmap DefineStdCursorBitmap (StdCursor id)
+ {
+ CursorFontShape shape;
+ string name;
+ IntPtr theme;
+ int size;
+ Bitmap bmp = null;
+
+ try {
+ shape = StdCursorToFontShape (id);
+ name = shape.ToString ().Replace ("XC_", string.Empty);
+ size = XcursorGetDefaultSize (DisplayHandle);
+ theme = XcursorGetTheme (DisplayHandle);
+ IntPtr images_ptr = XcursorLibraryLoadImages (name, theme, size);
+ DriverDebug ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr);
+
+ if (images_ptr == IntPtr.Zero) {
+ return null;
+ }
+
+ XcursorImages images = (XcursorImages) Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
+ DriverDebug ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
+
+ if (images.nimage > 0) {
+ // We only care about the first image.
+ XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
+
+ DriverDebug ("DefineStdCursorBitmap, loaded image <size={0}, height={1}, width={2}, xhot={3}, yhot={4}, pixels={5}", image.size, image.height, image.width, image.xhot, image.yhot, image.pixels);
+ // A sanity check
+ if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
+ int [] pixels = new int [image.width * image.height];
+ Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
+ bmp = new Bitmap (image.width, image.height);
+ for (int w = 0; w < image.width; w++) {
+ for (int h = 0; h < image.height; h++) {
+ bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
+ }
+ }
+ }
+ }
+
+ XcursorImagesDestroy (images_ptr);
+
+ } catch (DllNotFoundException ex) {
+ Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
+ return null;
+ }
+
+ return bmp;
+ }
+
+
+ internal override IntPtr DefineStdCursor(StdCursor id)
+ {
+ CursorFontShape shape;
+ IntPtr cursor;
+
+ shape = StdCursorToFontShape (id);
+
+ lock (XlibLock) {
+ cursor = XCreateFontCursor(DisplayHandle, shape);
+ }
+ return cursor;
+ }
+
+ internal static CursorFontShape StdCursorToFontShape (StdCursor id)
+ {
+ CursorFontShape shape;
+ // FIXME - define missing shapes
+
+ switch (id) {
+ case StdCursor.AppStarting: {
+ shape = CursorFontShape.XC_watch;
+ break;
+ }
+
+ case StdCursor.Arrow: {
+ shape = CursorFontShape.XC_top_left_arrow;
+ break;
+ }
+
+ case StdCursor.Cross: {
+ shape = CursorFontShape.XC_crosshair;
+ break;
+ }
+
+ case StdCursor.Default: {
+ shape = CursorFontShape.XC_top_left_arrow;
+ break;
+ }
+
+ case StdCursor.Hand: {
+ shape = CursorFontShape.XC_hand1;
+ break;
+ }
+
+ case StdCursor.Help: {
+ shape = CursorFontShape.XC_question_arrow;
+ break;
+ }
+
+ case StdCursor.HSplit: {
+ shape = CursorFontShape.XC_sb_v_double_arrow;
+ break;
+ }
+
+ case StdCursor.IBeam: {
+ shape = CursorFontShape.XC_xterm;
+ break;
+ }
+
+ case StdCursor.No: {
+ shape = CursorFontShape.XC_circle;
+ break;
+ }
+
+ case StdCursor.NoMove2D: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.NoMoveHoriz: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.NoMoveVert: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanEast: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanNE: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanNorth: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanNW: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanSE: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanSouth: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanSW: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanWest: {
+ shape = CursorFontShape.XC_sizing;
+ break;
+ }
+
+ case StdCursor.SizeAll: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.SizeNESW: {
+ shape = CursorFontShape.XC_top_right_corner;
+ break;
+ }
+
+ case StdCursor.SizeNS: {
+ shape = CursorFontShape.XC_sb_v_double_arrow;
+ break;
+ }
+
+ case StdCursor.SizeNWSE: {
+ shape = CursorFontShape.XC_top_left_corner;
+ break;
+ }
+
+ case StdCursor.SizeWE: {
+ shape = CursorFontShape.XC_sb_h_double_arrow;
+ break;
+ }
+
+ case StdCursor.UpArrow: {
+ shape = CursorFontShape.XC_center_ptr;
+ break;
+ }
+
+ case StdCursor.VSplit: {
+ shape = CursorFontShape.XC_sb_h_double_arrow;
+ break;
+ }
+
+ case StdCursor.WaitCursor: {
+ shape = CursorFontShape.XC_watch;
+ break;
+ }
+
+ default: {
+ shape = (CursorFontShape) 0;
+ break;
+ }
+ }
+
+ return shape;
+ }
+
+ internal override IntPtr DefWndProc(ref Message msg)
+ {
+ switch ((Msg)msg.Msg) {
+
+ case Msg.WM_IME_COMPOSITION:
+ string s = Keyboard.GetCompositionString ();
+ foreach (char c in s)
+ SendMessage (msg.HWnd, Msg.WM_IME_CHAR, (IntPtr) c, msg.LParam);
+ return IntPtr.Zero;
+
+ 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_PAINT: {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
+ if (hwnd != null) {
+ hwnd.expose_pending = false;
+ }
+
+ return IntPtr.Zero;
+ }
+
+ case Msg.WM_NCPAINT: {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
+ if (hwnd != null) {
+ hwnd.nc_expose_pending = false;
+ }
+
+ return IntPtr.Zero;
+ }
+
+ case Msg.WM_NCCALCSIZE: {
+ Hwnd hwnd;
+
+ if (msg.WParam == (IntPtr)1) {
+ hwnd = Hwnd.GetObjectFromWindow (msg.HWnd);
+
+ 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);
+ }
+ }
+
+ return IntPtr.Zero;
+ }
+
+ case Msg.WM_CONTEXTMENU: {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
+
+ if ((hwnd != null) && (hwnd.parent != null)) {
+ SendMessage(hwnd.parent.client_window, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam);
+ }
+ return IntPtr.Zero;
+ }
+
+ case Msg.WM_MOUSEWHEEL: {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
+
+ if ((hwnd != null) && (hwnd.parent != null)) {
+ SendMessage(hwnd.parent.client_window, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam);
+ if (msg.Result == IntPtr.Zero) {
+ return IntPtr.Zero;
+ }
+ }
+ return IntPtr.Zero;
+ }
+
+ case Msg.WM_SETCURSOR: {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
+ if (hwnd == null)
+ break; // not sure how this happens, but it does
+
+ // 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) {
+ AudibleAlert(AlertType.Default);
+ }
+ 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 handle)
+ {
+ if (Caret.Hwnd == handle) {
+ if (Caret.Visible) {
+ HideCaret ();
+ Caret.Timer.Stop();
+ }
+ if (Caret.gc != IntPtr.Zero) {
+ XFreeGC(DisplayHandle, Caret.gc);
+ Caret.gc = IntPtr.Zero;
+ }
+ Caret.Hwnd = IntPtr.Zero;
+ Caret.Visible = false;
+ Caret.On = false;
+ }
+ }
+
+ internal override void DestroyCursor(IntPtr cursor)
+ {
+ lock (XlibLock) {
+ XFreeCursor(DisplayHandle, cursor);
+ }
+ }
+
+ internal override void DestroyWindow(IntPtr handle)
+ {
+ Hwnd hwnd;
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ // The window should never ever be a zombie here, since we should
+ // wait until it's completely dead before returning from
+ // "destroying" calls, but just in case....
+ if (hwnd == null || hwnd.zombie) {
+ DriverDebug ("window {0:X} already destroyed", handle.ToInt32());
+ return;
+ }
+
+ DriverDebug ("Destroying window {0}", XplatUI.Window(hwnd.client_window));
+
+ 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;
+ }
+
+ lock (XlibLock) {
+ if (hwnd.whole_window != IntPtr.Zero) {
+ DriverDebug ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32());
+ Keyboard.DestroyICForWindow (hwnd.whole_window);
+ XDestroyWindow(DisplayHandle, hwnd.whole_window);
+ }
+ else if (hwnd.client_window != IntPtr.Zero) {
+ DriverDebug ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32());
+ Keyboard.DestroyICForWindow (hwnd.client_window);
+ XDestroyWindow(DisplayHandle, hwnd.client_window);
+ }
+
+ }
+ }
+
+ internal override IntPtr DispatchMessage(ref MSG msg)
+ {
+ return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ }
+
+ IntPtr GetReversibleScreenGC (Color backColor)
+ {
+ XGCValues gc_values;
+ IntPtr gc;
+ uint pixel;
+
+ XColor xcolor = new XColor();
+ xcolor.red = (ushort)(backColor.R * 257);
+ xcolor.green = (ushort)(backColor.G * 257);
+ xcolor.blue = (ushort)(backColor.B * 257);
+ XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
+ pixel = (uint)xcolor.pixel.ToInt32();
+
+
+ gc_values = new XGCValues();
+
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+ gc_values.foreground = (IntPtr)pixel;
+
+ gc = XCreateGC(DisplayHandle, RootWindow, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
+ XSetForeground(DisplayHandle, gc, (UIntPtr)pixel);
+ XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
+
+ return gc;
+ }
+
+ IntPtr GetReversibleWidgetGC (Widget Widget, int line_width)
+ {
+ XGCValues gc_values;
+ IntPtr gc;
+
+ gc_values = new XGCValues();
+
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+ gc_values.line_width = line_width;
+ gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo);
+
+ // This logic will give us true rubber bands: (libsx, SANE_XOR)
+ //mask = foreground ^ background;
+ //XSetForeground(DisplayHandle, gc, 0xffffffff);
+ //XSetBackground(DisplayHandle, gc, background);
+ //XSetFunction(DisplayHandle, gc, GXxor);
+ //XSetPlaneMask(DisplayHandle, gc, mask);
+
+
+ gc = XCreateGC(DisplayHandle, Widget.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values);
+ uint foreground;
+ uint background;
+
+ XColor xcolor = new XColor();
+
+ xcolor.red = (ushort)(Widget.ForeColor.R * 257);
+ xcolor.green = (ushort)(Widget.ForeColor.G * 257);
+ xcolor.blue = (ushort)(Widget.ForeColor.B * 257);
+ XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
+ foreground = (uint)xcolor.pixel.ToInt32();
+
+ xcolor.red = (ushort)(Widget.BackColor.R * 257);
+ xcolor.green = (ushort)(Widget.BackColor.G * 257);
+ xcolor.blue = (ushort)(Widget.BackColor.B * 257);
+ XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
+ background = (uint)xcolor.pixel.ToInt32();
+
+ uint mask = foreground ^ background;
+
+ XSetForeground(DisplayHandle, gc, (UIntPtr)0xffffffff);
+ XSetBackground(DisplayHandle, gc, (UIntPtr)background);
+ XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
+ XSetPlaneMask(DisplayHandle, gc, (IntPtr)mask);
+
+ return gc;
+ }
+
+ internal override void DrawReversibleLine(Point start, Point end, Color backColor)
+ {
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
+ IntPtr gc = GetReversibleScreenGC (backColor);
+
+ XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y);
+
+ XFreeGC(DisplayHandle, gc);
+ }
+
+ internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
+ {
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
+ IntPtr gc = GetReversibleScreenGC (backColor);
+
+ if (rectangle.Width < 0) {
+ rectangle.X += rectangle.Width;
+ rectangle.Width = -rectangle.Width;
+ }
+ if (rectangle.Height < 0) {
+ rectangle.Y += rectangle.Height;
+ rectangle.Height = -rectangle.Height;
+ }
+
+ int line_width = 1;
+ GCLineStyle line_style = GCLineStyle.LineSolid;
+ GCCapStyle cap_style = GCCapStyle.CapButt;
+ GCJoinStyle join_style = GCJoinStyle.JoinMiter;
+
+ switch (style) {
+ case FrameStyle.Dashed:
+ line_style = GCLineStyle.LineOnOffDash;
+ break;
+ case FrameStyle.Thick:
+ line_width = 2;
+ break;
+ }
+
+ XSetLineAttributes (DisplayHandle, gc, line_width, line_style, cap_style, join_style);
+
+ XDrawRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
+
+ XFreeGC(DisplayHandle, gc);
+ }
+
+ internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
+ {
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
+ IntPtr gc = GetReversibleScreenGC (backColor);
+
+ if (rectangle.Width < 0) {
+ rectangle.X += rectangle.Width;
+ rectangle.Width = -rectangle.Width;
+ }
+ if (rectangle.Height < 0) {
+ rectangle.Y += rectangle.Height;
+ rectangle.Height = -rectangle.Height;
+ }
+ XFillRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
+
+ XFreeGC(DisplayHandle, gc);
+ }
+
+ internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width)
+ {
+ IntPtr gc;
+ Widget Widget = Widget.FromHandle(handle);
+
+ gc = GetReversibleWidgetGC (Widget, line_width);
+
+ if ((rect.Width > 0) && (rect.Height > 0)) {
+ XDrawRectangle(DisplayHandle, Widget.Handle, gc, rect.Left, rect.Top, rect.Width, rect.Height);
+ } else {
+ if (rect.Width > 0) {
+ XDrawLine(DisplayHandle, Widget.Handle, gc, rect.X, rect.Y, rect.Right, rect.Y);
+ } else {
+ XDrawLine(DisplayHandle, Widget.Handle, gc, rect.X, rect.Y, rect.X, rect.Bottom);
+ }
+ }
+ XFreeGC(DisplayHandle, gc);
+ }
+
+ internal override void DoEvents()
+ {
+ DebugHelper.Enter ();
+
+ MSG msg = new MSG ();
+ XEventQueue queue;
+
+ if (OverrideCursorHandle != IntPtr.Zero) {
+ OverrideCursorHandle = IntPtr.Zero;
+ }
+
+ queue = ThreadQueue(Thread.CurrentThread);
+
+ queue.DispatchIdle = false;
+ in_doevents = true;
+
+ while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
+ Message m = Message.Create (msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
+
+ if (Application.FilterMessage (ref m))
+ continue;
+
+ TranslateMessage (ref msg);
+ DispatchMessage (ref msg);
+
+ string key = msg.hwnd + ":" + msg.message;
+ if (messageHold[key] != null) {
+ messageHold[key] = ((int)messageHold[key]) - 1;
+ DebugHelper.WriteLine ("Got " + msg + " for " + key);
+ }
+ }
+
+ in_doevents = false;
+ queue.DispatchIdle = true;
+
+ DebugHelper.Leave ();
+ }
+
+ internal override void EnableWindow(IntPtr handle, bool Enable)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (hwnd != null) {
+ hwnd.Enabled = Enable;
+ }
+ }
+
+ internal override void EndLoop(Thread thread)
+ {
+ // This is where we one day will shut down the loop for the thread
+ }
+
+ internal override IntPtr GetActive()
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr active = IntPtr.Zero;
+
+ XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
+ active = (IntPtr)Marshal.ReadInt32(prop);
+ XFree(prop);
+ } else {
+ // The window manager does not support _NET_ACTIVE_WINDOW. Fall back to XGetInputFocus.
+ IntPtr revert_to = IntPtr.Zero;
+ XGetInputFocus(DisplayHandle, out active, out revert_to);
+ }
+
+ if (active != IntPtr.Zero) {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow(active);
+ if (hwnd != null) {
+ active = hwnd.Handle;
+ } else {
+ active = IntPtr.Zero;
+ }
+ }
+ return active;
+ }
+
+ internal override Region GetClipRegion(IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (hwnd != null) {
+ return hwnd.UserClip;
+ }
+
+ return null;
+ }
+
+ internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y)
+ {
+ width = 20;
+ height = 20;
+ hotspot_x = 0;
+ hotspot_y = 0;
+ }
+
+ internal override void GetDisplaySize(out Size size)
+ {
+ XWindowAttributes attributes=new XWindowAttributes();
+
+ lock (XlibLock) {
+ // FIXME - use _NET_WM messages instead?
+ XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
+ }
+
+ size = new Size(attributes.width, attributes.height);
+ }
+
+ 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.FromHwnd(FosterParent);
+
+ width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
+ return new SizeF(width, font.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;
+ }
+
+ // This is a nop on win32 and x11
+ internal override IntPtr GetPreviousWindow(IntPtr handle)
+ {
+ return handle;
+ }
+
+ internal override void GetCursorPos(IntPtr handle, out int x, out int y)
+ {
+ IntPtr use_handle;
+ IntPtr root;
+ IntPtr child;
+ int root_x;
+ int root_y;
+ int win_x;
+ int win_y;
+ int keys_buttons;
+
+ if (handle != IntPtr.Zero) {
+ use_handle = Hwnd.ObjectFromHandle(handle).client_window;
+ } else {
+ use_handle = RootWindow;
+ }
+
+ lock (XlibLock) {
+ QueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
+ }
+
+ if (handle != IntPtr.Zero) {
+ x = win_x;
+ y = win_y;
+ } else {
+ x = root_x;
+ y = root_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;
+ }
+
+ [MonoTODO("Implement filtering")]
+ internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax)
+ {
+ XEvent xevent;
+ bool client;
+ Hwnd hwnd;
+
+ ProcessNextMessage:
+
+ if (((XEventQueue)queue_id).Count > 0) {
+ xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
+ } else {
+ UpdateMessageQueue ((XEventQueue)queue_id);
+
+ if (((XEventQueue)queue_id).Count > 0) {
+ xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
+ } else if (((XEventQueue)queue_id).Paint.Count > 0) {
+ xevent = ((XEventQueue)queue_id).Paint.Dequeue();
+ } else {
+ msg.hwnd= IntPtr.Zero;
+ msg.message = Msg.WM_ENTERIDLE;
+ return true;
+ }
+ }
+
+ hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
+
+#if DriverDebugDestroy
+ if (hwnd != null)
+ if (hwnd.zombie)
+ Console.WriteLine ( "GetMessage zombie, got Event: " + xevent.ToString () + " for 0x{0:x}", hwnd.Handle.ToInt32());
+ else
+ Console.WriteLine ( "GetMessage, got Event: " + xevent.ToString () + " for 0x{0:x}", hwnd.Handle.ToInt32());
+#endif
+ // Handle messages for windows that are already or are about to be destroyed.
+
+ // we need a special block for this because unless we remove the hwnd from the paint
+ // queue it will always stay there (since we don't handle the expose), and we'll
+ // effectively loop infinitely trying to repaint a non-existant window.
+ if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
+ hwnd.expose_pending = hwnd.nc_expose_pending = false;
+ hwnd.Queue.Paint.Remove (hwnd);
+ goto ProcessNextMessage;
+ }
+
+ // We need to make sure we only allow DestroyNotify events through for zombie
+ // hwnds, since much of the event handling code makes requests using the hwnd's
+ // client_window, and that'll result in BadWindow errors if there's some lag
+ // between the XDestroyWindow call and the DestroyNotify event.
+ if (hwnd == null || hwnd.zombie && xevent.AnyEvent.type != XEventName.ClientMessage) {
+ DriverDebug("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
+ goto ProcessNextMessage;
+ }
+
+
+ // If we get here, that means the window is no more but there are Client Messages
+ // to be processed, probably a Posted message (for instance, an WM_ACTIVATE message)
+ // We don't want anything else to run but the ClientMessage block, so reset all hwnd
+ // properties that might cause other processing to occur.
+ if (hwnd.zombie) {
+ hwnd.resizing_or_moving = false;
+ }
+
+ if (hwnd.client_window == xevent.AnyEvent.window) {
+ client = true;
+ //Console.WriteLine("Client message {1}, sending to window {0:X}", msg.hwnd.ToInt32(), xevent.type);
+ } else {
+ client = false;
+ //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32());
+ }
+
+ msg.hwnd = hwnd.Handle;
+
+ // Windows sends WM_ENTERSIZEMOVE when a form resize/move operation starts and WM_EXITSIZEMOVE
+ // when it is done. The problem in X11 is that there is no concept of start-end of a moving/sizing.
+ // Configure events ("this window has resized/moved") are sent for each step of the resize. We send a
+ // WM_ENTERSIZEMOVE when we get the first Configure event. The problem is the WM_EXITSIZEMOVE.
+ //
+ // - There is no way for us to know which is the last Configure event. We can't traverse the events
+ // queue, because the next configure event might not be pending yet.
+ // - We can't get ButtonPress/Release events for the window decorations, because they are not part
+ // of the window(s) we manage.
+ // - We can't rely on the mouse state to change to "up" before the last Configure event. It doesn't.
+ //
+ // We are almost 100% guaranteed to get another event (e.g Expose or other), but we can't know for sure
+ // which, so we have here to check if the mouse buttons state is "up" and send the WM_EXITSIZEMOVE
+ //
+ if (hwnd.resizing_or_moving) {
+ int root_x, root_y, win_x, win_y, keys_buttons;
+ IntPtr root, child;
+ XQueryPointer (DisplayHandle, hwnd.Handle, out root, out child, out root_x, out root_y,
+ out win_x, out win_y, out keys_buttons);
+ if ((keys_buttons & (int)MouseKeyMasks.Button1Mask) == 0 &&
+ (keys_buttons & (int)MouseKeyMasks.Button2Mask) == 0 &&
+ (keys_buttons & (int)MouseKeyMasks.Button3Mask) == 0) {
+ hwnd.resizing_or_moving = false;
+ SendMessage (hwnd.Handle, Msg.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ //
+ // If you add a new event to this switch make sure to add it in
+ // UpdateMessage also unless it is not coming through the X event system.
+ //
+ switch(xevent.type) {
+ case XEventName.KeyPress: {
+ Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
+
+ // F1 key special case - WM_HELP sending
+ if (msg.wParam == (IntPtr)VirtualKeys.VK_F1 || msg.wParam == (IntPtr)VirtualKeys.VK_HELP) {
+ // Send wM_HELP and then return it as a keypress message in
+ // case it needs to be preproccessed.
+ HELPINFO helpInfo = new HELPINFO ();
+ GetCursorPos (IntPtr.Zero, out helpInfo.MousePos.x, out helpInfo.MousePos.y);
+ IntPtr helpInfoPtr = Marshal.AllocHGlobal (Marshal.SizeOf (helpInfo));
+ Marshal.StructureToPtr (helpInfo, helpInfoPtr, true);
+ NativeWindow.WndProc (FocusWindow, Msg.WM_HELP, IntPtr.Zero, helpInfoPtr);
+ Marshal.FreeHGlobal (helpInfoPtr);
+ }
+ break;
+ }
+
+ case XEventName.KeyRelease: {
+ Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
+ break;
+ }
+
+ case XEventName.ButtonPress: {
+ switch(xevent.ButtonEvent.button) {
+ case 1: {
+ MouseState |= MouseButtons.Left;
+ if (client) {
+ msg.message = Msg.WM_LBUTTONDOWN;
+ msg.wParam = GetMousewParam (0);
+ } else {
+ msg.message = Msg.WM_NCLBUTTONDOWN;
+ msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
+ MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ break;
+ }
+
+ case 2: {
+ MouseState |= MouseButtons.Middle;
+ if (client) {
+ msg.message = Msg.WM_MBUTTONDOWN;
+ msg.wParam = GetMousewParam (0);
+ } else {
+ msg.message = Msg.WM_NCMBUTTONDOWN;
+ msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
+ MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ break;
+ }
+
+ case 3: {
+ MouseState |= MouseButtons.Right;
+ if (client) {
+ msg.message = Msg.WM_RBUTTONDOWN;
+ msg.wParam = GetMousewParam (0);
+ } else {
+ msg.message = Msg.WM_NCRBUTTONDOWN;
+ msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
+ MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ break;
+ }
+
+ case 4: {
+ msg.hwnd = FocusWindow;
+ msg.message=Msg.WM_MOUSEWHEEL;
+ msg.wParam=GetMousewParam(120);
+ break;
+ }
+
+ case 5: {
+ msg.hwnd = FocusWindow;
+ msg.message=Msg.WM_MOUSEWHEEL;
+ msg.wParam=GetMousewParam(-120);
+ break;
+ }
+
+ }
+
+ msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ mouse_position.X = xevent.ButtonEvent.x;
+ mouse_position.Y = xevent.ButtonEvent.y;
+
+ if (!hwnd.Enabled) {
+ IntPtr dummy;
+
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy);
+ msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
+ }
+
+ if (Grab.Hwnd != IntPtr.Zero) {
+ msg.hwnd = Grab.Hwnd;
+ }
+
+ if (ClickPending.Pending && ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
+ // Looks like a genuine double click, clicked twice on the same spot with the same keys
+ switch(xevent.ButtonEvent.button) {
+ case 1: {
+ msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
+ break;
+ }
+
+ case 2: {
+ msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
+ break;
+ }
+
+ case 3: {
+ msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
+ break;
+ }
+ }
+ ClickPending.Pending = false;
+ } else {
+ ClickPending.Pending = true;
+ ClickPending.Hwnd = msg.hwnd;
+ ClickPending.Message = msg.message;
+ ClickPending.wParam = msg.wParam;
+ ClickPending.lParam = msg.lParam;
+ ClickPending.Time = (long)xevent.ButtonEvent.time;
+ }
+
+ if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
+ SendParentNotify(msg.hwnd, msg.message, mouse_position.X, mouse_position.Y);
+ }
+
+ break;
+ }
+
+ case XEventName.ButtonRelease: {
+ switch(xevent.ButtonEvent.button) {
+ case 1: {
+ if (client) {
+ msg.message = Msg.WM_LBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCLBUTTONUP;
+ msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
+ MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ MouseState &= ~MouseButtons.Left;
+ msg.wParam = GetMousewParam (0);
+ break;
+ }
+
+ case 2: {
+ if (client) {
+ msg.message = Msg.WM_MBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCMBUTTONUP;
+ msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
+ MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ MouseState &= ~MouseButtons.Middle;
+ msg.wParam = GetMousewParam (0);
+ break;
+ }
+
+ case 3: {
+ if (client) {
+ msg.message = Msg.WM_RBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCRBUTTONUP;
+ msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
+ MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ MouseState &= ~MouseButtons.Right;
+ msg.wParam = GetMousewParam (0);
+ break;
+ }
+
+ case 4: {
+ goto ProcessNextMessage;
+ }
+
+ case 5: {
+ goto ProcessNextMessage;
+ }
+ }
+
+ if (!hwnd.Enabled) {
+ IntPtr dummy;
+
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy);
+ msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
+ }
+
+ if (Grab.Hwnd != IntPtr.Zero) {
+ msg.hwnd = Grab.Hwnd;
+ }
+
+ msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ mouse_position.X = xevent.ButtonEvent.x;
+ mouse_position.Y = xevent.ButtonEvent.y;
+
+ // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
+ // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
+ // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
+ if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
+ XEvent motionEvent = new XEvent ();
+ motionEvent.type = XEventName.MotionNotify;
+ motionEvent.MotionEvent.display = DisplayHandle;
+ motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
+ motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
+ motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
+ hwnd.Queue.EnqueueLocked (motionEvent);
+ }
+ break;
+ }
+
+ case XEventName.MotionNotify: {
+ if (client) {
+ DriverDebug("GetMessage(): Window {0:X} MotionNotify x={1} y={2}",
+ client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(),
+ xevent.MotionEvent.x, xevent.MotionEvent.y);
+
+ if (Grab.Hwnd != IntPtr.Zero) {
+ msg.hwnd = Grab.Hwnd;
+ } else {
+ if (hwnd.Enabled) {
+ NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
+ }
+ }
+
+ if (xevent.MotionEvent.is_hint != 0)
+ {
+ IntPtr root, child;
+ int mask;
+ XQueryPointer (DisplayHandle, xevent.AnyEvent.window,
+ out root, out child,
+ out xevent.MotionEvent.x_root,
+ out xevent.MotionEvent.y_root,
+ out xevent.MotionEvent.x,
+ out xevent.MotionEvent.y, out mask);
+ }
+
+ msg.message = Msg.WM_MOUSEMOVE;
+ msg.wParam = GetMousewParam(0);
+ msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
+
+ if (!hwnd.Enabled) {
+ IntPtr dummy;
+
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy);
+ msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
+ }
+
+ mouse_position.X = xevent.MotionEvent.x;
+ mouse_position.Y = xevent.MotionEvent.y;
+
+ if ((HoverState.Timer.Enabled) &&
+ (((mouse_position.X + HoverState.Size.Width) < HoverState.X) ||
+ ((mouse_position.X - HoverState.Size.Width) > HoverState.X) ||
+ ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) ||
+ ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) {
+ HoverState.Timer.Stop();
+ HoverState.Timer.Start();
+ HoverState.X = mouse_position.X;
+ HoverState.Y = mouse_position.Y;
+ }
+
+ break;
+ } else {
+ HitTest ht;
+ IntPtr dummy;
+
+ DriverDebug("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}",
+ client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(),
+ xevent.MotionEvent.x, xevent.MotionEvent.y);
+ msg.message = Msg.WM_NCMOUSEMOVE;
+
+ if (!hwnd.Enabled) {
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy);
+ msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
+ }
+
+ ht = NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
+ NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
+
+ mouse_position.X = xevent.MotionEvent.x;
+ mouse_position.Y = xevent.MotionEvent.y;
+ }
+
+ break;
+ }
+
+ case XEventName.EnterNotify: {
+ if (!hwnd.Enabled) {
+ goto ProcessNextMessage;
+ }
+ if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || xevent.AnyEvent.window != hwnd.client_window) {
+ goto ProcessNextMessage;
+ }
+ if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) { // Pseudo motion caused by grabbing
+ if (LastPointerWindow == xevent.AnyEvent.window)
+ goto ProcessNextMessage;
+
+ if (LastPointerWindow != IntPtr.Zero) {
+ Point enter_loc = new Point (xevent.ButtonEvent.x, xevent.ButtonEvent.y);
+
+ // We need this due to EnterNotify being fired on all the parent Widgets
+ // of the Widget being grabbed, and obviously in that scenario we are not
+ // actuallty entering them
+ Widget ctrl = Widget.FromHandle (hwnd.client_window);
+ foreach (Widget child_Widget in ctrl.Widgets.GetAllWidgets ())
+ if (child_Widget.Bounds.Contains (enter_loc))
+ goto ProcessNextMessage;
+
+ // A MouseLeave/LeaveNotify event is sent to the previous window
+ // until the mouse is ungrabbed, not when actually leaving its bounds
+ int x = xevent.CrossingEvent.x_root;
+ int y = xevent.CrossingEvent.y_root;
+ ScreenToClient (LastPointerWindow, ref x, ref y);
+
+ XEvent leaveEvent = new XEvent ();
+ leaveEvent.type = XEventName.LeaveNotify;
+ leaveEvent.CrossingEvent.display = DisplayHandle;
+ leaveEvent.CrossingEvent.window = LastPointerWindow;
+ leaveEvent.CrossingEvent.x = x;
+ leaveEvent.CrossingEvent.y = y;
+ leaveEvent.CrossingEvent.mode = NotifyMode.NotifyNormal;
+ Hwnd last_pointer_hwnd = Hwnd.ObjectFromHandle (LastPointerWindow);
+ last_pointer_hwnd.Queue.EnqueueLocked (leaveEvent);
+ }
+ }
+
+ LastPointerWindow = xevent.AnyEvent.window;
+
+ msg.message = Msg.WM_MOUSE_ENTER;
+ HoverState.X = xevent.CrossingEvent.x;
+ HoverState.Y = xevent.CrossingEvent.y;
+ HoverState.Timer.Enabled = true;
+ HoverState.Window = xevent.CrossingEvent.window;
+
+ // Win32 sends a WM_MOUSEMOVE after mouse enter
+ XEvent motionEvent = new XEvent ();
+ motionEvent.type = XEventName.MotionNotify;
+ motionEvent.MotionEvent.display = DisplayHandle;
+ motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
+ motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
+ motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
+ hwnd.Queue.EnqueueLocked (motionEvent);
+ break;
+ }
+
+ case XEventName.LeaveNotify: {
+ if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) {
+ WindowUngrabbed (hwnd.Handle);
+ goto ProcessNextMessage;
+ }
+ if (!hwnd.Enabled) {
+ goto ProcessNextMessage;
+ }
+ if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
+ goto ProcessNextMessage;
+ }
+ // If a grab is taking place, ignore it - we handle it in EnterNotify
+ if (Grab.Hwnd != IntPtr.Zero)
+ goto ProcessNextMessage;
+
+ // Reset the cursor explicitly on X11.
+ // X11 remembers the last set cursor for the window and in cases where
+ // the Widget won't get a WM_SETCURSOR X11 will restore the last
+ // known cursor, which we don't want.
+ //
+ SetCursor (hwnd.client_window, IntPtr.Zero);
+
+ msg.message=Msg.WM_MOUSELEAVE;
+ HoverState.Timer.Enabled = false;
+ HoverState.Window = IntPtr.Zero;
+ break;
+ }
+
+ #if later
+ case XEventName.CreateNotify: {
+ if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
+ msg.message = WM_CREATE;
+ // Set up CreateStruct
+ } else {
+ goto ProcessNextMessage;
+ }
+ break;
+ }
+ #endif
+
+
+ case XEventName.ReparentNotify: {
+ if (hwnd.parent == null) { // Toplevel
+ if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) {
+ hwnd.Reparented = true;
+
+ // The location given by the event is not reliable between different wm's,
+ // so use an alternative way of getting it.
+ Point location = GetTopLevelWindowLocation (hwnd);
+ hwnd.X = location.X;
+ hwnd.Y = location.Y;
+
+ if (hwnd.opacity != 0xffffffff) {
+ IntPtr opacity;
+
+ opacity = (IntPtr)(Int32)hwnd.opacity;
+ XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
+ }
+ SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
+ goto ProcessNextMessage;
+ } else {
+ hwnd.Reparented = false;
+ goto ProcessNextMessage;
+ }
+ }
+ goto ProcessNextMessage;
+ }
+
+ case XEventName.ConfigureNotify: {
+ if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+ DriverDebug("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}",
+ hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x,
+ xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
+
+ lock (hwnd.configure_lock) {
+ Form form = Widget.FromHandle (hwnd.client_window) as Form;
+ if (form != null && !hwnd.resizing_or_moving) {
+ if (hwnd.x != form.Bounds.X || hwnd.y != form.Bounds.Y) {
+ SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_MOVE, IntPtr.Zero);
+ hwnd.resizing_or_moving = true;
+ } else if (hwnd.width != form.Bounds.Width || hwnd.height != form.Bounds.Height) {
+ SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_SIZE, IntPtr.Zero);
+ hwnd.resizing_or_moving = true;
+ }
+ if (hwnd.resizing_or_moving)
+ SendMessage (form.Handle, Msg.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ hwnd.configure_pending = false;
+
+ // We need to adjust our client window to track the resize of whole_window
+ if (hwnd.whole_window != hwnd.client_window)
+ PerformNCCalc(hwnd);
+ }
+ }
+ goto ProcessNextMessage;
+ }
+
+ case XEventName.FocusIn: {
+ // We received focus. We use X11 focus only to know if the app window does or does not have focus
+ // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
+ // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
+ // about it having focus again
+ if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
+ goto ProcessNextMessage;
+ }
+
+
+ if (FocusWindow == IntPtr.Zero) {
+ Widget c = Widget.FromHandle (hwnd.client_window);
+
+ if (c == null)
+ goto ProcessNextMessage;
+ Form form = c.FindForm ();
+ if (form == null)
+ goto ProcessNextMessage;
+
+ if (ActiveWindow != form.Handle) {
+ ActiveWindow = form.Handle;
+ SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
+ }
+ goto ProcessNextMessage;
+ }
+ Keyboard.FocusIn (FocusWindow);
+ SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
+ goto ProcessNextMessage;
+ }
+
+ case XEventName.FocusOut: {
+ // Se the comment for our FocusIn handler
+ if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
+ goto ProcessNextMessage;
+ }
+
+ while (Keyboard.ResetKeyState(FocusWindow, ref msg)) {
+ SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam);
+ }
+
+ Keyboard.FocusOut(hwnd.client_window);
+ SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
+ goto ProcessNextMessage;
+ }
+
+ // We are already firing WM_SHOWWINDOW messages in the proper places, but I'm leaving this code
+ // in case we break a scenario not taken into account in the tests
+ case XEventName.MapNotify: {
+ /*if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+ hwnd.mapped = true;
+ msg.message = Msg.WM_SHOWWINDOW;
+ msg.wParam = (IntPtr) 1;
+ // XXX we're missing the lParam..
+ break;
+ }*/
+ goto ProcessNextMessage;
+ }
+
+ case XEventName.UnmapNotify: {
+ /*if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+ hwnd.mapped = false;
+ msg.message = Msg.WM_SHOWWINDOW;
+ msg.wParam = (IntPtr) 0;
+ // XXX we're missing the lParam..
+ break;
+ }*/
+ goto ProcessNextMessage;
+ }
+
+ case XEventName.Expose: {
+ if (!hwnd.Mapped) {
+ if (client) {
+ hwnd.expose_pending = false;
+ } else {
+ hwnd.nc_expose_pending = false;
+ }
+ goto ProcessNextMessage;
+ }
+
+ if (client) {
+ if (!hwnd.expose_pending) {
+ goto ProcessNextMessage;
+ }
+ } else {
+ if (!hwnd.nc_expose_pending) {
+ goto ProcessNextMessage;
+ }
+
+ switch (hwnd.border_style) {
+ case FormBorderStyle.Fixed3D: {
+ Graphics g;
+
+ g = Graphics.FromHwnd(hwnd.whole_window);
+ if (hwnd.border_static)
+ WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter);
+ else
+ WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken);
+ g.Dispose();
+ break;
+ }
+
+ case FormBorderStyle.FixedSingle: {
+ Graphics g;
+
+ g = Graphics.FromHwnd(hwnd.whole_window);
+ WidgetPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
+ g.Dispose();
+ break;
+ }
+ }
+ DriverDebug("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}",
+ hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+ xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+
+ Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ Region region = new Region (rect);
+ IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
+ msg.message = Msg.WM_NCPAINT;
+ msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
+ msg.refobject = region;
+ break;
+ }
+ DriverDebug("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}",
+ hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+ xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ if (Caret.Visible == true) {
+ Caret.Paused = true;
+ HideCaret();
+ }
+
+ if (Caret.Visible == true) {
+ ShowCaret();
+ Caret.Paused = false;
+ }
+ msg.message = Msg.WM_PAINT;
+ break;
+ }
+
+ case XEventName.DestroyNotify: {
+
+ // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
+ hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
+
+ // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
+ if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) {
+ CleanupCachedWindows (hwnd);
+
+ DriverDebug("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window));
+
+ msg.hwnd = hwnd.client_window;
+ msg.message=Msg.WM_DESTROY;
+ hwnd.Dispose();
+ } else {
+ goto ProcessNextMessage;
+ }
+
+ break;
+ }
+
+ case XEventName.ClientMessage: {
+ if (Dnd.HandleClientMessage (ref xevent)) {
+ goto ProcessNextMessage;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == AsyncAtom) {
+ XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
+ goto ProcessNextMessage;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
+ msg.message = Msg.WM_MOUSEHOVER;
+ msg.wParam = GetMousewParam(0);
+ msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
+ return true;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
+ DebugHelper.Indent ();
+ DebugHelper.WriteLine (String.Format ("Posted message:" + (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 () + " for 0x{0:x}", xevent.ClientMessageEvent.ptr1.ToInt32 ()));
+ DebugHelper.Unindent ();
+ msg.hwnd = xevent.ClientMessageEvent.ptr1;
+ msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
+ msg.wParam = xevent.ClientMessageEvent.ptr3;
+ msg.lParam = xevent.ClientMessageEvent.ptr4;
+ if (msg.message == (Msg)Msg.WM_QUIT)
+ return false;
+ else
+ return true;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == _XEMBED) {
+#if DriverDebugXEmbed
+ Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
+#endif
+
+ if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
+ XSizeHints hints = new XSizeHints();
+ IntPtr dummy;
+
+ XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
+
+ hwnd.width = hints.max_width;
+ hwnd.height = hints.max_height;
+ hwnd.ClientRect = Rectangle.Empty;
+ SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) {
+ if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) {
+ SendMessage (msg.hwnd, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_CLOSE, IntPtr.Zero);
+ msg.message = Msg.WM_CLOSE;
+ return true;
+ }
+
+ // We should not get this, but I'll leave the code in case we need it in the future
+ if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) {
+ goto ProcessNextMessage;
+ }
+ }
+ goto ProcessNextMessage;
+ }
+
+ default: {
+ goto ProcessNextMessage;
+ }
+ }
+
+ return true;
+ }
+
+ HitTest NCHitTest (Hwnd hwnd, int x, int y)
+ {
+ // The hit test is sent in screen coordinates
+ IntPtr dummy;
+ int screen_x, screen_y;
+ XTranslateCoordinates (DisplayHandle, hwnd.WholeWindow, RootWindow, x, y, out screen_x, out screen_y, out dummy);
+ return (HitTest) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero,
+ (IntPtr) (screen_y << 16 | screen_x & 0xFFFF));
+ }
+
+ // Our very basic implementation of MoveResize - we can extend it later
+ // *if* needed
+ internal override void BeginMoveResize (IntPtr handle)
+ {
+ // We *need* to ungrab the pointer in the current display
+ XplatUI.UngrabWindow (Grab.Hwnd);
+
+ int x_root, y_root;
+ GetCursorPos (IntPtr.Zero, out x_root, out y_root);
+
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+ SendNetWMMessage (hwnd.whole_window, _NET_WM_MOVERESIZE, (IntPtr) x_root, (IntPtr) y_root,
+ (IntPtr) NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT,
+ (IntPtr) 1); // left button
+ }
+
+ internal override bool GetText(IntPtr handle, out string text)
+ {
+
+ lock (XlibLock) {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ XGetWindowProperty(DisplayHandle, handle,
+ _NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
+ UTF8_STRING, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if ((long)nitems > 0 && prop != IntPtr.Zero) {
+ text = Marshal.PtrToStringUni (prop, (int)nitems);
+ XFree (prop);
+ return true;
+ }
+ else {
+ // fallback on the non-_NET property
+ IntPtr textptr;
+
+ textptr = IntPtr.Zero;
+
+ XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr);
+ if (textptr != IntPtr.Zero) {
+ text = Marshal.PtrToStringAnsi(textptr);
+ XFree(textptr);
+ return true;
+ } else {
+ text = "";
+ return false;
+ }
+ }
+ }
+ }
+
+ 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 handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd.cached_window_state == (FormWindowState)(-1))
+ hwnd.cached_window_state = UpdateWindowState (handle);
+
+ return hwnd.cached_window_state;
+ }
+
+ FormWindowState UpdateWindowState (IntPtr handle) {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr atom;
+ int maximized;
+ bool minimized;
+ XWindowAttributes attributes;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ maximized = 0;
+ minimized = false;
+ XGetWindowProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
+ for (int i = 0; i < (long)nitems; i++) {
+ atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
+ if ((atom == _NET_WM_STATE_MAXIMIZED_HORZ) || (atom == _NET_WM_STATE_MAXIMIZED_VERT)) {
+ maximized++;
+ } else if (atom == _NET_WM_STATE_HIDDEN) {
+ minimized = true;
+ }
+ }
+ XFree(prop);
+ }
+
+ if (minimized) {
+ return FormWindowState.Minimized;
+ } else if (maximized == 2) {
+ return FormWindowState.Maximized;
+ }
+
+ attributes = new XWindowAttributes();
+ XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
+ if (attributes.map_state == MapState.IsUnmapped) {
+ return (FormWindowState)(-1);
+ }
+
+
+ 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)
+ {
+ Hwnd hwnd;
+ IntPtr confine_to_window;
+
+ confine_to_window = IntPtr.Zero;
+
+ if (confine_to_handle != IntPtr.Zero) {
+ XWindowAttributes attributes = new XWindowAttributes();
+
+ hwnd = Hwnd.ObjectFromHandle(confine_to_handle);
+
+ lock (XlibLock) {
+ XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
+ }
+ Grab.Area.X = attributes.x;
+ Grab.Area.Y = attributes.y;
+ Grab.Area.Width = attributes.width;
+ Grab.Area.Height = attributes.height;
+ Grab.Confined = true;
+ confine_to_window = hwnd.client_window;
+ }
+
+ Grab.Hwnd = handle;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ lock (XlibLock) {
+ XGrabPointer(DisplayHandle, hwnd.client_window, false,
+ EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
+ EventMask.ButtonReleaseMask | EventMask.PointerMotionMask |
+ EventMask.PointerMotionHintMask | EventMask.LeaveWindowMask,
+ GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ internal override void UngrabWindow(IntPtr hwnd)
+ {
+ lock (XlibLock) {
+ XUngrabPointer(DisplayHandle, IntPtr.Zero);
+ XFlush(DisplayHandle);
+ }
+ WindowUngrabbed (hwnd);
+ }
+
+ void WindowUngrabbed (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 X doesn't seem to give us that information.
+ // Also only generate WM_CAPTURECHANGED if the window actually was grabbed.
+ // X will send a NotifyUngrab, but since it comes late sometimes we're
+ // calling WindowUngrabbed directly from UngrabWindow in order to send
+ // this WM right away.
+ SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
+
+ internal override void HandleException(Exception e)
+ {
+ StackTrace st = new StackTrace(e, true);
+ 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, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
+ }
+
+ internal override bool IsEnabled(IntPtr handle)
+ {
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+ return (hwnd != null && hwnd.Enabled);
+ }
+
+ internal override bool IsVisible(IntPtr handle)
+ {
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+ return (hwnd != null && hwnd.visible);
+ }
+
+ internal override void KillTimer(Timer timer)
+ {
+ XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
+
+ if (queue == null) {
+ // This isn't really an error, MS doesn't start the timer if
+ // it has no assosciated queue. In this case, remove the timer
+ // from the list of unattached timers (if it was enabled).
+ lock (unattached_timer_list) {
+ if (unattached_timer_list.Contains (timer))
+ unattached_timer_list.Remove (timer);
+ }
+ return;
+ }
+ queue.timer_list.Remove (timer);
+ }
+
+ internal override void MenuToScreen(IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ internal override void OverrideCursor(IntPtr cursor)
+ {
+ if (Grab.Hwnd != IntPtr.Zero) {
+ XChangeActivePointerGrab (DisplayHandle,
+ EventMask.ButtonMotionMask |
+ EventMask.PointerMotionMask |
+ EventMask.PointerMotionHintMask |
+ EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask,
+ cursor, IntPtr.Zero);
+ return;
+ }
+
+ OverrideCursorHandle = cursor;
+ }
+
+ internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client)
+ {
+ PaintEventArgs paint_event;
+ Hwnd hwnd;
+ Hwnd paint_hwnd;
+
+ //
+ // handle (and paint_hwnd) refers to the window that is should be painted.
+ // msg.HWnd (and hwnd) refers to the window that got the paint message.
+ //
+
+ hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
+ if (msg.HWnd == handle) {
+ paint_hwnd = hwnd;
+ } else {
+ paint_hwnd = Hwnd.ObjectFromHandle (handle);
+ }
+
+ if (Caret.Visible == true) {
+ 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);
+ }
+
+ 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);
+
+ return paint_event;
+ } else {
+ dc = Graphics.FromHwnd (paint_hwnd.whole_window);
+
+ if (!hwnd.nc_invalid.IsEmpty) {
+ 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 (msg.HWnd);
+
+ Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
+ dc.Flush();
+ dc.Dispose();
+
+ PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop();
+ pe.SetGraphics (null);
+ pe.Dispose ();
+
+ if (Caret.Visible == true) {
+ ShowCaret();
+ Caret.Paused = false;
+ }
+ }
+
+ [MonoTODO("Implement filtering and PM_NOREMOVE")]
+ internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
+ {
+ XEventQueue queue = (XEventQueue) queue_id;
+ bool pending;
+
+ if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
+ throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
+ }
+
+ pending = false;
+ if (queue.Count > 0) {
+ pending = true;
+ } else {
+ // Only call UpdateMessageQueue if real events are pending
+ // otherwise we go to sleep on the socket
+ if (XPending(DisplayHandle) != 0) {
+ UpdateMessageQueue((XEventQueue)queue_id);
+ pending = true;
+ } else if (((XEventQueue)queue_id).Paint.Count > 0) {
+ pending = true;
+ }
+ }
+
+ CheckTimers(queue.timer_list, DateTime.UtcNow);
+
+ if (!pending) {
+ return false;
+ }
+ return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
+ }
+
+ internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam)
+ {
+ XEvent xevent = new XEvent ();
+ Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = DisplayHandle;
+
+ if (hwnd != null) {
+ xevent.ClientMessageEvent.window = hwnd.whole_window;
+ } else {
+ xevent.ClientMessageEvent.window = IntPtr.Zero;
+ }
+
+ xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = handle;
+ xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
+ xevent.ClientMessageEvent.ptr3 = wparam;
+ xevent.ClientMessageEvent.ptr4 = lparam;
+
+ if (hwnd != null)
+ hwnd.Queue.EnqueueLocked (xevent);
+ else
+ ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent);
+
+ return true;
+ }
+
+ internal override void PostQuitMessage(int exitCode)
+ {
+ ApplicationContext ctx = Application.MWFThread.Current.Context;
+ Form f = ctx != null ? ctx.MainForm : null;
+ if (f != null)
+ PostMessage (Application.MWFThread.Current.Context.MainForm.window.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+ else
+ PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+ XFlush(DisplayHandle);
+ }
+
+ internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave)
+ {
+ // TODO
+ }
+
+ 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);
+ }
+
+ internal override void ResetMouseHover(IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (hwnd == null) {
+ return;
+ }
+
+ HoverState.Timer.Enabled = true;
+ HoverState.X = mouse_position.X;
+ HoverState.Y = mouse_position.Y;
+ HoverState.Window = handle;
+ }
+
+
+ internal override void ScreenToClient(IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ Form form = Widget.FromHandle (handle) as Form;
+ if (form != null && form.window_manager != null) {
+ dest_y_return -= form.window_manager.TitleBarHeight;
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg)
+ {
+ return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) &&
+ arg == xevent.GraphicsExposeEvent.drawable;
+ }
+
+ delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg);
+
+ void ProcessGraphicsExpose (Hwnd hwnd)
+ {
+ XEvent xevent = new XEvent ();
+ IntPtr handle = Hwnd.HandleFromObject (hwnd);
+ EventPredicate predicate = GraphicsExposePredicate;
+
+ for (;;) {
+ XIfEvent (Display, ref xevent, predicate, handle);
+ if (xevent.type != XEventName.GraphicsExpose)
+ break;
+
+ AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y,
+ xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height);
+
+ if (xevent.GraphicsExposeEvent.count == 0)
+ break;
+ }
+ }
+
+ internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children)
+ {
+ Hwnd hwnd;
+ IntPtr gc;
+ XGCValues gc_values;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ Rectangle r = Rectangle.Intersect (hwnd.Invalid, area);
+ if (!r.IsEmpty) {
+ /* We have an invalid area in the window we're scrolling.
+ Adjust our stored invalid rectangle to to match the scrolled amount */
+
+ r.X += XAmount;
+ r.Y += YAmount;
+
+ if (r.X < 0) {
+ r.Width += r.X;
+ r.X =0;
+ }
+
+ if (r.Y < 0) {
+ r.Height += r.Y;
+ r.Y =0;
+ }
+
+ if (area.Contains (hwnd.Invalid))
+ hwnd.ClearInvalidArea ();
+ hwnd.AddInvalidArea(r);
+ }
+
+ gc_values = new XGCValues();
+
+ if (with_children) {
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+ }
+
+ gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
+
+ Rectangle visible_rect = GetTotalVisibleArea (hwnd.client_window);
+ visible_rect.Intersect (area);
+
+ Rectangle dest_rect = visible_rect;
+ dest_rect.Y += YAmount;
+ dest_rect.X += XAmount;
+ dest_rect.Intersect (area);
+
+ Point src = new Point (dest_rect.X - XAmount, dest_rect.Y - YAmount);
+ XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src.X, src.Y,
+ dest_rect.Width, dest_rect.Height, dest_rect.X, dest_rect.Y);
+
+ Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount);
+ AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height);
+
+ ProcessGraphicsExpose (hwnd);
+
+ XFreeGC(DisplayHandle, gc);
+ }
+
+ internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children)
+ {
+ Hwnd hwnd;
+ Rectangle rect;
+
+ hwnd = Hwnd.GetObjectFromWindow(handle);
+
+ rect = hwnd.ClientRect;
+ rect.X = 0;
+ rect.Y = 0;
+ ScrollWindow(handle, rect, XAmount, YAmount, with_children);
+ }
+
+ Rectangle GetDirtyArea (Rectangle total_area, Rectangle valid_area, int XAmount, int YAmount)
+ {
+ Rectangle dirty_area = total_area;
+
+ if (YAmount > 0)
+ dirty_area.Height -= valid_area.Height;
+ else if (YAmount < 0) {
+ dirty_area.Height -= valid_area.Height;
+ dirty_area.Y += valid_area.Height;
+ }
+
+ if (XAmount > 0)
+ dirty_area.Width -= valid_area.Width;
+ else if (XAmount < 0) {
+ dirty_area.Width -= valid_area.Width;
+ dirty_area.X += valid_area.Width;
+ }
+
+ return dirty_area;
+ }
+
+ Rectangle GetTotalVisibleArea (IntPtr handle)
+ {
+ Widget c = Widget.FromHandle (handle);
+
+ Rectangle visible_area = c.ClientRectangle;
+ visible_area.Location = c.PointToScreen (Point.Empty);
+
+ for (Widget parent = c.Parent; parent != null; parent = parent.Parent) {
+ if (!parent.IsHandleCreated || !parent.Visible)
+ return visible_area; // Non visible, not need to finish computations
+
+ Rectangle r = parent.ClientRectangle;
+ r.Location = parent.PointToScreen (Point.Empty);
+
+ visible_area.Intersect (r);
+ }
+
+ visible_area.Location = c.PointToClient (visible_area.Location);
+ return visible_area;
+ }
+
+ internal override void SendAsyncMethod (AsyncMethodData method)
+ {
+ Hwnd hwnd;
+ XEvent xevent = new XEvent ();
+
+ hwnd = Hwnd.ObjectFromHandle(method.Handle);
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = DisplayHandle;
+ xevent.ClientMessageEvent.window = method.Handle;
+ xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
+
+ hwnd.Queue.EnqueueLocked (xevent);
+
+ WakeupMain ();
+ }
+
+ delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
+
+ internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ Hwnd h;
+ h = Hwnd.ObjectFromHandle(hwnd);
+
+ if (h != null && h.queue != ThreadQueue (Thread.CurrentThread)) {
+ AsyncMethodResult result;
+ AsyncMethodData data;
+
+ result = new AsyncMethodResult ();
+ data = new AsyncMethodData ();
+
+ data.Handle = hwnd;
+ data.Method = new WndProcDelegate (NativeWindow.WndProc);
+ data.Args = new object[] { hwnd, message, wParam, lParam };
+ data.Result = result;
+
+ SendAsyncMethod (data);
+ DriverDebug("Sending {0} message across.", message);
+
+ return IntPtr.Zero;
+ }
+ string key = hwnd + ":" + message;
+ if (messageHold[key] != null)
+ messageHold[key] = ((int)messageHold[key]) - 1;
+ return NativeWindow.WndProc(hwnd, message, wParam, lParam);
+ }
+
+ internal override int SendInput(IntPtr handle, Queue keys)
+ {
+ if (handle == IntPtr.Zero)
+ return 0;
+
+ int count = keys.Count;
+ Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
+
+ while (keys.Count > 0) {
+
+ MSG msg = (MSG)keys.Dequeue();
+
+ XEvent xevent = new XEvent ();
+
+ xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
+ xevent.KeyEvent.display = DisplayHandle;
+
+ if (hwnd != null) {
+ xevent.KeyEvent.window = hwnd.whole_window;
+ } else {
+ xevent.KeyEvent.window = IntPtr.Zero;
+ }
+
+ xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
+
+ hwnd.Queue.EnqueueLocked (xevent);
+ }
+ return count;
+ }
+
+ internal override void SetAllowDrop (IntPtr handle, bool value)
+ {
+ // We allow drop on all windows
+ }
+
+ 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) {
+ CreateParams cp = form.GetCreateParams ();
+ if (border_style == FormBorderStyle.FixedToolWindow ||
+ border_style == FormBorderStyle.SizableToolWindow ||
+ cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
+ form.window_manager = new ToolWindowManager (form);
+ }
+ }
+
+ RequestNCRecalc(handle);
+ }
+
+ internal override void SetCaretPos(IntPtr handle, int x, int y)
+ {
+ if (Caret.Hwnd == handle) {
+ Caret.Timer.Stop();
+ HideCaret();
+
+ Caret.X = x;
+ Caret.Y = y;
+
+ Keyboard.SetCaretPos (Caret, handle, x, y);
+
+ if (Caret.Visible == true) {
+ ShowCaret();
+ Caret.Timer.Start();
+ }
+ }
+ }
+
+ internal override void SetClipRegion(IntPtr handle, Region region)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (hwnd == null) {
+ return;
+ }
+
+ hwnd.UserClip = region;
+ }
+
+ internal override void SetCursor(IntPtr handle, IntPtr cursor)
+ {
+ Hwnd hwnd;
+
+ if (OverrideCursorHandle == IntPtr.Zero) {
+ if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
+ return;
+ }
+
+ LastCursorHandle = cursor;
+ LastCursorWindow = handle;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ lock (XlibLock) {
+ if (cursor != IntPtr.Zero) {
+ XDefineCursor(DisplayHandle, hwnd.whole_window, cursor);
+ } else {
+ XUndefineCursor(DisplayHandle, hwnd.whole_window);
+ }
+ XFlush(DisplayHandle);
+ }
+ return;
+ }
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ lock (XlibLock) {
+ XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
+ }
+ }
+
+ void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child,
+ out int root_x, out int root_y, out int child_x, out int child_y,
+ out int mask)
+ {
+ /* this code was written with the help of
+ glance at gdk. I never would have realized we
+ needed a loop in order to traverse down in the
+ hierarchy. I would have assumed you'd get the
+ most deeply nested child and have to do
+ XQueryTree to move back up the hierarchy..
+ stupid me, of course. */
+ IntPtr c;
+
+ XGrabServer (display);
+
+ XQueryPointer(display, w, out root, out c,
+ out root_x, out root_y, out child_x, out child_y,
+ out mask);
+
+ if (root != w)
+ c = root;
+
+ IntPtr child_last = IntPtr.Zero;
+ while (c != IntPtr.Zero) {
+ child_last = c;
+ XQueryPointer(display, c, out root, out c,
+ out root_x, out root_y, out child_x, out child_y,
+ out mask);
+ }
+ XUngrabServer (display);
+ XFlush (display);
+
+ child = child_last;
+ }
+
+ internal override void SetCursorPos(IntPtr handle, int x, int y)
+ {
+ if (handle == IntPtr.Zero) {
+ lock (XlibLock) {
+ IntPtr root, child;
+ int root_x, root_y, child_x, child_y, mask;
+
+ /* we need to do a
+ * QueryPointer before warping
+ * because if the warp is on
+ * the RootWindow, the x/y are
+ * relative to the current
+ * mouse position
+ */
+ QueryPointer (DisplayHandle, RootWindow,
+ out root,
+ out child,
+ out root_x, out root_y,
+ out child_x, out child_y,
+ out mask);
+
+ XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
+
+ XFlush (DisplayHandle);
+
+ /* then we need to a
+ * QueryPointer after warping
+ * to manually generate a
+ * motion event for the window
+ * we move into.
+ */
+ QueryPointer (DisplayHandle, RootWindow,
+ out root,
+ out child,
+ out root_x, out root_y,
+ out child_x, out child_y,
+ out mask);
+
+ Hwnd child_hwnd = Hwnd.ObjectFromHandle(child);
+ if (child_hwnd == null) {
+ return;
+ }
+
+ XEvent xevent = new XEvent ();
+
+ xevent.type = XEventName.MotionNotify;
+ xevent.MotionEvent.display = DisplayHandle;
+ xevent.MotionEvent.window = child_hwnd.client_window;
+ xevent.MotionEvent.root = RootWindow;
+ xevent.MotionEvent.x = child_x;
+ xevent.MotionEvent.y = child_y;
+ xevent.MotionEvent.x_root = root_x;
+ xevent.MotionEvent.y_root = root_y;
+ xevent.MotionEvent.state = mask;
+
+ child_hwnd.Queue.EnqueueLocked (xevent);
+ }
+ } else {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ lock (XlibLock) {
+ XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
+ }
+ }
+ }
+
+ internal override void SetFocus(IntPtr handle)
+ {
+ Hwnd hwnd;
+ IntPtr prev_focus_window;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd.client_window == FocusWindow) {
+ return;
+ }
+
+ // Win32 doesn't do anything if disabled
+ if (!hwnd.enabled)
+ return;
+
+ prev_focus_window = FocusWindow;
+ FocusWindow = hwnd.client_window;
+
+ if (prev_focus_window != IntPtr.Zero) {
+ SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
+ }
+ Keyboard.FocusIn (FocusWindow);
+ SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
+
+ //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
+ }
+
+ internal override void SetIcon(IntPtr handle, Icon icon)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (hwnd != null) {
+ SetIcon(hwnd, icon);
+ }
+ }
+
+ internal override void SetMenu(IntPtr handle, Menu menu)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ hwnd.menu = menu;
+
+ RequestNCRecalc(handle);
+ }
+
+ internal override void SetModal(IntPtr handle, bool Modal)
+ {
+ if (Modal) {
+ ModalWindows.Push(handle);
+ } else {
+ if (ModalWindows.Contains(handle)) {
+ ModalWindows.Pop();
+ }
+ if (ModalWindows.Count > 0) {
+ Activate((IntPtr)ModalWindows.Peek());
+ }
+ }
+
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+ Widget ctrl = Widget.FromHandle (handle);
+ SetWMStyles (hwnd, ctrl.GetCreateParams ());
+ }
+
+ internal override IntPtr SetParent(IntPtr handle, IntPtr parent)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ hwnd.parent = Hwnd.ObjectFromHandle(parent);
+
+ lock (XlibLock) {
+ DriverDebug("Parent for window {0} = {1}", XplatUI.Window(hwnd.Handle), XplatUI.Window(hwnd.parent != null ? hwnd.parent.Handle : IntPtr.Zero));
+ XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent == null ? FosterParent : hwnd.parent.client_window, hwnd.x, hwnd.y);
+ }
+
+ return IntPtr.Zero;
+ }
+
+ internal override void SetTimer (Timer timer)
+ {
+ XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
+
+ if (queue == null) {
+ // This isn't really an error, MS doesn't start the timer if
+ // it has no assosciated queue at this stage (it will be
+ // enabled when a window is activated).
+ unattached_timer_list.Add (timer);
+ return;
+ }
+ queue.timer_list.Add (timer);
+ WakeupMain ();
+ }
+
+ internal override bool SetTopmost(IntPtr handle, bool enabled)
+ {
+
+ Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
+ hwnd.topmost = enabled;
+
+ if (enabled) {
+ lock (XlibLock) {
+ if (hwnd.Mapped) {
+ SendNetWMMessage(hwnd.WholeWindow, _NET_WM_STATE, (IntPtr) NetWmStateRequest._NET_WM_STATE_ADD, _NET_WM_STATE_ABOVE, IntPtr.Zero);
+ } else {
+ int[] atoms = new int[8];
+ atoms[0] = _NET_WM_STATE_ABOVE.ToInt32();
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
+ }
+ }
+ } else {
+ lock (XlibLock) {
+ if (hwnd.Mapped)
+ SendNetWMMessage(hwnd.WholeWindow, _NET_WM_STATE, (IntPtr) NetWmStateRequest._NET_WM_STATE_REMOVE, _NET_WM_STATE_ABOVE, IntPtr.Zero);
+ else
+ XDeleteProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE);
+ }
+ }
+ return true;
+ }
+
+ internal override bool SetOwner(IntPtr handle, IntPtr handle_owner)
+ {
+ Hwnd hwnd;
+ Hwnd hwnd_owner;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (handle_owner != IntPtr.Zero) {
+ hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
+ lock (XlibLock) {
+ int[] atoms;
+
+ atoms = new int[8];
+
+ atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
+
+ if (hwnd_owner != null) {
+ XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
+ } else {
+ XSetTransientForHint(DisplayHandle, hwnd.whole_window, RootWindow);
+ }
+ }
+ } else {
+ lock (XlibLock) {
+ XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR);
+ }
+ }
+ return true;
+ }
+
+ internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ hwnd.visible = visible;
+
+ lock (XlibLock) {
+ if (visible) {
+ MapWindow(hwnd, WindowType.Both);
+
+ if (Widget.FromHandle(handle) is Form) {
+ FormWindowState s;
+
+ s = ((Form)Widget.FromHandle(handle)).WindowState;
+
+ switch(s) {
+ case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break;
+ case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break;
+ }
+ }
+
+ SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+ }
+ else {
+ UnmapWindow(hwnd, WindowType.Both);
+ }
+ }
+ return true;
+ }
+
+ internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max)
+ {
+ Widget ctrl = Widget.FromHandle (handle);
+ SetWindowMinMax (handle, maximized, min, max, ctrl != null ? ctrl.GetCreateParams () : null);
+ }
+
+ internal void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp)
+ {
+ Hwnd hwnd;
+ XSizeHints hints;
+ IntPtr dummy;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ if (hwnd == null) {
+ return;
+ }
+
+ min.Width = Math.Max (min.Width, SystemInformation.MinimumWindowSize.Width);
+ min.Height = Math.Max (min.Height, SystemInformation.MinimumWindowSize.Height);
+
+ hints = new XSizeHints();
+
+ XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
+ if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
+ if (cp != null)
+ min = TranslateWindowSizeToXWindowSize (cp, min);
+ hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
+ hints.min_width = min.Width;
+ hints.min_height = min.Height;
+ }
+
+ if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
+ if (cp != null)
+ max = TranslateWindowSizeToXWindowSize (cp, max);
+ hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
+ hints.max_width = max.Width;
+ hints.max_height = max.Height;
+ }
+
+ if (hints.flags != IntPtr.Zero) {
+ // The Metacity team has decided that they won't care about this when clicking the maximize icon,
+ // they will maximize the window to fill the screen/parent no matter what.
+ // http://bugzilla.ximian.com/show_bug.cgi?id=80021
+ XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints);
+ }
+
+ if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
+ if (cp != null)
+ maximized.Size = TranslateWindowSizeToXWindowSize (cp);
+ hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
+ hints.x = maximized.X;
+ hints.y = maximized.Y;
+ hints.width = maximized.Width;
+ hints.height = maximized.Height;
+
+ // Metacity does not seem to follow this constraint for maximized (zoomed) windows
+ XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints);
+ }
+ }
+
+
+ internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height)
+ {
+ Hwnd 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) {
+ MapWindow(hwnd, WindowType.Whole);
+ }
+ hwnd.zero_sized = false;
+ }
+
+ if ((width < 1) || (height < 1)) {
+ hwnd.zero_sized = true;
+ UnmapWindow(hwnd, WindowType.Whole);
+ }
+
+ // 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) {
+ //Hack?
+ hwnd.x = x;
+ hwnd.y = y;
+ hwnd.width = width;
+ hwnd.height = height;
+ SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+
+ if (hwnd.fixed_size) {
+ SetWindowMinMax(handle, Rectangle.Empty, new Size(width, height), new Size(width, height));
+ }
+
+ lock (XlibLock) {
+ Widget ctrl = Widget.FromHandle (handle);
+ Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams (), new Size (width, height));
+ MoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
+ PerformNCCalc(hwnd);
+ }
+ }
+
+ // Update our position/size immediately, so
+ // that future calls to SetWindowPos aren't
+ // kept from calling XMoveResizeWindow (by the
+ // "Save a server roundtrip" block above).
+ hwnd.x = x;
+ hwnd.y = y;
+ hwnd.width = width;
+ hwnd.height = height;
+ hwnd.ClientRect = Rectangle.Empty;
+ }
+
+ internal override void SetWindowState(IntPtr handle, FormWindowState state)
+ {
+ FormWindowState current_state;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ current_state = GetWindowState(handle);
+
+ if (current_state == state) {
+ return;
+ }
+
+ switch(state) {
+ case FormWindowState.Normal: {
+ lock (XlibLock) {
+ if (current_state == FormWindowState.Minimized) {
+ MapWindow(hwnd, WindowType.Both);
+ } else if (current_state == FormWindowState.Maximized) {
+ SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
+ }
+ }
+ Activate(handle);
+ return;
+ }
+
+ case FormWindowState.Minimized: {
+ lock (XlibLock) {
+ if (current_state == FormWindowState.Maximized) {
+ SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
+ }
+ XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo);
+ }
+ return;
+ }
+
+ case FormWindowState.Maximized: {
+ lock (XlibLock) {
+ if (current_state == FormWindowState.Minimized) {
+ MapWindow(hwnd, WindowType.Both);
+ }
+
+ SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)1 /* Add */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
+ }
+ Activate(handle);
+ return;
+ }
+ }
+ }
+
+ internal override void SetWindowStyle(IntPtr handle, CreateParams cp)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ SetHwndStyles(hwnd, cp);
+ SetWMStyles(hwnd, cp);
+ }
+
+ internal override double GetWindowTransparency(IntPtr handle)
+ {
+ return 1.0;
+ }
+
+ internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key)
+ {
+ Hwnd hwnd;
+ IntPtr opacity;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (hwnd == null) {
+ return;
+ }
+
+ hwnd.opacity = (uint)(0xffffffff * transparency);
+ opacity = (IntPtr)hwnd.opacity;
+
+ if (transparency >= 1.0) {
+ XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_OPACITY);
+ } else {
+ XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
+ }
+ }
+
+ internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom)
+ {
+ Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (!hwnd.mapped) {
+ return false;
+ }
+
+ if (top) {
+ lock (XlibLock) {
+ XRaiseWindow(DisplayHandle, hwnd.whole_window);
+ }
+ return true;
+ } else if (!bottom) {
+ Hwnd after_hwnd = null;
+
+ if (after_handle != IntPtr.Zero) {
+ after_hwnd = Hwnd.ObjectFromHandle(after_handle);
+ }
+
+ XWindowChanges values = new XWindowChanges();
+
+ if (after_hwnd == null) {
+ // Work around metacity 'issues'
+ int[] atoms;
+
+ atoms = new int[2];
+ atoms[0] = unixtime();
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_USER_TIME, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, atoms, 1);
+
+ XRaiseWindow(DisplayHandle, hwnd.whole_window);
+ SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
+ return true;
+ //throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order");
+ }
+
+ values.sibling = after_hwnd.whole_window;
+ values.stack_mode = StackMode.Below;
+
+ lock (XlibLock) {
+ XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
+ }
+ } else {
+ // Bottom
+ lock (XlibLock) {
+ XLowerWindow(DisplayHandle, hwnd.whole_window);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ internal override void ShowCursor(bool show)
+ {
+ ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
+ }
+
+ internal override object StartLoop(Thread thread)
+ {
+ XEventQueue q = ThreadQueue(thread);
+ return q;
+ }
+
+ internal override TransparencySupport SupportsTransparency()
+ {
+ // We need to check if the x compositing manager is running
+ return TransparencySupport.Set;
+ }
+
+ internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt)
+ {
+ GetSystrayManagerWindow();
+
+ if (SystrayMgrWindow != IntPtr.Zero) {
+ XSizeHints size_hints;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+ DriverDebug("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
+
+ // Oh boy.
+ if (hwnd.client_window != hwnd.whole_window) {
+ Keyboard.DestroyICForWindow (hwnd.client_window);
+ XDestroyWindow(DisplayHandle, hwnd.client_window);
+ hwnd.client_window = hwnd.whole_window;
+ }
+
+ /* by virtue of the way the tests are ordered when determining if it's PAINT
+ or NCPAINT, client_window == whole_window will always be PAINT. So, if we're
+ waiting on an nc_expose, drop it and remove the hwnd from the list (unless
+ there's a pending expose). */
+ if (hwnd.nc_expose_pending) {
+ hwnd.nc_expose_pending = false;
+ if (!hwnd.expose_pending)
+ hwnd.Queue.Paint.Remove (hwnd);
+ }
+
+ // We are going to be directly mapped by the system tray, so mark as mapped
+ // so we can later properly unmap it.
+ hwnd.mapped = true;
+
+ size_hints = new XSizeHints();
+
+ size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
+
+ size_hints.min_width = 24;
+ size_hints.min_height = 24;
+ size_hints.max_width = 24;
+ size_hints.max_height = 24;
+ size_hints.base_width = 24;
+ size_hints.base_height = 24;
+
+ XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints);
+
+ int[] atoms = new int[2];
+ atoms [0] = 1; // Version 1
+ atoms [1] = 1; // we want to be mapped
+
+ // This line cost me 3 days...
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2);
+
+ // Need to pick some reasonable defaults
+ tt = new ToolTip();
+ tt.AutomaticDelay = 350;
+ tt.InitialDelay = 250;
+ tt.ReshowDelay = 250;
+ tt.ShowAlways = true;
+
+ if ((tip != null) && (tip != string.Empty)) {
+ tt.SetToolTip(Widget.FromHandle(handle), tip);
+ tt.Active = true;
+ } else {
+ tt.Active = false;
+ }
+
+ SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
+
+ return true;
+ }
+ tt = null;
+ return false;
+ }
+
+ internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt)
+ {
+ Widget Widget;
+
+ Widget = Widget.FromHandle(handle);
+ if (Widget != null && tt != null) {
+ tt.SetToolTip(Widget, tip);
+ tt.Active = true;
+ SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ internal override void SystrayRemove(IntPtr handle, ref ToolTip tt)
+ {
+
+ SetVisible (handle, false, false);
+
+ // The caller can now re-dock it later...
+ if (tt != null) {
+ tt.Dispose();
+ tt = null;
+ }
+ // Close any balloon window *we* fired.
+ ThemeEngine.Current.HideBalloonWindow (handle);
+ }
+
+ internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
+ {
+ ThemeEngine.Current.ShowBalloonWindow (handle, timeout, title, text, icon);
+ SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW);
+ }
+
+ internal override bool Text(IntPtr handle, string text)
+{
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ lock (XlibLock) {
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_NAME, UTF8_STRING, 8,
+ PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
+
+ // XXX this has problems with UTF8.
+ // we need to either use the actual
+ // text if it's latin-1, or convert it
+ // to compound text if it's in a
+ // different charset.
+ XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text);
+ }
+ return true;
+ }
+
+ internal override bool TranslateMessage(ref MSG msg)
+ {
+ return Keyboard.TranslateMessage (ref msg);
+ }
+
+ internal override void UpdateWindow(IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (!hwnd.visible || !hwnd.expose_pending || !hwnd.Mapped) {
+ return;
+ }
+
+ SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+ hwnd.Queue.Paint.Remove(hwnd);
+ }
+
+ internal override void CreateOffscreenDrawable (IntPtr handle,
+ int width, int height,
+ out object offscreen_drawable)
+ {
+ IntPtr root_out;
+ int x_out, y_out, width_out, height_out, border_width_out, depth_out;
+
+ XGetGeometry (DisplayHandle, handle,
+ out root_out,
+ out x_out, out y_out,
+ out width_out, out height_out,
+ out border_width_out, out depth_out);
+
+ IntPtr pixmap = XCreatePixmap (DisplayHandle, handle, width, height, depth_out);
+
+ offscreen_drawable = pixmap;
+
+ }
+
+ internal override void DestroyOffscreenDrawable (object offscreen_drawable)
+ {
+ XFreePixmap (DisplayHandle, (IntPtr)offscreen_drawable);
+ }
+
+ internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
+ {
+ return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
+ }
+
+ internal override void BlitFromOffscreen (IntPtr dest_handle,
+ Graphics dest_dc,
+ object offscreen_drawable,
+ Graphics offscreen_dc,
+ Rectangle r)
+ {
+ XGCValues gc_values;
+ IntPtr gc;
+
+ gc_values = new XGCValues();
+
+ gc = XCreateGC (DisplayHandle, dest_handle, IntPtr.Zero, ref gc_values);
+
+ XCopyArea (DisplayHandle, (IntPtr)offscreen_drawable, dest_handle,
+ gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
+
+ XFreeGC (DisplayHandle, gc);
+ }
+
+ #endregion // Public Static Methods
+
+ #region Events
+ internal override event EventHandler Idle;
+ #endregion // Events
+
+
+#if TRACE && false
+
+#region Xcursor imports
+ [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")]
+ internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")]
+ internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")]
+ internal extern static void XcursorImagesDestroy (IntPtr images);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")]
+ internal extern static int XcursorGetDefaultSize (IntPtr display);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")]
+ internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")]
+ internal extern static IntPtr XcursorGetTheme (IntPtr display);
+#endregion
+#region X11 Imports
+ [DllImport ("libX11", EntryPoint="XOpenDisplay")]
+ internal extern static IntPtr XOpenDisplay(IntPtr display);
+ [DllImport ("libX11", EntryPoint="XCloseDisplay")]
+ internal extern static int XCloseDisplay(IntPtr display);
+ [DllImport ("libX11", EntryPoint="XSynchronize")]
+ internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
+
+ [DllImport ("libX11", EntryPoint="XCreateWindow")]
+ internal extern static IntPtr _XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes);
+ internal static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes)
+ {
+ DebugHelper.TraceWriteLine ("XCreateWindow");
+ return _XCreateWindow(display, parent, x, y, width, height,
+ border_width, depth, xclass, visual, valuemask, ref attributes);
+ }
+ [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
+ internal extern static IntPtr _XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
+ internal static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background)
+ {
+ DebugHelper.TraceWriteLine ("XCreateSimpleWindow");
+ return _XCreateSimpleWindow(display, parent, x, y, width, height, border_width, border, background);
+ }
+ [DllImport ("libX11", EntryPoint="XMapWindow")]
+ internal extern static int _XMapWindow(IntPtr display, IntPtr window);
+ internal static int XMapWindow(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XMapWindow");
+ return _XMapWindow(display, window);
+ }
+ [DllImport ("libX11", EntryPoint="XMapRaised")]
+ internal extern static int _XMapRaised(IntPtr display, IntPtr window);
+ internal static int XMapRaised(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XMapRaised");
+ return _XMapRaised(display, window);
+ }
+ [DllImport ("libX11", EntryPoint="XUnmapWindow")]
+ internal extern static int _XUnmapWindow(IntPtr display, IntPtr window);
+ internal static int XUnmapWindow(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XUnmapWindow");
+ return _XUnmapWindow(display, window);
+ }
+ [DllImport ("libX11", EntryPoint="XMapSubwindows")]
+ internal extern static int _XMapSubindows(IntPtr display, IntPtr window);
+ internal static int XMapSubindows(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XMapSubindows");
+ return _XMapSubindows(display, window);
+ }
+ [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
+ internal extern static int _XUnmapSubwindows(IntPtr display, IntPtr window);
+ internal static int XUnmapSubwindows(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XUnmapSubwindows");
+ return _XUnmapSubwindows(display, window);
+ }
+ [DllImport ("libX11", EntryPoint="XRootWindow")]
+ internal extern static IntPtr _XRootWindow(IntPtr display, int screen_number);
+ internal static IntPtr XRootWindow(IntPtr display, int screen_number)
+ {
+ DebugHelper.TraceWriteLine ("XRootWindow");
+ return _XRootWindow(display, screen_number);
+ }
+ [DllImport ("libX11", EntryPoint="XNextEvent")]
+ internal extern static IntPtr _XNextEvent(IntPtr display, ref XEvent xevent);
+ internal static IntPtr XNextEvent(IntPtr display, ref XEvent xevent)
+ {
+ DebugHelper.TraceWriteLine ("XNextEvent");
+ return _XNextEvent(display, ref xevent);
+ }
+ [DllImport ("libX11", EntryPoint="XConnectionNumber")]
+ internal extern static int _XConnectionNumber (IntPtr display);
+ internal static int XConnectionNumber (IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XConnectionNumber");
+ return _XConnectionNumber (display);
+ }
+ [DllImport ("libX11", EntryPoint="XPending")]
+ internal extern static int _XPending (IntPtr display);
+ internal static int XPending (IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XPending");
+ DebugHelper.DumpCallers (3);
+ return _XPending (display);
+ }
+ [DllImport ("libX11", EntryPoint="XSelectInput")]
+ internal extern static IntPtr _XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
+ internal static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask)
+ {
+ DebugHelper.TraceWriteLine ("XSelectInput");
+ return _XSelectInput(display, window, mask);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDestroyWindow")]
+ internal extern static int _XDestroyWindow(IntPtr display, IntPtr window);
+ internal static int XDestroyWindow(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XDestroyWindow 0x{0:x}", window.ToInt32());
+ return _XDestroyWindow(display, window);
+ }
+
+ [DllImport ("libX11", EntryPoint="XReparentWindow")]
+ internal extern static int _XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
+ internal static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y)
+ {
+ DebugHelper.TraceWriteLine ("XReparentWindow");
+ return _XReparentWindow(display, window, parent, x, y);
+ }
+
+ [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
+ extern static int _XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+ static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height) {
+ DebugHelper.TraceWriteLine ("XMoveResizeWindow");
+ return _XMoveResizeWindow(display, window, x, y, width, height);
+ }
+
+ internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height)
+ {
+ int ret = XMoveResizeWindow (display, window, x, y, width, height);
+ Keyboard.MoveCurrentCaretPos ();
+ return ret;
+ }
+
+ [DllImport ("libX11", EntryPoint="XResizeWindow")]
+ internal extern static int _XResizeWindow(IntPtr display, IntPtr window, int width, int height);
+ internal static int XResizeWindow(IntPtr display, IntPtr window, int width, int height)
+ {
+ DebugHelper.TraceWriteLine ("XResizeWindow");
+ return _XResizeWindow(display, window, width, height);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
+ internal extern static int _XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
+ internal static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes)
+ {
+ DebugHelper.TraceWriteLine ("XGetWindowAttributes");
+ return _XGetWindowAttributes(display, window, ref attributes);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFlush")]
+ internal extern static int _XFlush(IntPtr display);
+ internal static int XFlush(IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XFlush");
+ return _XFlush(display);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetWMName")]
+ internal extern static int _XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
+ internal static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop)
+ {
+ DebugHelper.TraceWriteLine ("XSetWMName");
+ return _XSetWMName(display, window, ref text_prop);
+ }
+
+ [DllImport ("libX11", EntryPoint="XStoreName")]
+ internal extern static int _XStoreName(IntPtr display, IntPtr window, string window_name);
+ internal static int XStoreName(IntPtr display, IntPtr window, string window_name)
+ {
+ DebugHelper.TraceWriteLine ("XStoreName");
+ return _XStoreName(display, window, window_name);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFetchName")]
+ internal extern static int _XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
+ internal static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name)
+ {
+ DebugHelper.TraceWriteLine ("XFetchName");
+ return _XFetchName(display, window, ref window_name);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSendEvent")]
+ internal extern static int _XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
+ internal static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event)
+ {
+ DebugHelper.TraceWriteLine ("XSendEvent");
+ return _XSendEvent(display, window, propagate, event_mask, ref send_event);
+ }
+
+ [DllImport ("libX11", EntryPoint="XQueryTree")]
+ internal extern static int _XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return);
+ internal static int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return)
+ {
+ DebugHelper.TraceWriteLine ("XQueryTree");
+ return _XQueryTree(display, window, out root_return, out parent_return, out children_return, out nchildren_return);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFree")]
+ internal extern static int _XFree(IntPtr data);
+ internal static int XFree(IntPtr data)
+ {
+ DebugHelper.TraceWriteLine ("XFree");
+ return _XFree(data);
+ }
+
+ [DllImport ("libX11", EntryPoint="XRaiseWindow")]
+ internal extern static int _XRaiseWindow(IntPtr display, IntPtr window);
+ internal static int XRaiseWindow(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XRaiseWindow");
+ return _XRaiseWindow(display, window);
+ }
+
+ [DllImport ("libX11", EntryPoint="XLowerWindow")]
+ internal extern static uint _XLowerWindow(IntPtr display, IntPtr window);
+ internal static uint XLowerWindow(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XLowerWindow");
+ return _XLowerWindow(display, window);
+ }
+
+ [DllImport ("libX11", EntryPoint="XConfigureWindow")]
+ internal extern static uint _XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
+ internal static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values)
+ {
+ DebugHelper.TraceWriteLine ("XConfigureWindow");
+ return _XConfigureWindow(display, window, value_mask, ref values);
+ }
+
+ [DllImport ("libX11", EntryPoint="XInternAtom")]
+ internal extern static IntPtr _XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
+ internal static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists)
+ {
+ DebugHelper.TraceWriteLine ("XInternAtom");
+ return _XInternAtom(display, atom_name, only_if_exists);
+ }
+
+ [DllImport ("libX11", EntryPoint="XInternAtoms")]
+ internal extern static int _XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
+ internal static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms)
+ {
+ DebugHelper.TraceWriteLine ("XInternAtoms");
+ return _XInternAtoms(display, atom_names, atom_count, only_if_exists, atoms);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
+ internal extern static int _XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
+ internal static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count)
+ {
+ DebugHelper.TraceWriteLine ("XSetWMProtocols");
+ return _XSetWMProtocols(display, window, protocols, count);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGrabPointer")]
+ internal extern static int _XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp);
+ internal static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp)
+ {
+ DebugHelper.TraceWriteLine ("XGrabPointer");
+ return _XGrabPointer(display, window, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, timestamp);
+ }
+
+ [DllImport ("libX11", EntryPoint="XUngrabPointer")]
+ internal extern static int _XUngrabPointer(IntPtr display, IntPtr timestamp);
+ internal static int XUngrabPointer(IntPtr display, IntPtr timestamp)
+ {
+ DebugHelper.TraceWriteLine ("XUngrabPointer");
+ return _XUngrabPointer(display, timestamp);
+ }
+
+ [DllImport ("libX11", EntryPoint="XQueryPointer")]
+ internal extern static bool _XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons);
+ internal static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons)
+ {
+ DebugHelper.TraceWriteLine ("XQueryPointer");
+ return _XQueryPointer(display, window, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
+ }
+
+ [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
+ internal extern static bool _XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return);
+ internal static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return)
+ {
+ DebugHelper.TraceWriteLine ("XTranslateCoordinates");
+ return _XTranslateCoordinates (display, src_w, dest_w, src_x, src_y, out intdest_x_return, out dest_y_return, out child_return);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth);
+ internal static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth)
+ {
+ DebugHelper.TraceWriteLine ("XGetGeometry");
+ return _XGetGeometry(display, window, out root, out x, out y, out width, out height, out border_width, out depth);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth);
+ internal static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth)
+ {
+ DebugHelper.TraceWriteLine ("XGetGeometry");
+ return _XGetGeometry(display, window, root, out x, out y, out width, out height, border_width, depth);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth);
+ internal static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth)
+ {
+ DebugHelper.TraceWriteLine ("XGetGeometry");
+ return _XGetGeometry(display, window, root, out x, out y, width, height, border_width, depth);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth);
+ internal static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth)
+ {
+ DebugHelper.TraceWriteLine ("XGetGeometry");
+ return _XGetGeometry(display, window, root, x, y, out width, out height, border_width, depth);
+ }
+
+ [DllImport ("libX11", EntryPoint="XWarpPointer")]
+ internal extern static uint _XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y);
+ internal static uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y)
+ {
+ DebugHelper.TraceWriteLine ("XWarpPointer");
+ return _XWarpPointer(display, src_w, dest_w, src_x, src_y, src_width, src_height, dest_x, dest_y);
+ }
+
+ [DllImport ("libX11", EntryPoint="XClearWindow")]
+ internal extern static int _XClearWindow(IntPtr display, IntPtr window);
+ internal static int XClearWindow(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XClearWindow");
+ return _XClearWindow(display, window);
+ }
+
+ [DllImport ("libX11", EntryPoint="XClearArea")]
+ internal extern static int _XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
+ internal static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures)
+ {
+ DebugHelper.TraceWriteLine ("XClearArea");
+ return _XClearArea(display, window, x, y, width, height, exposures);
+ }
+
+ // Colormaps
+ [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
+ internal extern static IntPtr _XDefaultScreenOfDisplay(IntPtr display);
+ internal static IntPtr XDefaultScreenOfDisplay(IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XDefaultScreenOfDisplay");
+ return _XDefaultScreenOfDisplay(display);
+ }
+
+ [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
+ internal extern static int _XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
+ internal static int XDefaultScreenOfDisplay(IntPtr display, IntPtr Screen)
+ {
+ DebugHelper.TraceWriteLine ("XDefaultScreenOfDisplay");
+ return _XScreenNumberOfScreen(display, Screen);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDefaultVisual")]
+ internal extern static IntPtr _XDefaultVisual(IntPtr display, int screen_number);
+ internal static IntPtr XDefaultScreenOfDisplay(IntPtr display, int screen_number)
+ {
+ DebugHelper.TraceWriteLine ("XDefaultScreenOfDisplay");
+ return _XDefaultVisual(display, screen_number);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDefaultDepth")]
+ internal extern static uint _XDefaultDepth(IntPtr display, int screen_number);
+ internal static uint XDefaultDepth(IntPtr display, int screen_number)
+ {
+ DebugHelper.TraceWriteLine ("XDefaultDepth");
+ return _XDefaultDepth(display, screen_number);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDefaultScreen")]
+ internal extern static int _XDefaultScreen(IntPtr display);
+ internal static int XDefaultScreen(IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XDefaultScreen");
+ return _XDefaultScreen(display);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDefaultColormap")]
+ internal extern static IntPtr _XDefaultColormap(IntPtr display, int screen_number);
+ internal static IntPtr XDefaultColormap(IntPtr display, int screen_number)
+ {
+ DebugHelper.TraceWriteLine ("XDefaultColormap");
+ return _XDefaultColormap(display, screen_number);
+ }
+
+ [DllImport ("libX11", EntryPoint="XLookupColor")]
+ internal extern static int _XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
+ internal static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color)
+ {
+ DebugHelper.TraceWriteLine ("XLookupColor");
+ return _XLookupColor(display, Colormap, Coloranem, ref exact_def_color, ref screen_def_color);
+ }
+
+ [DllImport ("libX11", EntryPoint="XAllocColor")]
+ internal extern static int _XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
+ internal static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def)
+ {
+ DebugHelper.TraceWriteLine ("XAllocColor");
+ return _XAllocColor(display, Colormap, ref colorcell_def);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
+ internal extern static int _XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
+ internal static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window)
+ {
+ DebugHelper.TraceWriteLine ("XSetTransientForHint");
+ return _XSetTransientForHint(display, window, prop_window);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, ref data, nelements);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, ref value, nelements);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, ref value, nelements);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, data, nelements);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, data, nelements);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, data, nelements);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, atoms, nelements);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
+ internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
+ internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length)
+ {
+ DebugHelper.TraceWriteLine ("XChangeProperty");
+ return _XChangeProperty(display, window, property, type, format, mode, text, text_length);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDeleteProperty")]
+ internal extern static int _XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
+ internal static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property)
+ {
+ DebugHelper.TraceWriteLine ("XDeleteProperty");
+ return _XDeleteProperty(display, window, property);
+ }
+
+ // Drawing
+ [DllImport ("libX11", EntryPoint="XCreateGC")]
+ internal extern static IntPtr _XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
+ internal static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values)
+ {
+ DebugHelper.TraceWriteLine ("XCreateGC");
+ return _XCreateGC(display, window, valuemask, ref values);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFreeGC")]
+ internal extern static int _XFreeGC(IntPtr display, IntPtr gc);
+ internal static int XFreeGC(IntPtr display, IntPtr gc)
+ {
+ DebugHelper.TraceWriteLine ("XFreeGC");
+ return _XFreeGC(display, gc);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetFunction")]
+ internal extern static int _XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
+ internal static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function)
+ {
+ DebugHelper.TraceWriteLine ("XSetFunction");
+ return _XSetFunction(display, gc, function);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetLineAttributes")]
+ internal extern static int _XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
+ internal static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style)
+ {
+ DebugHelper.TraceWriteLine ("XSetLineAttributes");
+ return _XSetLineAttributes(display, gc, line_width, line_style, cap_style, join_style);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDrawLine")]
+ internal extern static int _XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
+ internal static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2)
+ {
+ DebugHelper.TraceWriteLine ("XDrawLine");
+ return _XDrawLine(display, drawable, gc, x1, y1, x2, y2);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDrawRectangle")]
+ internal extern static int _XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
+ internal static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height)
+ {
+ DebugHelper.TraceWriteLine ("XDrawRectangle");
+ return _XDrawRectangle(display, drawable, gc, x1, y1, width, height);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFillRectangle")]
+ internal extern static int _XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
+ internal static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height)
+ {
+ DebugHelper.TraceWriteLine ("XFillRectangle");
+ return _XFillRectangle(display, drawable, gc, x1, y1, width, height);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
+ internal extern static int _XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
+ internal static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background)
+ {
+ DebugHelper.TraceWriteLine ("XSetWindowBackground");
+ return _XSetWindowBackground(display, window, background);
+ }
+
+ [DllImport ("libX11", EntryPoint="XCopyArea")]
+ internal extern static int _XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
+ internal static int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y)
+ {
+ DebugHelper.TraceWriteLine ("XCopyArea");
+ return _XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
+ internal extern static int _XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop);
+ internal static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop)
+ {
+ DebugHelper.TraceWriteLine ("XGetWindowProperty");
+ return _XGetWindowProperty(display, window, atom, long_offset, long_length, delete, req_type, out actual_type, out actual_format, out nitems, out bytes_after, ref prop);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetInputFocus")]
+ internal extern static int _XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
+ internal static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time)
+ {
+ DebugHelper.TraceWriteLine ("XSetInputFocus");
+ return _XSetInputFocus(display, window, revert_to, time);
+ }
+
+ [DllImport ("libX11", EntryPoint="XIconifyWindow")]
+ internal extern static int _XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
+ internal static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number)
+ {
+ DebugHelper.TraceWriteLine ("XIconifyWindow");
+ return _XIconifyWindow(display, window, screen_number);
+ }
+
+ [DllImport ("libX11", EntryPoint="XDefineCursor")]
+ internal extern static int _XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
+ internal static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor)
+ {
+ DebugHelper.TraceWriteLine ("XDefineCursor");
+ return _XDefineCursor(display, window, cursor);
+ }
+
+ [DllImport ("libX11", EntryPoint="XUndefineCursor")]
+ internal extern static int _XUndefineCursor(IntPtr display, IntPtr window);
+ internal static int XUndefineCursor(IntPtr display, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XUndefineCursor");
+ return _XUndefineCursor(display, window);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFreeCursor")]
+ internal extern static int _XFreeCursor(IntPtr display, IntPtr cursor);
+ internal static int XFreeCursor(IntPtr display, IntPtr cursor)
+ {
+ DebugHelper.TraceWriteLine ("XFreeCursor");
+ return _XFreeCursor(display, cursor);
+ }
+
+ [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
+ internal extern static IntPtr _XCreateFontCursor(IntPtr display, CursorFontShape shape);
+ internal static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape)
+ {
+ DebugHelper.TraceWriteLine ("XCreateFontCursor");
+ return _XCreateFontCursor(display, shape);
+ }
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
+ internal extern static IntPtr _XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot);
+ internal static IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot)
+ {
+ DebugHelper.TraceWriteLine ("XCreatePixmapCursor");
+ return _XCreatePixmapCursor(display, source, mask, ref foreground_color, ref background_color, x_hot, y_hot);
+ }
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
+ internal extern static IntPtr _XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
+ internal static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth)
+ {
+ DebugHelper.TraceWriteLine ("XCreatePixmapFromBitmapData");
+ return _XCreatePixmapFromBitmapData(display, drawable, data, width, height, fg, bg, depth);
+ }
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmap")]
+ internal extern static IntPtr _XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
+ internal static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth)
+ {
+ DebugHelper.TraceWriteLine ("XCreatePixmap");
+ return _XCreatePixmap(display, d, width, height, depth);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFreePixmap")]
+ internal extern static IntPtr _XFreePixmap(IntPtr display, IntPtr pixmap);
+ internal static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap)
+ {
+ DebugHelper.TraceWriteLine ("XFreePixmap");
+ return _XFreePixmap(display, pixmap);
+ }
+
+ [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
+ internal extern static int _XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
+ internal static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height)
+ {
+ DebugHelper.TraceWriteLine ("XQueryBestCursor");
+ return _XQueryBestCursor(display, drawable, width, height, out best_width, out best_height);
+ }
+
+ [DllImport ("libX11", EntryPoint="XQueryExtension")]
+ internal extern static int _XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
+ internal static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error)
+ {
+ DebugHelper.TraceWriteLine ("XQueryExtension");
+ return _XQueryExtension(display, extension_name, ref major, ref first_event, ref first_error);
+ }
+
+ [DllImport ("libX11", EntryPoint="XWhitePixel")]
+ internal extern static IntPtr _XWhitePixel(IntPtr display, int screen_no);
+ internal static IntPtr XWhitePixel(IntPtr display, int screen_no)
+ {
+ DebugHelper.TraceWriteLine ("XWhitePixel");
+ return _XWhitePixel(display, screen_no);
+ }
+
+ [DllImport ("libX11", EntryPoint="XBlackPixel")]
+ internal extern static IntPtr _XBlackPixel(IntPtr display, int screen_no);
+ internal static IntPtr XBlackPixel(IntPtr display, int screen_no)
+ {
+ DebugHelper.TraceWriteLine ("XBlackPixel");
+ return _XBlackPixel(display, screen_no);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGrabServer")]
+ internal extern static void _XGrabServer(IntPtr display);
+ internal static void XGrabServer(IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XGrabServer");
+ _XGrabServer(display);
+ }
+
+ [DllImport ("libX11", EntryPoint="XUngrabServer")]
+ internal extern static void _XUngrabServer(IntPtr display);
+ internal static void XUngrabServer(IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XUngrabServer");
+ _XUngrabServer(display);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetWMNormalHints")]
+ internal extern static void _XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
+ internal static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return)
+ {
+ DebugHelper.TraceWriteLine ("XGetWMNormalHints");
+ _XGetWMNormalHints(display, window, ref hints, out supplied_return);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
+ internal extern static void _XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+ internal static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints)
+ {
+ DebugHelper.TraceWriteLine ("XSetWMNormalHints");
+ _XSetWMNormalHints(display, window, ref hints);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetZoomHints")]
+ internal extern static void _XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+ internal static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints)
+ {
+ DebugHelper.TraceWriteLine ("XSetZoomHints");
+ _XSetZoomHints(display, window, ref hints);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetWMHints")]
+ internal extern static void _XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
+ internal static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints)
+ {
+ DebugHelper.TraceWriteLine ("XSetWMHints");
+ _XSetWMHints(display, window, ref wmhints);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetIconSizes")]
+ internal extern static int _XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
+ internal static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count)
+ {
+ DebugHelper.TraceWriteLine ("XGetIconSizes");
+ return _XGetIconSizes(display, window, out size_list, out count);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
+ internal extern static IntPtr _XSetErrorHandler(XErrorHandler error_handler);
+ internal static IntPtr XSetErrorHandler(XErrorHandler error_handler)
+ {
+ DebugHelper.TraceWriteLine ("XSetErrorHandler");
+ return _XSetErrorHandler(error_handler);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetErrorText")]
+ internal extern static IntPtr _XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
+ internal static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length)
+ {
+ DebugHelper.TraceWriteLine ("XGetErrorText");
+ return _XGetErrorText(display, code, buffer, length);
+ }
+
+ [DllImport ("libX11", EntryPoint="XInitThreads")]
+ internal extern static int _XInitThreads();
+ internal static int XInitThreads()
+ {
+ DebugHelper.TraceWriteLine ("XInitThreads");
+ return _XInitThreads();
+ }
+
+ [DllImport ("libX11", EntryPoint="XConvertSelection")]
+ internal extern static int _XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
+ internal static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time)
+ {
+ DebugHelper.TraceWriteLine ("XConvertSelection");
+ return _XConvertSelection(display, selection, target, property, requestor, time);
+ }
+
+ [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
+ internal extern static IntPtr _XGetSelectionOwner(IntPtr display, IntPtr selection);
+ internal static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection)
+ {
+ DebugHelper.TraceWriteLine ("XGetSelectionOwner");
+ return _XGetSelectionOwner(display, selection);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
+ internal extern static int _XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
+ internal static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time)
+ {
+ DebugHelper.TraceWriteLine ("XSetSelectionOwner");
+ return _XSetSelectionOwner(display, selection, owner, time);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
+ internal extern static int _XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
+ internal static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask)
+ {
+ DebugHelper.TraceWriteLine ("XSetPlaneMask");
+ return _XSetPlaneMask(display, gc, mask);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetForeground")]
+ internal extern static int _XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
+ internal static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground)
+ {
+ DebugHelper.TraceWriteLine ("XSetForeground");
+ return _XSetForeground(display, gc, foreground);
+ }
+
+ [DllImport ("libX11", EntryPoint="XSetBackground")]
+ internal extern static int _XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
+ internal static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background)
+ {
+ DebugHelper.TraceWriteLine ("XSetBackground");
+ return _XSetBackground(display, gc, background);
+ }
+
+ [DllImport ("libX11", EntryPoint="XBell")]
+ internal extern static int _XBell(IntPtr display, int percent);
+ internal static int XBell(IntPtr display, int percent)
+ {
+ DebugHelper.TraceWriteLine ("XBell");
+ return _XBell(display, percent);
+ }
+
+ [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")]
+ internal extern static int _XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
+ internal static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time)
+ {
+ DebugHelper.TraceWriteLine ("XChangeActivePointerGrab");
+ return _XChangeActivePointerGrab (display, event_mask, cursor, time);
+ }
+
+ [DllImport ("libX11", EntryPoint="XFilterEvent")]
+ internal extern static bool _XFilterEvent(ref XEvent xevent, IntPtr window);
+ internal static bool XFilterEvent(ref XEvent xevent, IntPtr window)
+ {
+ DebugHelper.TraceWriteLine ("XFilterEvent");
+ return _XFilterEvent(ref xevent, window);
+ }
+
+ [DllImport ("libX11", EntryPoint="XkbSetDetectableAutoRepeat")]
+ internal extern static void _XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
+ internal static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported)
+ {
+ DebugHelper.TraceWriteLine ("XkbSetDetectableAutoRepeat");
+ _XkbSetDetectableAutoRepeat (display, detectable, supported);
+ }
+
+ [DllImport ("libX11", EntryPoint="XPeekEvent")]
+ internal extern static void _XPeekEvent (IntPtr display, ref XEvent xevent);
+ internal static void XPeekEvent (IntPtr display, ref XEvent xevent)
+ {
+ DebugHelper.TraceWriteLine ("XPeekEvent");
+ _XPeekEvent (display, ref xevent);
+ }
+
+ [DllImport ("libX11", EntryPoint="XIfEvent")]
+ internal extern static void _XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);
+ internal static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg)
+ {
+ DebugHelper.TraceWriteLine ("XIfEvent");
+ _XIfEvent (display, ref xevent, event_predicate, arg);
+ }
+#endregion
+
+#region Xinerama imports
+ [DllImport ("libXinerama", EntryPoint="XineramaQueryScreens")]
+ extern static IntPtr _XineramaQueryScreens (IntPtr display, out int number);
+ internal static IntPtr XineramaQueryScreens (IntPtr display, out int number)
+ {
+ DebugHelper.TraceWriteLine ("XineramaQueryScreens");
+ return _XineramaQueryScreens (display, out number);
+ }
+
+ [DllImport ("libXinerama", EntryPoint="XineramaIsActive")]
+ extern static bool _XineramaIsActive (IntPtr display);
+ static bool XineramaNotInstalled;
+
+ internal static bool XineramaIsActive (IntPtr display)
+ {
+ DebugHelper.TraceWriteLine ("XineramaIsActive");
+
+ if (XineramaNotInstalled)
+ return false;
+ try {
+ return _XineramaIsActive (display);
+ } catch (DllNotFoundException) {
+ // Xinerama isn't installed
+ XineramaNotInstalled = true;
+ return false;
+ }
+ }
+#endregion
+
+#else //no TRACE defined
+
+#region Xcursor imports
+ [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")]
+ internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")]
+ internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")]
+ internal extern static void XcursorImagesDestroy (IntPtr images);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")]
+ internal extern static int XcursorGetDefaultSize (IntPtr display);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")]
+ internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")]
+ internal extern static IntPtr XcursorGetTheme (IntPtr display);
+#endregion
+ #region X11 Imports
+ [DllImport ("libX11", EntryPoint="XOpenDisplay")]
+ internal extern static IntPtr XOpenDisplay(IntPtr display);
+ [DllImport ("libX11", EntryPoint="XCloseDisplay")]
+ internal extern static int XCloseDisplay(IntPtr display);
+ [DllImport ("libX11", EntryPoint="XSynchronize")]
+ internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
+
+ [DllImport ("libX11", EntryPoint="XCreateWindow")]
+ internal extern static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes);
+
+ [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
+ internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
+
+ [DllImport ("libX11", EntryPoint="XMapWindow")]
+ internal extern static int XMapWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XMapRaised")]
+ internal extern static int XMapRaised(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XUnmapWindow")]
+ internal extern static int XUnmapWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XMapSubwindows")]
+ internal extern static int XMapSubindows(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
+ internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XRootWindow")]
+ internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XNextEvent")]
+ internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
+
+ [DllImport ("libX11", EntryPoint="XConnectionNumber")]
+ internal extern static int XConnectionNumber (IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XPending")]
+ internal extern static int XPending (IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XSelectInput")]
+ internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
+
+ [DllImport ("libX11", EntryPoint="XDestroyWindow")]
+ internal extern static int XDestroyWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XReparentWindow")]
+ internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
+
+ [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
+ extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+ internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height)
+ {
+ int ret = XMoveResizeWindow (display, window, x, y, width, height);
+ Keyboard.MoveCurrentCaretPos ();
+ return ret;
+ }
+
+ [DllImport ("libX11", EntryPoint="XResizeWindow")]
+ internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
+
+ [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
+ internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
+
+ [DllImport ("libX11", EntryPoint="XFlush")]
+ internal extern static int XFlush(IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XSetWMName")]
+ internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
+
+ [DllImport ("libX11", EntryPoint="XStoreName")]
+ internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
+
+ [DllImport ("libX11", EntryPoint="XFetchName")]
+ internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
+
+ [DllImport ("libX11", EntryPoint="XSendEvent")]
+ internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
+
+ [DllImport ("libX11", EntryPoint="XQueryTree")]
+ internal extern static int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return);
+
+ [DllImport ("libX11", EntryPoint="XFree")]
+ internal extern static int XFree(IntPtr data);
+
+ [DllImport ("libX11", EntryPoint="XRaiseWindow")]
+ internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XLowerWindow")]
+ internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XConfigureWindow")]
+ internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
+
+ [DllImport ("libX11", EntryPoint="XInternAtom")]
+ internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
+
+ [DllImport ("libX11", EntryPoint="XInternAtoms")]
+ internal extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
+
+ [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
+ internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
+
+ [DllImport ("libX11", EntryPoint="XGrabPointer")]
+ internal extern static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp);
+
+ [DllImport ("libX11", EntryPoint="XUngrabPointer")]
+ internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp);
+
+ [DllImport ("libX11", EntryPoint="XQueryPointer")]
+ internal extern static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons);
+
+ [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
+ internal extern static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return);
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth);
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth);
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth);
+
+ [DllImport ("libX11", EntryPoint="XGetGeometry")]
+ internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth);
+
+ [DllImport ("libX11", EntryPoint="XWarpPointer")]
+ internal extern static uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y);
+
+ [DllImport ("libX11", EntryPoint="XClearWindow")]
+ internal extern static int XClearWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XClearArea")]
+ internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
+
+ // Colormaps
+ [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
+ internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
+ internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
+
+ [DllImport ("libX11", EntryPoint="XDefaultVisual")]
+ internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XDefaultDepth")]
+ internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XDefaultScreen")]
+ internal extern static int XDefaultScreen(IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XDefaultColormap")]
+ internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XLookupColor")]
+ internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
+
+ [DllImport ("libX11", EntryPoint="XAllocColor")]
+ internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
+
+ [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
+ internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
+
+ [DllImport ("libX11", EntryPoint="XDeleteProperty")]
+ internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
+
+ // Drawing
+ [DllImport ("libX11", EntryPoint="XCreateGC")]
+ internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
+
+ [DllImport ("libX11", EntryPoint="XFreeGC")]
+ internal extern static int XFreeGC(IntPtr display, IntPtr gc);
+
+ [DllImport ("libX11", EntryPoint="XSetFunction")]
+ internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
+
+ [DllImport ("libX11", EntryPoint="XSetLineAttributes")]
+ internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
+
+ [DllImport ("libX11", EntryPoint="XDrawLine")]
+ internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
+
+ [DllImport ("libX11", EntryPoint="XDrawRectangle")]
+ internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
+
+ [DllImport ("libX11", EntryPoint="XFillRectangle")]
+ internal extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
+
+ [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
+ internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
+
+ [DllImport ("libX11", EntryPoint="XCopyArea")]
+ internal extern static int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
+
+ [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
+ internal extern static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop);
+
+ [DllImport ("libX11", EntryPoint="XSetInputFocus")]
+ internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XIconifyWindow")]
+ internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XDefineCursor")]
+ internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
+
+ [DllImport ("libX11", EntryPoint="XUndefineCursor")]
+ internal extern static int XUndefineCursor(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XFreeCursor")]
+ internal extern static int XFreeCursor(IntPtr display, IntPtr cursor);
+
+ [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
+ internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
+ internal extern static IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot);
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
+ internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmap")]
+ internal extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
+
+ [DllImport ("libX11", EntryPoint="XFreePixmap")]
+ internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
+
+ [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
+ internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
+
+ [DllImport ("libX11", EntryPoint="XQueryExtension")]
+ internal extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
+
+ [DllImport ("libX11", EntryPoint="XWhitePixel")]
+ internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
+
+ [DllImport ("libX11", EntryPoint="XBlackPixel")]
+ internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
+
+ [DllImport ("libX11", EntryPoint="XGrabServer")]
+ internal extern static void XGrabServer(IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XUngrabServer")]
+ internal extern static void XUngrabServer(IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XGetWMNormalHints")]
+ internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
+
+ [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
+ internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport ("libX11", EntryPoint="XSetZoomHints")]
+ internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport ("libX11", EntryPoint="XSetWMHints")]
+ internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
+
+ [DllImport ("libX11", EntryPoint="XGetIconSizes")]
+ internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
+
+ [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
+ internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
+
+ [DllImport ("libX11", EntryPoint="XGetErrorText")]
+ internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
+
+ [DllImport ("libX11", EntryPoint="XInitThreads")]
+ internal extern static int XInitThreads();
+
+ [DllImport ("libX11", EntryPoint="XConvertSelection")]
+ internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
+ internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
+
+ [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
+ internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
+ internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
+
+ [DllImport ("libX11", EntryPoint="XSetForeground")]
+ internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
+
+ [DllImport ("libX11", EntryPoint="XSetBackground")]
+ internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
+
+ [DllImport ("libX11", EntryPoint="XBell")]
+ internal extern static int XBell(IntPtr display, int percent);
+
+ [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")]
+ internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XFilterEvent")]
+ internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XkbSetDetectableAutoRepeat")]
+ internal extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
+
+ [DllImport ("libX11", EntryPoint="XPeekEvent")]
+ internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
+
+ [DllImport ("libX11", EntryPoint="XIfEvent")]
+ internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);
+
+ [DllImport ("libX11", EntryPoint="XGetInputFocus")]
+ internal extern static void XGetInputFocus (IntPtr display, out IntPtr focus, out IntPtr revert_to);
+ #endregion
+#region Gtk/Gdk imports
+ [DllImport("libgdk-x11-2.0")]
+ internal extern static IntPtr gdk_atom_intern (string atomName, bool onlyIfExists);
+
+ [DllImport("libgtk-x11-2.0")]
+ internal extern static IntPtr gtk_clipboard_get (IntPtr atom);
+
+ [DllImport("libgtk-x11-2.0")]
+ internal extern static void gtk_clipboard_store (IntPtr clipboard);
+
+ [DllImport("libgtk-x11-2.0")]
+ internal extern static void gtk_clipboard_set_text (IntPtr clipboard, string text, int len);
+#endregion
+
+
+#region Xinerama imports
+ [DllImport ("libXinerama")]
+ internal extern static IntPtr XineramaQueryScreens (IntPtr display, out int number);
+
+ [DllImport ("libXinerama", EntryPoint = "XineramaIsActive")]
+ extern static bool _XineramaIsActive (IntPtr display);
+ static bool XineramaNotInstalled;
+
+ internal static bool XineramaIsActive (IntPtr display)
+ {
+ if (XineramaNotInstalled)
+ return false;
+ try {
+ return _XineramaIsActive (display);
+ } catch (DllNotFoundException) {
+ // Xinerama isn't installed
+ XineramaNotInstalled = true;
+ return false;
+ }
+ }
+#endregion
+
+#endif
+ }
+}
diff --git a/source/ShiftUI/Internal/XplatUIX11GTK.cs b/source/ShiftUI/Internal/XplatUIX11GTK.cs
new file mode 100644
index 0000000..03ea185
--- /dev/null
+++ b/source/ShiftUI/Internal/XplatUIX11GTK.cs
@@ -0,0 +1,4634 @@
+// 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-2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+// Alexander Olk [email protected]
+//
+//
+
+// NOTE:
+// This driver understands the following environment variables: (Set the var to enable feature)
+//
+// MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered;
+// by default a message is displayed but execution continues
+//
+// MONO_XSYNC = perform all X11 commands synchronous; this is slower but
+// helps in debugging errors
+//
+
+// NOT COMPLETE - WORK IN PROGRESS
+
+// One feature of the driver is, that PaintEventstart returns a graphics context created from a offscreen drawable (pixmap)
+
+// define to log Window handles and relationships to stdout
+#undef DriverDebug
+
+// Extra detailed debug
+#undef DriverDebugExtra
+
+using System;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+
+// Only do the poll when building with mono for now
+#if __MonoCS__
+using Mono.Unix.Native;
+#endif
+
+/// X11 Version
+namespace ShiftUI {
+ internal class XplatUIX11GTK : XplatUIDriver {
+
+ internal enum GdkWindowClass {
+ GDK_INPUT_OUTPUT,
+ GDK_INPUT_ONLY
+ }
+
+ internal enum GdkWindowType {
+ GDK_WINDOW_ROOT,
+ GDK_WINDOW_TOPLEVEL,
+ GDK_WINDOW_CHILD,
+ GDK_WINDOW_DIALOG,
+ GDK_WINDOW_TEMP,
+ GDK_WINDOW_FOREIGN
+ }
+
+ internal enum GdkWindowHints {
+ GDK_HINT_POS = 1 << 0,
+ GDK_HINT_MIN_SIZE = 1 << 1,
+ GDK_HINT_MAX_SIZE = 1 << 2,
+ GDK_HINT_BASE_SIZE = 1 << 3,
+ GDK_HINT_ASPECT = 1 << 4,
+ GDK_HINT_RESIZE_INC = 1 << 5,
+ GDK_HINT_WIN_GRAVITY = 1 << 6,
+ GDK_HINT_USER_POS = 1 << 7,
+ GDK_HINT_USER_SIZE = 1 << 8
+ }
+
+ internal enum GdkGravity {
+ GDK_GRAVITY_NORTH_WEST = 1,
+ GDK_GRAVITY_NORTH,
+ GDK_GRAVITY_NORTH_EAST,
+ GDK_GRAVITY_WEST,
+ GDK_GRAVITY_CENTER,
+ GDK_GRAVITY_EAST,
+ GDK_GRAVITY_SOUTH_WEST,
+ GDK_GRAVITY_SOUTH,
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_STATIC
+ }
+
+ internal enum GdkWindowEdge {
+ GDK_WINDOW_EDGE_NORTH_WEST,
+ GDK_WINDOW_EDGE_NORTH,
+ GDK_WINDOW_EDGE_NORTH_EAST,
+ GDK_WINDOW_EDGE_WEST,
+ GDK_WINDOW_EDGE_EAST,
+ GDK_WINDOW_EDGE_SOUTH_WEST,
+ GDK_WINDOW_EDGE_SOUTH,
+ GDK_WINDOW_EDGE_SOUTH_EAST
+ }
+
+ internal enum GdkWindowTypeHint {
+ GDK_WINDOW_TYPE_HINT_NORMAL,
+ GDK_WINDOW_TYPE_HINT_DIALOG,
+ GDK_WINDOW_TYPE_HINT_MENU,
+ GDK_WINDOW_TYPE_HINT_TOOLBAR,
+ GDK_WINDOW_TYPE_HINT_SPLASHSCREEN,
+ GDK_WINDOW_TYPE_HINT_UTILITY,
+ GDK_WINDOW_TYPE_HINT_DOCK,
+ GDK_WINDOW_TYPE_HINT_DESKTOP
+ }
+
+ internal enum GdkWindowAttributesType {
+ GDK_WA_TITLE = 1 << 1,
+ GDK_WA_X = 1 << 2,
+ GDK_WA_Y = 1 << 3,
+ GDK_WA_CURSOR = 1 << 4,
+ GDK_WA_COLORMAP = 1 << 5,
+ GDK_WA_VISUAL = 1 << 6,
+ GDK_WA_WMCLASS = 1 << 7,
+ GDK_WA_NOREDIR = 1 << 8
+ }
+
+ internal enum GdkEventMask {
+ GDK_EXPOSURE_MASK = 1 << 1,
+ GDK_POINTER_MOTION_MASK = 1 << 2,
+ GDK_POINTER_MOTION_HINT_MASK = 1 << 3,
+ GDK_BUTTON_MOTION_MASK = 1 << 4,
+ GDK_BUTTON1_MOTION_MASK = 1 << 5,
+ GDK_BUTTON2_MOTION_MASK = 1 << 6,
+ GDK_BUTTON3_MOTION_MASK = 1 << 7,
+ GDK_BUTTON_PRESS_MASK = 1 << 8,
+ GDK_BUTTON_RELEASE_MASK = 1 << 9,
+ GDK_KEY_PRESS_MASK = 1 << 10,
+ GDK_KEY_RELEASE_MASK = 1 << 11,
+ GDK_ENTER_NOTIFY_MASK = 1 << 12,
+ GDK_LEAVE_NOTIFY_MASK = 1 << 13,
+ GDK_FOCUS_CHANGE_MASK = 1 << 14,
+ GDK_STRUCTURE_MASK = 1 << 15,
+ GDK_PROPERTY_CHANGE_MASK = 1 << 16,
+ GDK_VISIBILITY_NOTIFY_MASK = 1 << 17,
+ GDK_PROXIMITY_IN_MASK = 1 << 18,
+ GDK_PROXIMITY_OUT_MASK = 1 << 19,
+ GDK_SUBSTRUCTURE_MASK = 1 << 20,
+ GDK_SCROLL_MASK = 1 << 21,
+ GDK_ALL_EVENTS_MASK = 0x3FFFFE
+ }
+
+ internal enum GdkEventType {
+ GDK_NOTHING = -1,
+ GDK_DELETE = 0,
+ GDK_DESTROY = 1,
+ GDK_EXPOSE = 2,
+ GDK_MOTION_NOTIFY = 3,
+ GDK_BUTTON_PRESS = 4,
+ GDK_2BUTTON_PRESS = 5,
+ GDK_3BUTTON_PRESS = 6,
+ GDK_BUTTON_RELEASE = 7,
+ GDK_KEY_PRESS = 8,
+ GDK_KEY_RELEASE = 9,
+ GDK_ENTER_NOTIFY = 10,
+ GDK_LEAVE_NOTIFY = 11,
+ GDK_FOCUS_CHANGE = 12,
+ GDK_CONFIGURE = 13,
+ GDK_MAP = 14,
+ GDK_UNMAP = 15,
+ GDK_PROPERTY_NOTIFY = 16,
+ GDK_SELECTION_CLEAR = 17,
+ GDK_SELECTION_REQUEST = 18,
+ GDK_SELECTION_NOTIFY = 19,
+ GDK_PROXIMITY_IN = 20,
+ GDK_PROXIMITY_OUT = 21,
+ GDK_DRAG_ENTER = 22,
+ GDK_DRAG_LEAVE = 23,
+ GDK_DRAG_MOTION = 24,
+ GDK_DRAG_STATUS = 25,
+ GDK_DROP_START = 26,
+ GDK_DROP_FINISHED = 27,
+ GDK_CLIENT_EVENT = 28,
+ GDK_VISIBILITY_NOTIFY = 29,
+ GDK_NO_EXPOSE = 30,
+ GDK_SCROLL = 31,
+ GDK_WINDOW_STATE = 32,
+ GDK_SETTING = 33,
+ GDK_OWNER_CHANGE = 34,
+ GDK_GRAB_BROKEN = 35
+ }
+
+ internal enum GdkWMDecoration {
+ GDK_DECOR_ALL = 1 << 0,
+ GDK_DECOR_BORDER = 1 << 1,
+ GDK_DECOR_RESIZEH = 1 << 2,
+ GDK_DECOR_TITLE = 1 << 3,
+ GDK_DECOR_MENU = 1 << 4,
+ GDK_DECOR_MINIMIZE = 1 << 5,
+ GDK_DECOR_MAXIMIZE = 1 << 6
+ }
+
+ internal enum GdkWMFunction {
+ GDK_FUNC_ALL = 1 << 0,
+ GDK_FUNC_RESIZE = 1 << 1,
+ GDK_FUNC_MOVE = 1 << 2,
+ GDK_FUNC_MINIMIZE = 1 << 3,
+ GDK_FUNC_MAXIMIZE = 1 << 4,
+ GDK_FUNC_CLOSE = 1 << 5
+ }
+
+ internal enum GdkCursorType {
+ GDK_X_CURSOR = 0,
+ GDK_ARROW = 2,
+ GDK_BASED_ARROW_DOWN = 4,
+ GDK_BASED_ARROW_UP = 6,
+ GDK_BOAT = 8,
+ GDK_BOGOSITY = 10,
+ GDK_BOTTOM_LEFT_CORNER = 12,
+ GDK_BOTTOM_RIGHT_CORNER = 14,
+ GDK_BOTTOM_SIDE = 16,
+ GDK_BOTTOM_TEE = 18,
+ GDK_BOX_SPIRAL = 20,
+ GDK_CENTER_PTR = 22,
+ GDK_CIRCLE = 24,
+ GDK_CLOCK = 26,
+ GDK_COFFEE_MUG = 28,
+ GDK_CROSS = 30,
+ GDK_CROSS_REVERSE = 32,
+ GDK_CROSSHAIR = 34,
+ GDK_DIAMOND_CROSS = 36,
+ GDK_DOT = 38,
+ GDK_DOTBOX = 40,
+ GDK_DOUBLE_ARROW = 42,
+ GDK_DRAFT_LARGE = 44,
+ GDK_DRAFT_SMALL = 46,
+ GDK_DRAPED_BOX = 48,
+ GDK_EXCHANGE = 50,
+ GDK_FLEUR = 52,
+ GDK_GOBBLER = 54,
+ GDK_GUMBY = 56,
+ GDK_HAND1 = 58,
+ GDK_HAND2 = 60,
+ GDK_HEART = 62,
+ GDK_ICON = 64,
+ GDK_IRON_CROSS = 66,
+ GDK_LEFT_PTR = 68,
+ GDK_LEFT_SIDE = 70,
+ GDK_LEFT_TEE = 72,
+ GDK_LEFTBUTTON = 74,
+ GDK_LL_ANGLE = 76,
+ GDK_LR_ANGLE = 78,
+ GDK_MAN = 80,
+ GDK_MIDDLEBUTTON = 82,
+ GDK_MOUSE = 84,
+ GDK_PENCIL = 86,
+ GDK_PIRATE = 88,
+ GDK_PLUS = 90,
+ GDK_QUESTION_ARROW = 92,
+ GDK_RIGHT_PTR = 94,
+ GDK_RIGHT_SIDE = 96,
+ GDK_RIGHT_TEE = 98,
+ GDK_RIGHTBUTTON = 100,
+ GDK_RTL_LOGO = 102,
+ GDK_SAILBOAT = 104,
+ GDK_SB_DOWN_ARROW = 106,
+ GDK_SB_H_DOUBLE_ARROW = 108,
+ GDK_SB_LEFT_ARROW = 110,
+ GDK_SB_RIGHT_ARROW = 112,
+ GDK_SB_UP_ARROW = 114,
+ GDK_SB_V_DOUBLE_ARROW = 116,
+ GDK_SHUTTLE = 118,
+ GDK_SIZING = 120,
+ GDK_SPIDER = 122,
+ GDK_SPRAYCAN = 124,
+ GDK_STAR = 126,
+ GDK_TARGET = 128,
+ GDK_TCROSS = 130,
+ GDK_TOP_LEFT_ARROW = 132,
+ GDK_TOP_LEFT_CORNER = 134,
+ GDK_TOP_RIGHT_CORNER = 136,
+ GDK_TOP_SIDE = 138,
+ GDK_TOP_TEE = 140,
+ GDK_TREK = 142,
+ GDK_UL_ANGLE = 144,
+ GDK_UMBRELLA = 146,
+ GDK_UR_ANGLE = 148,
+ GDK_WATCH = 150,
+ GDK_XTERM = 152,
+ GDK_LAST_CURSOR,
+ GDK_CURSOR_IS_PIXMAP = -1
+ }
+
+ internal enum GdkPropMode {
+ GDK_PROP_MODE_REPLACE,
+ GDK_PROP_MODE_PREPEND,
+ GDK_PROP_MODE_APPEND
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct GdkGeometry {
+ internal int min_width;
+ internal int min_height;
+ internal int max_width;
+ internal int max_height;
+ internal int base_width;
+ internal int base_height;
+ internal int width_inc;
+ internal int height_inc;
+ internal double min_aspect;
+ internal double max_aspect;
+ internal GdkGravity win_gravity;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct GdkWindowAttr {
+ internal string title;
+ internal int event_mask;
+ internal int x, y;
+ internal int width;
+ internal int height;
+ internal GdkWindowClass wclass;
+ internal IntPtr visual;
+ internal IntPtr colormap;
+ internal GdkWindowType window_type;
+ internal IntPtr cursor;
+ internal string wmclass_name;
+ internal string wmclass_class;
+ internal bool override_redirect;
+ }
+
+ #region Local Variables
+ // General
+ static volatile XplatUIX11GTK Instance;
+ private static int RefCount;
+ private static object XlibLock; // Our locking object
+
+ // General X11
+ private static IntPtr DisplayHandle; // X11 handle to display
+ private static IntPtr GdkDisplayHandle; // gdk handle to display
+ private static int ScreenNo; // Screen number used
+ private static IntPtr GdkScreen;
+ private static IntPtr DefaultColormap; // Colormap for screen
+ private static IntPtr GdkDefaultColormap; // Gdk Colormap for screen
+ private static IntPtr CustomVisual; // Visual for window creation
+ private static IntPtr GdkCustomVisual;
+ private static IntPtr CustomColormap; // Colormap for window creation
+ private static IntPtr GdkCustomColormap;
+ private static int VisualBestDepth;
+ private static IntPtr RootWindow; // Handle of the root window for the screen/display
+ private static IntPtr GdkRootWindow; // Gdk handle of the root window for the screen/display
+ private static IntPtr FosterParent; // Container to hold child windows until their parent exists
+ private static IntPtr GdkFosterParent; // Container to hold child windows until their parent exists
+ private static XErrorHandler ErrorHandler; // Error handler delegate
+ private static bool ErrorExceptions; // Throw exceptions on X errors
+ private static bool PostQuitState; // True if we've got an pending exit
+
+ // Clipboard
+ private static IntPtr ClipMagic = new IntPtr(27051977);
+
+ // Communication
+ private static int PostAtom; // PostMessage atom
+ private static int AsyncAtom; // Support for async messages
+
+ // Message Loop
+ private static XEventQueue MessageQueue; // Holds our queued up events
+ #if __MonoCS__ //
+ private static Pollfd[] pollfds; // For watching the X11 socket
+ #endif //
+ private static X11Keyboard Keyboard; //
+ private static X11Dnd Dnd;
+ private static Socket listen; //
+ private static Socket wake; //
+ private static Socket wake_receive; //
+ private static byte[] network_buffer; //
+
+
+ // Focus tracking
+ private static IntPtr ActiveWindow; // Handle of the active window
+ private static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any)
+
+ // Modality support
+ private static Stack ModalWindows; // Stack of our modal windows
+
+ // Systray
+ private static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window
+
+ // Cursors
+ private static IntPtr LastCursorWindow; // The last window we set the cursor on
+ private static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
+ private static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
+
+ // Caret
+ private static CaretStruct Caret; //
+
+ // Support for Window Styles
+ private static int[] NetAtoms; // All atoms we know
+
+ // mouse hover message generation
+ private static HoverStruct HoverState; //
+
+ // double click message generation
+ private static ClickStruct ClickPending; //
+
+ // Support for mouse grab
+ private static GrabStruct Grab; //
+
+ // State
+ private static Point MousePosition; // Last position of mouse, in screen coords
+ internal static MouseButtons MouseState; // Last state of mouse buttons
+
+ // Timers
+ private static ArrayList TimerList; // Holds SWF.Timers
+
+ // 'Constants'
+ private static int DoubleClickInterval; // msec; max interval between clicks to count as double click
+
+ const GdkEventMask GdkSelectInputMask = GdkEventMask.GDK_BUTTON_PRESS_MASK |
+ GdkEventMask.GDK_BUTTON_RELEASE_MASK |
+ GdkEventMask.GDK_KEY_PRESS_MASK |
+ GdkEventMask.GDK_KEY_RELEASE_MASK |
+ GdkEventMask.GDK_ENTER_NOTIFY_MASK |
+ GdkEventMask.GDK_LEAVE_NOTIFY_MASK |
+ GdkEventMask.GDK_EXPOSURE_MASK |
+ GdkEventMask.GDK_FOCUS_CHANGE_MASK |
+ GdkEventMask.GDK_POINTER_MOTION_MASK |
+ GdkEventMask.GDK_VISIBILITY_NOTIFY_MASK |
+ GdkEventMask.GDK_SUBSTRUCTURE_MASK |
+ GdkEventMask.GDK_STRUCTURE_MASK;
+
+ static readonly object lockobj = new object ();
+
+ static Hashtable backing_store = new Hashtable (5);
+
+ #endregion // Local Variables
+ #region Constructors
+ private XplatUIX11GTK ()
+ {
+ Console.WriteLine ("XplatUIX11GTK ctor...");
+ // Handle singleton stuff first
+ RefCount = 0;
+
+ // init gdk
+ gdk_init_check (IntPtr.Zero, IntPtr.Zero);
+
+ // Now regular initialization
+ XlibLock = new object ();
+ MessageQueue = new XEventQueue ();
+ TimerList = new ArrayList ();
+ XInitThreads ();
+
+ ErrorExceptions = false;
+
+ // X11 Initialization
+ SetDisplay (gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
+ X11DesktopColors.Initialize ();
+
+ // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does)
+ ErrorHandler = new XErrorHandler (HandleError);
+ XSetErrorHandler (ErrorHandler);
+ }
+ #endregion // Constructors
+
+ #region Singleton Specific Code
+ public static XplatUIX11GTK GetInstance ()
+ {
+ lock (lockobj) {
+ if (Instance == null) {
+ Instance = new XplatUIX11GTK ();
+ }
+ RefCount++;
+ }
+ return Instance;
+ }
+
+ public int Reference {
+ get {
+ return RefCount;
+ }
+ }
+ #endregion
+
+ #region Internal Properties
+ internal static IntPtr Display {
+ get {
+ return DisplayHandle;
+ }
+
+ set {
+ XplatUIX11GTK.GetInstance ().SetDisplay (value);
+ }
+ }
+
+ internal static int Screen {
+ get {
+ return ScreenNo;
+ }
+
+ set {
+ ScreenNo = value;
+ }
+ }
+
+ internal static IntPtr RootWindowHandle {
+ get {
+ return RootWindow;
+ }
+
+ set {
+ RootWindow = value;
+ }
+ }
+
+ internal static IntPtr Visual {
+ get {
+ return CustomVisual;
+ }
+
+ set {
+ CustomVisual = value;
+ }
+ }
+
+ internal static IntPtr ColorMap {
+ get {
+ return CustomColormap;
+ }
+
+ set {
+ CustomColormap = value;
+ }
+ }
+ #endregion
+
+ #region XExceptionClass
+ internal class XException : ApplicationException {
+ IntPtr Display;
+ IntPtr ResourceID;
+ IntPtr Serial;
+ XRequest RequestCode;
+ byte ErrorCode;
+ byte MinorCode;
+
+ public XException (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode)
+ {
+ this.Display = Display;
+ this.ResourceID = ResourceID;
+ this.Serial = Serial;
+ this.RequestCode = RequestCode;
+ this.ErrorCode = ErrorCode;
+ this.MinorCode = MinorCode;
+ }
+
+ public override string Message {
+ get {
+ return GetMessage (Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode);
+ }
+ }
+
+ public static string GetMessage (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode)
+ {
+ StringBuilder sb;
+ string x_error_text;
+ string error;
+
+ sb = new StringBuilder (160);
+ XGetErrorText (Display, ErrorCode, sb, sb.Capacity);
+ x_error_text = sb.ToString ();
+
+ error = String.Format ("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:x}\n Serial: {4}", x_error_text, RequestCode, RequestCode, ResourceID.ToInt32 (), Serial);
+ return error;
+ }
+ }
+ #endregion // XExceptionClass
+
+ #region Internal Methods
+ // native X display handle
+ internal void SetDisplay (IntPtr display_handle)
+ {
+ if (display_handle != IntPtr.Zero) {
+ Hwnd hwnd;
+
+ if ((GdkDisplayHandle != IntPtr.Zero) && (GdkFosterParent != IntPtr.Zero)) {
+ hwnd = Hwnd.ObjectFromHandle (gdk_x11_drawable_get_xid (GdkFosterParent));
+ gdk_window_destroy (GdkFosterParent);
+ hwnd.Dispose ();
+ }
+
+ if (GdkDisplayHandle != IntPtr.Zero) {
+ gdk_display_close (GdkDisplayHandle);
+ }
+
+ DisplayHandle = display_handle;
+ GdkDisplayHandle = gdk_x11_lookup_xdisplay (display_handle);
+
+ // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has
+ // been hacked to do this for us.
+ Graphics.FromHdcInternal (DisplayHandle);
+
+ // Debugging support
+ if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
+ XSynchronize (DisplayHandle, true);
+ }
+
+ if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
+ ErrorExceptions = true;
+ }
+
+ // Generic X11 setup
+ GdkScreen = gdk_screen_get_default ();
+ // or gdk_x11_get_default_screen
+ ScreenNo = gdk_screen_get_number (GdkScreen);
+ GdkRootWindow = gdk_get_default_root_window ();
+ RootWindow = gdk_x11_drawable_get_xid (GdkRootWindow);
+ GdkDefaultColormap = gdk_colormap_get_system ();
+ DefaultColormap = gdk_x11_colormap_get_xcolormap (GdkDefaultColormap);
+
+ VisualBestDepth = gdk_visual_get_best_depth ();
+ //Console.WriteLine (VisualBestDepth);
+
+ // Create the foster parent
+ FosterParent = XCreateSimpleWindow (DisplayHandle, RootWindow, 0, 0, 1, 1, 4, 0, 0);
+ GdkFosterParent = gdk_window_foreign_new (FosterParent);
+
+ if (GdkFosterParent == IntPtr.Zero) {
+ Console.WriteLine ("XplatUIX11GTK Constructor failed to create FosterParent");
+ }
+
+ hwnd = new Hwnd ();
+
+ hwnd.WholeWindow = FosterParent;
+ hwnd.ClientWindow = FosterParent;
+
+ // For sleeping on the X11 socket
+ listen = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
+ IPEndPoint ep = new IPEndPoint (IPAddress.Loopback, 0);
+ listen.Bind (ep);
+ listen.Listen (1);
+
+ // To wake up when a timer is ready
+ network_buffer = new byte [10];
+
+ wake = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
+ wake.Connect (listen.LocalEndPoint);
+ wake_receive = listen.Accept ();
+
+ #if __MonoCS__
+ pollfds = new Pollfd [2];
+ pollfds [0] = new Pollfd ();
+ pollfds [0].fd = XConnectionNumber (DisplayHandle);
+ pollfds [0].events = PollEvents.POLLIN;
+
+ pollfds [1] = new Pollfd ();
+ pollfds [1].fd = wake_receive.Handle.ToInt32 ();
+ pollfds [1].events = PollEvents.POLLIN;
+ #endif
+
+ Keyboard = new X11Keyboard (DisplayHandle);
+ Dnd = new X11Dnd (DisplayHandle);
+
+ PostQuitState = false;
+
+ DoubleClickInterval = 500;
+
+ HoverState.Interval = 500;
+ HoverState.Timer = new Timer ();
+ HoverState.Timer.Enabled = false;
+ HoverState.Timer.Interval = HoverState.Interval;
+ HoverState.Timer.Tick += new EventHandler (MouseHover);
+ HoverState.X = -1;
+ HoverState.Y = -1;
+
+ ActiveWindow = IntPtr.Zero;
+ FocusWindow = IntPtr.Zero;
+ ModalWindows = new Stack (3);
+
+ MouseState = MouseButtons.None;
+ MousePosition = new Point (0, 0);
+
+ Caret.Timer = new Timer ();
+ Caret.Timer.Interval = 500; // FIXME - where should this number come from?
+ Caret.Timer.Tick += new EventHandler (CaretCallback);
+
+ SetupAtoms ();
+
+ // Grab atom changes off the root window to catch certain WM events
+ gdk_window_set_events (GdkRootWindow, (int)GdkEventMask.GDK_PROPERTY_CHANGE_MASK);
+
+ // Handle any upcoming errors
+ ErrorHandler = new XErrorHandler (HandleError);
+ XSetErrorHandler (ErrorHandler);
+ } else {
+ throw new ArgumentNullException ("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)");
+ }
+ }
+ #endregion // Internal Methods
+
+ #region Private Methods
+ private static void SetupAtoms ()
+ {
+ NetAtoms = new int [(int)NA.LAST_NET_ATOM];
+
+ NetAtoms [(int)NA.WM_PROTOCOLS] = XInternAtom (DisplayHandle, "WM_PROTOCOLS", false);
+ NetAtoms [(int)NA.WM_DELETE_WINDOW] = XInternAtom (DisplayHandle, "WM_DELETE_WINDOW", false);
+ NetAtoms [(int)NA.WM_TAKE_FOCUS] = XInternAtom (DisplayHandle, "WM_TAKE_FOCUS", false);
+
+ NetAtoms [(int)NA._NET_SUPPORTED] = XInternAtom (DisplayHandle, "_NET_SUPPORTED", false);
+ NetAtoms [(int)NA._NET_CLIENT_LIST] = XInternAtom (DisplayHandle, "_NET_CLIENT_LIST", false);
+ NetAtoms [(int)NA._NET_NUMBER_OF_DESKTOPS] = XInternAtom (DisplayHandle, "_NET_NUMBER_OF_DESKTOPS", false);
+ NetAtoms [(int)NA._NET_DESKTOP_GEOMETRY] = XInternAtom (DisplayHandle, "_NET_DESKTOP_GEOMETRY", false);
+ NetAtoms [(int)NA._NET_DESKTOP_VIEWPORT] = XInternAtom (DisplayHandle, "_NET_DESKTOP_VIEWPORT", false);
+ NetAtoms [(int)NA._NET_CURRENT_DESKTOP] = XInternAtom (DisplayHandle, "_NET_CURRENT_DESKTOP", false);
+ NetAtoms [(int)NA._NET_DESKTOP_NAMES] = XInternAtom (DisplayHandle, "_NET_DESKTOP_NAMES", false);
+ NetAtoms [(int)NA._NET_ACTIVE_WINDOW] = XInternAtom (DisplayHandle, "_NET_ACTIVE_WINDOW", false);
+ NetAtoms [(int)NA._NET_WORKAREA] = XInternAtom (DisplayHandle, "_NET_WORKAREA", false);
+ NetAtoms [(int)NA._NET_SUPPORTING_WM_CHECK] = XInternAtom (DisplayHandle, "_NET_SUPPORTING_WM_CHECK", false);
+ NetAtoms [(int)NA._NET_VIRTUAL_ROOTS] = XInternAtom (DisplayHandle, "_NET_VIRTUAL_ROOTS", false);
+ NetAtoms [(int)NA._NET_DESKTOP_LAYOUT] = XInternAtom (DisplayHandle, "_NET_DESKTOP_LAYOUT", false);
+ NetAtoms [(int)NA._NET_SHOWING_DESKTOP] = XInternAtom (DisplayHandle, "_NET_SHOWING_DESKTOP", false);
+
+ NetAtoms [(int)NA._NET_CLOSE_WINDOW] = XInternAtom (DisplayHandle, "_NET_CLOSE_WINDOW", false);
+ NetAtoms [(int)NA._NET_MOVERESIZE_WINDOW] = XInternAtom (DisplayHandle, "_NET_MOVERESIZE_WINDOW", false);
+ NetAtoms [(int)NA._NET_WM_MOVERESIZE] = XInternAtom (DisplayHandle, "_NET_WM_MOVERESIZE", false);
+ NetAtoms [(int)NA._NET_RESTACK_WINDOW] = XInternAtom (DisplayHandle, "_NET_RESTACK_WINDOW", false);
+ NetAtoms [(int)NA._NET_REQUEST_FRAME_EXTENTS] = XInternAtom (DisplayHandle, "_NET_REQUEST_FRAME_EXTENTS", false);
+
+ NetAtoms [(int)NA._NET_WM_NAME] = XInternAtom (DisplayHandle, "_NET_WM_NAME", false);
+ NetAtoms [(int)NA._NET_WM_VISIBLE_NAME] = XInternAtom (DisplayHandle, "_NET_WM_VISIBLE_NAME", false);
+ NetAtoms [(int)NA._NET_WM_ICON_NAME] = XInternAtom (DisplayHandle, "_NET_WM_ICON_NAME", false);
+ NetAtoms [(int)NA._NET_WM_VISIBLE_ICON_NAME] = XInternAtom (DisplayHandle, "_NET_WM_VISIBLE_ICON_NAME", false);
+ NetAtoms [(int)NA._NET_WM_DESKTOP] = XInternAtom (DisplayHandle, "_NET_WM_DESKTOP", false);
+ NetAtoms [(int)NA._NET_WM_WINDOW_TYPE] = XInternAtom (DisplayHandle, "_NET_WM_WINDOW_TYPE", false);
+ NetAtoms [(int)NA._NET_WM_STATE] = XInternAtom (DisplayHandle, "_NET_WM_STATE", false);
+ NetAtoms [(int)NA._NET_WM_ALLOWED_ACTIONS] = XInternAtom (DisplayHandle, "_NET_WM_ALLOWED_ACTIONS", false);
+ NetAtoms [(int)NA._NET_WM_STRUT] = XInternAtom (DisplayHandle, "_NET_WM_STRUT", false);
+ NetAtoms [(int)NA._NET_WM_STRUT_PARTIAL] = XInternAtom (DisplayHandle, "_NET_WM_STRUT_PARTIAL", false);
+ NetAtoms [(int)NA._NET_WM_ICON_GEOMETRY] = XInternAtom (DisplayHandle, "_NET_WM_ICON_GEOMETRY", false);
+ NetAtoms [(int)NA._NET_WM_ICON] = XInternAtom (DisplayHandle, "_NET_WM_ICON", false);
+ NetAtoms [(int)NA._NET_WM_PID] = XInternAtom (DisplayHandle, "_NET_WM_PID", false);
+ NetAtoms [(int)NA._NET_WM_HANDLED_ICONS] = XInternAtom (DisplayHandle, "_NET_WM_HANDLED_ICONS", false);
+ NetAtoms [(int)NA._NET_WM_USER_TIME] = XInternAtom (DisplayHandle, "_NET_WM_USER_TIME", false);
+ NetAtoms [(int)NA._NET_FRAME_EXTENTS] = XInternAtom (DisplayHandle, "_NET_FRAME_EXTENTS", false);
+
+ NetAtoms [(int)NA._NET_WM_PING] = XInternAtom (DisplayHandle, "_NET_WM_PING", false);
+ NetAtoms [(int)NA._NET_WM_SYNC_REQUEST] = XInternAtom (DisplayHandle, "_NET_WM_SYNC_REQUEST", false);
+
+ NetAtoms [(int)NA._NET_SYSTEM_TRAY_S] = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString (), false);
+ NetAtoms [(int)NA._NET_SYSTEM_TRAY_OPCODE] = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_OPCODE", false);
+ NetAtoms [(int)NA._NET_SYSTEM_TRAY_ORIENTATION] = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_ORIENTATION", false);
+
+ NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ] = XInternAtom (DisplayHandle, "_NET_WM_STATE_MAXIMIZED_HORZ", false);
+ NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT] = XInternAtom (DisplayHandle, "_NET_WM_STATE_MAXIMIZED_VERT", false);
+ NetAtoms [(int)NA._NET_WM_STATE_HIDDEN] = XInternAtom (DisplayHandle, "_NET_WM_STATE_HIDDEN", false);
+
+ NetAtoms [(int)NA._XEMBED] = XInternAtom (DisplayHandle, "_XEMBED", false);
+ NetAtoms [(int)NA._XEMBED_INFO] = XInternAtom (DisplayHandle, "_XEMBED_INFO", false);
+
+ NetAtoms [(int)NA._MOTIF_WM_HINTS] = XInternAtom (DisplayHandle, "_MOTIF_WM_HINTS", false);
+
+ NetAtoms [(int)NA._NET_WM_STATE_NO_TASKBAR] = XInternAtom (DisplayHandle, "_NET_WM_STATE_NO_TASKBAR", false);
+ NetAtoms [(int)NA._NET_WM_STATE_ABOVE] = XInternAtom (DisplayHandle, "_NET_WM_STATE_ABOVE", false);
+ NetAtoms [(int)NA._NET_WM_STATE_MODAL] = XInternAtom (DisplayHandle, "_NET_WM_STATE_MODAL", false);
+ NetAtoms [(int)NA._NET_WM_CONTEXT_HELP] = XInternAtom (DisplayHandle, "_NET_WM_CONTEXT_HELP", false);
+ NetAtoms [(int)NA._NET_WM_WINDOW_OPACITY] = XInternAtom (DisplayHandle, "_NET_WM_WINDOW_OPACITY", false);
+
+ // Clipboard support
+ NetAtoms [(int)NA.CLIPBOARD] = XInternAtom (DisplayHandle, "CLIPBOARD", false);
+ NetAtoms [(int)NA.DIB] = (int)Atom.XA_PIXMAP;
+ NetAtoms [(int)NA.OEMTEXT] = XInternAtom (DisplayHandle, "COMPOUND_TEXT", false);
+ NetAtoms [(int)NA.UNICODETEXT] = XInternAtom (DisplayHandle, "UTF8_STRING", false);
+ NetAtoms [(int)NA.TARGETS] = XInternAtom (DisplayHandle, "TARGETS", false);
+
+ // Special Atoms
+ AsyncAtom = XInternAtom (DisplayHandle, "_SWF_AsyncAtom", false);
+ PostAtom = XInternAtom (DisplayHandle, "_SWF_PostMessageAtom", false);
+ HoverState.Atom = XInternAtom (DisplayHandle, "_SWF_HoverAtom", false);
+ }
+
+ private void GetSystrayManagerWindow ()
+ {
+ gdk_x11_grab_server ();
+ SystrayMgrWindow = XGetSelectionOwner (DisplayHandle, NetAtoms [(int)NA._NET_SYSTEM_TRAY_S]);
+ gdk_x11_ungrab_server ();
+ gdk_display_flush (GdkDisplayHandle);
+ }
+
+ private void SendNetWMMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
+ {
+ XEvent xev;
+
+ xev = new XEvent ();
+ xev.ClientMessageEvent.type = XEventName.ClientMessage;
+ xev.ClientMessageEvent.send_event = true;
+ xev.ClientMessageEvent.window = window;
+ xev.ClientMessageEvent.message_type = message_type;
+ xev.ClientMessageEvent.format = 32;
+ xev.ClientMessageEvent.ptr1 = l0;
+ xev.ClientMessageEvent.ptr2 = l1;
+ xev.ClientMessageEvent.ptr3 = l2;
+ XSendEvent (DisplayHandle, RootWindow, false, EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask, ref xev);
+ }
+
+ private void SendNetClientMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
+ {
+ XEvent xev;
+
+ xev = new XEvent ();
+ xev.ClientMessageEvent.type = XEventName.ClientMessage;
+ xev.ClientMessageEvent.send_event = true;
+ xev.ClientMessageEvent.window = window;
+ xev.ClientMessageEvent.message_type = message_type;
+ xev.ClientMessageEvent.format = 32;
+ xev.ClientMessageEvent.ptr1 = l0;
+ xev.ClientMessageEvent.ptr2 = l1;
+ xev.ClientMessageEvent.ptr3 = l2;
+ XSendEvent (DisplayHandle, window, false, EventMask.NoEventMask, ref xev);
+ }
+
+ private void DeriveStyles (IntPtr handle, int Style, int ExStyle, out FormBorderStyle border_style, out TitleStyle title_style, out int caption_height, out int tool_caption_height)
+ {
+
+ // Only MDI windows get caption_heights
+ caption_height = 0;
+ tool_caption_height = 19;
+
+ if ((Style & (int) WindowStyles.WS_CHILD) != 0) {
+ if ((Style & (int) WindowStyles.WS_BORDER) == 0) {
+ border_style = FormBorderStyle.None;
+ } else if ((ExStyle & (int) WindowStyles.WS_EX_CLIENTEDGE) != 0) {
+ border_style = FormBorderStyle.Fixed3D;
+ } else {
+ border_style = FormBorderStyle.FixedSingle;
+ }
+ title_style = TitleStyle.None;
+ } else {
+ bool is_mdi = false;
+
+ if ((ExStyle & (int) WindowStyles.WS_EX_MDICHILD) != 0) {
+ caption_height = 26;
+ is_mdi = true;
+ }
+
+ title_style = TitleStyle.None;
+ if ((Style & (int)WindowStyles.WS_CAPTION) != 0) {
+ if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
+ title_style = TitleStyle.Tool;
+ } else {
+ title_style = TitleStyle.Normal;
+ }
+ }
+
+ if (!is_mdi) {
+ border_style = FormBorderStyle.None;
+
+ if ((Style & (int)WindowStyles.WS_THICKFRAME) != 0) {
+ if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
+ border_style = FormBorderStyle.SizableToolWindow;
+ } else {
+ border_style = FormBorderStyle.Sizable;
+ }
+ } else {
+ if ((ExStyle & (int)WindowStyles.WS_EX_CLIENTEDGE) != 0) {
+ border_style = FormBorderStyle.Fixed3D;
+ } else if ((ExStyle & (int)WindowStyles.WS_EX_DLGMODALFRAME) != 0) {
+ border_style = FormBorderStyle.FixedDialog;
+ } else if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
+ border_style = FormBorderStyle.FixedToolWindow;
+ } else if ((Style & (int)WindowStyles.WS_BORDER) != 0) {
+ border_style = FormBorderStyle.Sizable;
+ } else {
+ border_style = FormBorderStyle.None;
+ }
+ }
+ } else {
+ if ((Style & (int) WindowStyles.WS_OVERLAPPEDWINDOW) != 0 ||
+ (ExStyle & (int) WindowStyles.WS_EX_TOOLWINDOW) != 0) {
+ border_style = (FormBorderStyle) 0xFFFF;
+ } else {
+ border_style = FormBorderStyle.None;
+ }
+ }
+ }
+ }
+
+ private void SetHwndStyles (Hwnd hwnd, CreateParams cp)
+ {
+ DeriveStyles (hwnd.Handle, cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height);
+ }
+
+ private void SetWMStyles (Hwnd hwnd, CreateParams cp)
+ {
+ GdkWMDecoration decorations = GdkWMDecoration.GDK_DECOR_ALL;
+
+ if ((cp.Style & (int)WindowStyles.WS_CAPTION) != 0) {
+ decorations |= GdkWMDecoration.GDK_DECOR_TITLE | GdkWMDecoration.GDK_DECOR_MENU;
+ }
+
+ if ((cp.Style & ((int)WindowStyles.WS_THICKFRAME)) != 0) {
+ decorations |= GdkWMDecoration.GDK_DECOR_BORDER | GdkWMDecoration.GDK_DECOR_RESIZEH;
+ }
+ if ((cp.Style & ((int)WindowStyles.WS_MINIMIZEBOX)) != 0) {
+ decorations |= GdkWMDecoration.GDK_DECOR_MINIMIZE;
+ }
+
+ if ((cp.Style & ((int)WindowStyles.WS_MAXIMIZEBOX)) != 0) {
+ decorations |= GdkWMDecoration.GDK_DECOR_MAXIMIZE;
+ }
+
+ // is this needed ? most window managers do not even honour any MotifFunctions...
+// if ((cp.Style & ((int)WindowStyles.WS_SYSMENU)) != 0) {
+// functions |= MotifFunctions.Close;
+// }
+
+ if ((cp.ExStyle & ((int)WindowStyles.WS_EX_DLGMODALFRAME)) != 0) {
+ decorations |= GdkWMDecoration.GDK_DECOR_BORDER;
+ }
+
+ if ((cp.Style & ((int)WindowStyles.WS_DLGFRAME)) != 0) {
+ decorations |= GdkWMDecoration.GDK_DECOR_BORDER;
+ }
+
+ if ((cp.Style & ((int)WindowStyles.WS_BORDER)) != 0) {
+ decorations |= GdkWMDecoration.GDK_DECOR_BORDER;
+ }
+
+ if ((cp.ExStyle & ((int)WindowStyles.WS_EX_TOOLWINDOW)) != 0) {
+ decorations = 0;
+ }
+
+ gdk_window_set_decorations (gdk_window_foreign_new (hwnd.whole_window), (int)decorations);
+ }
+
+ private void SetIcon (Hwnd hwnd, Icon icon)
+ {
+ Bitmap bitmap;
+ int size;
+ uint[] data;
+ int index;
+
+ bitmap = icon.ToBitmap ();
+ index = 0;
+ size = bitmap.Width * bitmap.Height + 2;
+ data = new uint [size];
+
+ data [index++] = (uint)bitmap.Width;
+ data [index++] = (uint)bitmap.Height;
+
+ for (int y = 0; y < bitmap.Height; y++) {
+ for (int x = 0; x < bitmap.Width; x++) {
+ data [index++] = (uint)bitmap.GetPixel (x, y).ToArgb ();
+ }
+ }
+ XChangeProperty (DisplayHandle, hwnd.whole_window, NetAtoms [(int)NA._NET_WM_ICON], Atom.XA_CARDINAL, 32, PropertyMode.Replace, data, size);
+ }
+
+ private IntPtr ImageToPixmap (Image image)
+ {
+ return IntPtr.Zero;
+ }
+
+ private void WakeupMain ()
+ {
+ wake.Send (new byte [] { 0xFF });
+ }
+
+ private void TranslatePropertyToClipboard (int property)
+ {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Clipboard.Item = null;
+
+ XGetWindowProperty (DisplayHandle, FosterParent, property, 0, 0x7fffffff, true, Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if (nitems > 0) {
+ if (property == (int)Atom.XA_STRING) {
+ Clipboard.Item = Marshal.PtrToStringAnsi (prop);
+ } else if (property == (int)Atom.XA_BITMAP) {
+ // FIXME - convert bitmap to image
+ } else if (property == (int)Atom.XA_PIXMAP) {
+ // FIXME - convert pixmap to image
+ } else if (property == NetAtoms [(int)NA.OEMTEXT]) {
+ Clipboard.Item = Marshal.PtrToStringAnsi (prop);
+ } else if (property == NetAtoms [(int)NA.UNICODETEXT]) {
+ Clipboard.Item = Marshal.PtrToStringAnsi (prop);
+ }
+
+ XFree (prop);
+ }
+ }
+
+ private void AddExpose (XEvent xevent)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
+
+ // Don't waste time
+ if (hwnd == null) {
+ return;
+ }
+
+ if (xevent.AnyEvent.window == hwnd.client_window) {
+ hwnd.AddInvalidArea (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ if (!hwnd.expose_pending) {
+ MessageQueue.Enqueue (xevent);
+ hwnd.expose_pending = true;
+ }
+ } else {
+ if (!hwnd.nc_expose_pending) {
+ MessageQueue.Enqueue (xevent);
+ hwnd.nc_expose_pending = true;
+ }
+ }
+ }
+
+ private void InvalidateWholeWindow (IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ InvalidateWholeWindow (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height));
+ }
+
+ private void InvalidateWholeWindow (IntPtr handle, Rectangle rectangle)
+ {
+ Hwnd hwnd;
+ XEvent xevent;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+
+ xevent = new XEvent ();
+ xevent.type = XEventName.Expose;
+ xevent.ExposeEvent.display = DisplayHandle;
+ xevent.ExposeEvent.window = hwnd.whole_window;
+
+ xevent.ExposeEvent.x = rectangle.X;
+ xevent.ExposeEvent.y = rectangle.Y;
+ xevent.ExposeEvent.width = rectangle.Width;
+ xevent.ExposeEvent.height = rectangle.Height;
+
+ AddExpose (xevent);
+ }
+
+ private void WholeToScreen (IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ lock (XlibLock) {
+ gdk_window_get_origin (gdk_window_lookup (hwnd.whole_window), out dest_x_return, out dest_y_return);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ private void AddConfigureNotify (XEvent xevent)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow (xevent.ConfigureEvent.window);
+
+ // Don't waste time
+ if (hwnd == null) {
+ return;
+ }
+
+ if (xevent.ConfigureEvent.window == hwnd.whole_window) {
+ if (!hwnd.reparented) {
+ hwnd.x = xevent.ConfigureEvent.x;
+ hwnd.y = xevent.ConfigureEvent.y;
+ } else {
+ int dummy_int;
+
+ gdk_window_get_geometry (gdk_window_lookup (hwnd.whole_window), out hwnd.x, out hwnd.y, out dummy_int, out dummy_int, out dummy_int);
+ }
+
+ hwnd.width = xevent.ConfigureEvent.width;
+ hwnd.height = xevent.ConfigureEvent.height;
+
+ if (!hwnd.configure_pending) {
+ MessageQueue.Enqueue (xevent);
+ hwnd.configure_pending = true;
+ }
+ }
+ // We drop configure events for Client windows
+ }
+
+ private void ShowCaret ()
+ {
+ if ((Caret.gc == IntPtr.Zero) || Caret.On) {
+ return;
+ }
+ Caret.On = true;
+
+ // gdk_gc_set_foreground
+ // gdk_draw_line
+ lock (XlibLock) {
+ XDrawLine (DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+ }
+
+ private void HideCaret ()
+ {
+ if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
+ return;
+ }
+ Caret.On = false;
+
+ // gdk_gc_set_foreground
+ // gdk_draw_text_wc
+ lock (XlibLock) {
+ XDrawLine (DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+ }
+
+ private int NextTimeout (DateTime now)
+ {
+ int timeout = Int32.MaxValue;
+ lock (TimerList) {
+ foreach (Timer timer in TimerList) {
+ int next = (int) (timer.Expires - now).TotalMilliseconds;
+ if (next < 0) {
+ return 0; // Have a timer that has already expired
+ }
+
+ if (next < timeout) {
+ timeout = next;
+ }
+ }
+ }
+ if (timeout < Timer.Minimum) {
+ timeout = Timer.Minimum;
+ }
+
+ return timeout;
+ }
+
+ private void CheckTimers (DateTime now)
+ {
+ lock (TimerList) {
+ int count;
+
+ count = TimerList.Count;
+
+ if (count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < TimerList.Count; i++) {
+ Timer timer;
+
+ timer = (Timer) TimerList [i];
+
+ if (timer.Enabled && timer.Expires <= now) {
+ timer.Update (now);
+ timer.FireTick ();
+ }
+ }
+ }
+ }
+
+ private void UpdateMessageQueue ()
+ {
+ DateTime now;
+ int pending;
+
+ now = DateTime.Now;
+
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+
+ if (pending == 0) {
+ if (Idle != null) {
+ Idle (this, EventArgs.Empty);
+ }
+
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+
+ if (pending == 0) {
+ int timeout;
+
+ timeout = NextTimeout (now);
+ if (timeout > 0) {
+ #if __MonoCS__
+ Syscall.poll (pollfds, (uint) pollfds.Length, timeout);
+ // Clean out buffer, so we're not busy-looping on the same data
+ if (pollfds[1].revents != 0) {
+ wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
+ }
+ #endif
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+ }
+
+ CheckTimers (now);
+
+ if (pending == 0) {
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+
+ while (pending > 0) {
+ XEvent xevent = new XEvent ();
+
+ lock (XlibLock) {
+ XNextEvent (DisplayHandle, ref xevent);
+ }
+//Console.WriteLine("Got x event {0}", xevent);
+ switch (xevent.type) {
+ case XEventName.Expose:
+ AddExpose (xevent);
+ break;
+
+ case XEventName.SelectionClear: {
+ // Should we do something?
+ break;
+ }
+
+ case XEventName.SelectionRequest: {
+ if (Dnd.HandleSelectionRequestEvent (ref xevent))
+ break;
+ XEvent sel_event;
+
+ sel_event = new XEvent ();
+ sel_event.SelectionEvent.type = XEventName.SelectionNotify;
+ sel_event.SelectionEvent.send_event = true;
+ sel_event.SelectionEvent.display = DisplayHandle;
+ sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
+ sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
+ sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
+ sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
+ sel_event.SelectionEvent.property = 0;
+
+ // Seems that some apps support asking for supported types
+ if (xevent.SelectionEvent.target == NetAtoms [(int)NA.TARGETS]) {
+ uint[] atoms;
+ int atom_count;
+
+ atoms = new uint [5];
+ atom_count = 0;
+
+ if (Clipboard.Item is String) {
+ atoms [atom_count++] = (uint)Atom.XA_STRING;
+ atoms [atom_count++] = (uint)NetAtoms [(int)NA.OEMTEXT];
+ atoms [atom_count++] = (uint)NetAtoms [(int)NA.UNICODETEXT];
+ } else if (Clipboard.Item is Image) {
+ atoms [atom_count++] = (uint)Atom.XA_PIXMAP;
+ atoms [atom_count++] = (uint)Atom.XA_BITMAP;
+ } else {
+ // FIXME - handle other types
+ }
+
+ XChangeProperty (DisplayHandle, xevent.SelectionEvent.requestor, xevent.SelectionRequestEvent.property, xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
+ } else if (Clipboard.Item is string) {
+ IntPtr buffer;
+ int buflen;
+
+ buflen = 0;
+
+ if (xevent.SelectionRequestEvent.target == (int)Atom.XA_STRING) {
+ Byte[] bytes;
+
+ bytes = new ASCIIEncoding ().GetBytes ((string)Clipboard.Item);
+ buffer = Marshal.AllocHGlobal (bytes.Length);
+ buflen = bytes.Length;
+
+ for (int i = 0; i < buflen; i++) {
+ Marshal.WriteByte (buffer, i, bytes [i]);
+ }
+ } else if (xevent.SelectionRequestEvent.target == NetAtoms [(int)NA.OEMTEXT]) {
+ // FIXME - this should encode into ISO2022
+ buffer = Marshal.StringToHGlobalAnsi ((string)Clipboard.Item);
+ while (Marshal.ReadByte (buffer, buflen) != 0) {
+ buflen++;
+ }
+ } else if (xevent.SelectionRequestEvent.target == NetAtoms [(int)NA.UNICODETEXT]) {
+ buffer = Marshal.StringToHGlobalAnsi ((string)Clipboard.Item);
+ while (Marshal.ReadByte (buffer, buflen) != 0) {
+ buflen++;
+ }
+ } else {
+ buffer = IntPtr.Zero;
+ }
+
+ if (buffer != IntPtr.Zero) {
+ XChangeProperty (DisplayHandle, xevent.SelectionRequestEvent.requestor, xevent.SelectionRequestEvent.property, xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
+ sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
+ Marshal.FreeHGlobal (buffer);
+ }
+ } else if (Clipboard.Item is Image) {
+ if (xevent.SelectionEvent.target == (int)Atom.XA_PIXMAP) {
+ // FIXME - convert image and store as property
+ } else if (xevent.SelectionEvent.target == (int)Atom.XA_PIXMAP) {
+ // FIXME - convert image and store as property
+ }
+ }
+
+ XSendEvent (DisplayHandle, xevent.SelectionRequestEvent.requestor, false, EventMask.NoEventMask, ref sel_event);
+ break;
+ }
+
+ case XEventName.SelectionNotify: {
+ if (Clipboard.Enumerating) {
+ Clipboard.Enumerating = false;
+ if (xevent.SelectionEvent.property != 0) {
+ XDeleteProperty (DisplayHandle, FosterParent, xevent.SelectionEvent.property);
+ if (!Clipboard.Formats.Contains (xevent.SelectionEvent.property)) {
+ Clipboard.Formats.Add (xevent.SelectionEvent.property);
+ #if DriverDebugExtra
+ Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
+ #endif
+ }
+ }
+ } else if (Clipboard.Retrieving) {
+ Clipboard.Retrieving = false;
+ if (xevent.SelectionEvent.property != 0) {
+ TranslatePropertyToClipboard (xevent.SelectionEvent.property);
+ } else {
+ Clipboard.Item = null;
+ }
+ } else {
+ Dnd.HandleSelectionNotifyEvent (ref xevent);
+ }
+ break;
+ }
+
+ case XEventName.KeyPress:
+ case XEventName.KeyRelease:
+ case XEventName.ButtonPress:
+ case XEventName.ButtonRelease:
+ case XEventName.MotionNotify:
+ case XEventName.EnterNotify:
+ case XEventName.LeaveNotify:
+ case XEventName.CreateNotify:
+ case XEventName.DestroyNotify:
+ case XEventName.FocusIn:
+ case XEventName.FocusOut:
+ case XEventName.ClientMessage:
+ case XEventName.ReparentNotify:
+ MessageQueue.Enqueue (xevent);
+ break;
+
+ case XEventName.ConfigureNotify:
+ AddConfigureNotify (xevent);
+ break;
+
+ case XEventName.PropertyNotify:
+ if (xevent.PropertyEvent.atom == NetAtoms [(int)NA._NET_ACTIVE_WINDOW]) {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr prev_active;;
+
+ prev_active = ActiveWindow;
+ XGetWindowProperty (DisplayHandle, RootWindow, NetAtoms [(int)NA._NET_ACTIVE_WINDOW], 0, 1, false, Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((nitems > 0) && (prop != IntPtr.Zero)) {
+ ActiveWindow = Hwnd.GetHandleFromWindow ((IntPtr)Marshal.ReadInt32 (prop));
+ XFree (prop);
+
+ if (prev_active != ActiveWindow) {
+ if (prev_active != IntPtr.Zero) {
+ PostMessage (prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
+ }
+ if (ActiveWindow != IntPtr.Zero) {
+ PostMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
+ }
+ }
+ if (ModalWindows.Count == 0) {
+ break;
+ } else {
+ // Modality handling, if we are modal and the new active window is one
+ // of ours but not the modal one, switch back to the modal window
+
+ if (NativeWindow.FromHandle (ActiveWindow) != null) {
+ if (ActiveWindow != (IntPtr)ModalWindows.Peek ()) {
+ Activate ((IntPtr)ModalWindows.Peek ());
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ }
+
+ lock (XlibLock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+ }
+
+ private 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.Control) != 0) {
+ result |= (int)MsgButtons.MK_CONTROL;
+ }
+
+ if ((mods & Keys.Shift) != 0) {
+ result |= (int)MsgButtons.MK_SHIFT;
+ }
+
+ result |= Delta << 16;
+
+ return (IntPtr)result;
+ }
+ private IntPtr XGetParent (IntPtr handle)
+ {
+ return gdk_x11_drawable_get_xid (gdk_window_get_parent (gdk_window_lookup (handle)));
+ }
+
+ private int HandleError (IntPtr display, ref XErrorEvent error_event)
+ {
+ if (ErrorExceptions) {
+ throw new XException (error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code);
+ } else {
+ Console.WriteLine ("X11 Error encountered: {0}{1}\n", XException.GetMessage (error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code), Environment.StackTrace);
+ }
+ return 0;
+ }
+
+ private void DestroyChildWindow (ShiftUI.Widget c)
+ {
+ Hwnd hwnd;
+ int i;
+ ShiftUI.Widget[] Widgets;
+
+ if (c != null) {
+ Widgets = c.Widgets.GetAllWidgets ();
+
+ for (i = 0; i < Widgets.Length; i++) {
+ if (Widgets [i].IsHandleCreated) {
+ hwnd = Hwnd.ObjectFromHandle (Widgets [i].Handle);
+ SendMessage (Widgets [i].Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
+ hwnd.Dispose ();
+ }
+ DestroyChildWindow (Widgets [i]);
+ }
+ }
+ }
+
+ #endregion // Private Methods
+
+ #region Callbacks
+ private void MouseHover (object sender, EventArgs e)
+ {
+ if ((HoverState.X == MousePosition.X) && (HoverState.Y == MousePosition.Y)) {
+ XEvent xevent;
+
+ HoverState.Timer.Enabled = false;
+
+ if (HoverState.Window != IntPtr.Zero) {
+ xevent = new XEvent ();
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = DisplayHandle;
+ xevent.ClientMessageEvent.window = (IntPtr)HoverState.Window;
+ xevent.ClientMessageEvent.message_type = (IntPtr)HoverState.Atom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
+
+ MessageQueue.EnqueueLocked (xevent);
+
+ WakeupMain ();
+ }
+ }
+ }
+
+ private void CaretCallback (object sender, EventArgs e)
+ {
+ if (Caret.Paused) {
+ return;
+ }
+ Caret.On = !Caret.On;
+
+ XDrawLine (DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
+ }
+ #endregion // Callbacks
+
+ #region Public Properties
+
+ internal int Caption {
+ get {
+ return 25;
+ }
+ }
+
+ internal override Size CursorSize {
+ get {
+ uint x;
+ uint y;
+ gdk_display_get_maximal_cursor_size (GdkDisplayHandle, out x, out y);
+
+ return new Size ((int)x, (int)y);
+ }
+ }
+
+ internal override bool DragFullWindows {
+ get {
+ return true;
+ }
+ }
+
+ internal override Size DragSize {
+ get {
+ return new Size (4, 4);
+ }
+ }
+
+ internal override Size FrameBorderSize {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ internal override Size IconSize {
+ get {
+ IntPtr list;
+ XIconSize size;
+ int count;
+
+ if (XGetIconSizes (DisplayHandle, RootWindow, out list, out count) != 0) {
+ long current;
+ int largest;
+
+ current = (long)list;
+ largest = 0;
+
+ size = new XIconSize ();
+
+ for (int i = 0; i < count; i++) {
+ size = (XIconSize)Marshal.PtrToStructure ((IntPtr)current, size.GetType ());
+ current += Marshal.SizeOf (size);
+
+ // Look for our preferred size
+ if (size.min_width == 32) {
+ XFree (list);
+ return new Size (32, 32);
+ }
+
+ if (size.max_width == 32) {
+ XFree (list);
+ return new Size (32, 32);
+ }
+
+ if (size.min_width < 32 && size.max_width > 32) {
+ int x;
+
+ // check if we can fit one
+ x = size.min_width;
+ while (x < size.max_width) {
+ x += size.width_inc;
+ if (x == 32) {
+ XFree (list);
+ return new Size (32, 32);
+ }
+ }
+ }
+
+ if (largest < size.max_width) {
+ largest = size.max_width;
+ }
+ }
+
+ // We didn't find a match or we wouldn't be here
+ return new Size (largest, largest);
+
+ } else {
+ return new Size (32, 32);
+ }
+ }
+ }
+
+ internal override int KeyboardSpeed {
+ get {
+ //
+ // A lot harder: need to do:
+ // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
+ // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
+ // XkbGetWidgets(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
+ //
+ // And from that we can tell the repetition rate
+ //
+ // Notice, the values must map to:
+ // [0, 31] which maps to 2.5 to 30 repetitions per second.
+ //
+ return 0;
+ }
+ }
+
+ internal override int KeyboardDelay {
+ get {
+ //
+ // Return values must range from 0 to 4, 0 meaning 250ms,
+ // and 4 meaning 1000 ms.
+ //
+ return 1; // ie, 500 ms
+ }
+ }
+
+ internal override Size MaxWindowTrackSize {
+ get {
+ return new Size (WorkingArea.Width, WorkingArea.Height);
+ }
+ }
+
+ internal override Size MinimizedWindowSize {
+ get {
+ return new Size (1, 1);
+ }
+ }
+
+ internal override Size MinimizedWindowSpacingSize {
+ get {
+ return new Size (1, 1);
+ }
+ }
+
+ internal override Size MinimumWindowSize {
+ get {
+ return new Size (1, 1);
+ }
+ }
+
+ internal override Size MinWindowTrackSize {
+ get {
+ return new Size (1, 1);
+ }
+ }
+
+ internal override Keys ModifierKeys {
+ get {
+ return Keyboard.ModifierKeys;
+ }
+ }
+
+ internal override Size SmallIconSize {
+ get {
+ IntPtr list;
+ XIconSize size;
+ int count;
+
+ if (XGetIconSizes (DisplayHandle, RootWindow, out list, out count) != 0) {
+ long current;
+ int smallest;
+
+ current = (long)list;
+ smallest = 0;
+
+ size = new XIconSize ();
+
+ for (int i = 0; i < count; i++) {
+ size = (XIconSize)Marshal.PtrToStructure ((IntPtr)current, size.GetType ());
+ current += Marshal.SizeOf (size);
+
+ // Look for our preferred size
+ if (size.min_width == 16) {
+ XFree (list);
+ return new Size (16, 16);
+ }
+
+ if (size.max_width == 16) {
+ XFree (list);
+ return new Size (16, 16);
+ }
+
+ if (size.min_width < 16 && size.max_width > 16) {
+ int x;
+
+ // check if we can fit one
+ x = size.min_width;
+ while (x < size.max_width) {
+ x += size.width_inc;
+ if (x == 16) {
+ XFree (list);
+ return new Size (16, 16);
+ }
+ }
+ }
+
+ if (smallest == 0 || smallest > size.min_width) {
+ smallest = size.min_width;
+ }
+ }
+
+ // We didn't find a match or we wouldn't be here
+ return new Size (smallest, smallest);
+
+ } else {
+ return new Size (16, 16);
+ }
+ }
+ }
+
+ internal override int MouseButtonCount {
+ get {
+ return 3;
+ }
+ }
+
+ internal override bool MouseButtonsSwapped {
+ get {
+ return false; // FIXME - how to detect?
+ }
+ }
+
+ internal override bool MouseWheelPresent {
+ get {
+ return true; // FIXME - how to detect?
+ }
+ }
+
+ internal override Rectangle VirtualScreen {
+ get {
+ return WorkingArea;
+ }
+ }
+
+ internal override Rectangle WorkingArea {
+ get {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ int width;
+ int height;
+
+ XGetWindowProperty (DisplayHandle, RootWindow, NetAtoms [(int)NA._NET_DESKTOP_GEOMETRY], 0, 256, false, Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((nitems == 2) && (prop != IntPtr.Zero)) {
+ width = Marshal.ReadInt32 (prop, 0);
+ height = Marshal.ReadInt32 (prop, 4);
+
+ XFree (prop);
+ return new Rectangle (0, 0, width, height);
+ } else {
+ XWindowAttributes attributes=new XWindowAttributes ();
+
+ lock (XlibLock) {
+ XGetWindowAttributes (DisplayHandle, XRootWindow (DisplayHandle, ScreenNo), ref attributes);
+ }
+
+ return new Rectangle (0, 0, attributes.width, attributes.height);
+ }
+ }
+ }
+ #endregion // Public properties
+
+ #region Public Static Methods
+ internal override IntPtr InitializeDriver ()
+ {
+ lock (this) {
+ if (GdkDisplayHandle == IntPtr.Zero) {
+ SetDisplay (gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
+ }
+ }
+ return IntPtr.Zero;
+ }
+
+ internal override void ShutdownDriver (IntPtr token)
+ {
+ lock (this) {
+ if (GdkDisplayHandle != IntPtr.Zero) {
+ gdk_display_close (GdkDisplayHandle);
+ DisplayHandle = IntPtr.Zero;
+ GdkDisplayHandle = IntPtr.Zero;
+ }
+ }
+ }
+
+ internal override void EnableThemes ()
+ {
+ ThemesEnabled = true;
+ }
+
+
+ internal override void Activate (IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd != null) lock (XlibLock) {
+ SendNetWMMessage (hwnd.whole_window, (IntPtr)NetAtoms [(int)NA._NET_ACTIVE_WINDOW], IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ //XRaiseWindow(DisplayHandle, handle);
+ }
+ return;
+ }
+
+ internal override void AudibleAlert (AlertType atype)
+ {
+ gdk_display_beep (gdk_x11_lookup_xdisplay (DisplayHandle));
+ return;
+ }
+
+
+ internal override void CaretVisible (IntPtr handle, bool visible)
+ {
+ // Visible is cumulative; two hides require two shows before the caret is visible again
+ if (Caret.Hwnd == handle) {
+ 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 bool CalculateWindowRect (IntPtr handle, ref Rectangle ClientRect, int Style, int ExStyle, Menu menu, out Rectangle WindowRect)
+ {
+ FormBorderStyle border_style;
+ TitleStyle title_style;
+ int caption_height;
+ int tool_caption_height;
+
+ DeriveStyles (handle, Style, ExStyle, out border_style, out title_style,
+ out caption_height, out tool_caption_height);
+
+ WindowRect = Hwnd.GetWindowRectangle (border_style, menu, title_style,
+ caption_height, tool_caption_height,
+ ClientRect);
+
+ return true;
+ }
+
+ internal override void ClientToScreen (IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates (DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+
+ internal override void CreateCaret (IntPtr handle, int width, int height)
+ {
+ XGCValues gc_values;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (Caret.Hwnd != IntPtr.Zero) {
+ DestroyCaret (Caret.Hwnd);
+ }
+
+ Caret.Hwnd = handle;
+ Caret.Window = hwnd.client_window;
+ Caret.Width = width;
+ Caret.Height = height;
+ Caret.Visible = 0;
+ Caret.On = false;
+
+ gc_values = new XGCValues ();
+ gc_values.line_width = width;
+
+ Caret.gc = XCreateGC (DisplayHandle, Caret.Window, GCFunction.GCLineWidth, ref gc_values);
+ if (Caret.gc == IntPtr.Zero) {
+ Caret.Hwnd = IntPtr.Zero;
+ return;
+ }
+
+ XSetFunction (DisplayHandle, Caret.gc, GXFunction.GXinvert);
+ }
+
+ internal override IntPtr CreateWindow (CreateParams cp)
+ {
+ GdkWindowAttr gdk_window_attributes;
+ GdkWindowAttributesType attributes_mask = 0;
+ Hwnd hwnd;
+ int X;
+ int Y;
+ int Width;
+ int Height;
+ IntPtr GdkParentHandle;
+ IntPtr GdkWholeWindow;
+ IntPtr GdkClientWindow;
+ Rectangle ClientRect;
+ GdkWindowType gdk_window_type;
+
+
+ hwnd = new Hwnd ();
+
+ gdk_window_attributes = new GdkWindowAttr ();
+
+ X = cp.X;
+ Y = cp.Y;
+ Width = cp.Width;
+ Height = cp.Height;
+
+ if (Width < 1) Width = 1;
+ if (Height < 1) Height = 1;
+
+ gdk_window_type = GdkWindowType.GDK_WINDOW_CHILD;
+
+ if (cp.Parent != IntPtr.Zero) {
+ GdkParentHandle = gdk_window_lookup (Hwnd.ObjectFromHandle (cp.Parent).client_window);
+ } else {
+ if ((cp.Style & (int)WindowStyles.WS_CHILD) != 0) {
+ // We need to use our foster parent window until this poor child gets it's parent assigned
+ GdkParentHandle = GdkFosterParent;
+ } else if ((cp.Style & (int)WindowStyles.WS_POPUP) != 0) {
+ GdkParentHandle = GdkRootWindow;
+ } else {
+ // Default position on screen, if window manager doesn't place us somewhere else
+ if (X < 1) X = 50;
+ if (Y < 1) Y = 50;
+ GdkParentHandle = GdkRootWindow;
+ }
+ }
+
+// ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
+
+// Attributes.bit_gravity = Gravity.NorthWestGravity;
+// Attributes.win_gravity = Gravity.NorthWestGravity;
+
+ // FIXME: does gdk need that ?
+ // Save what's under the toolwindow
+ if ((cp.ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
+// Attributes.save_under = true;
+// ValueMask |= SetWindowValuemask.SaveUnder;
+ }
+
+ // If we're a popup without caption we override the WM
+ if ((cp.Style & ((int)WindowStyles.WS_POPUP)) != 0) {
+ if ((cp.Style & (int)WindowStyles.WS_CAPTION) == 0) {
+ gdk_window_attributes.override_redirect = true;
+ attributes_mask |= GdkWindowAttributesType.GDK_WA_NOREDIR;
+ }
+ }
+
+ hwnd.x = X;
+ hwnd.y = Y;
+ hwnd.width = Width;
+ hwnd.height = Height;
+ hwnd.parent = Hwnd.ObjectFromHandle (cp.Parent);
+
+ if ((cp.Style & ((int)WindowStyles.WS_DISABLED)) != 0) {
+ hwnd.enabled = false;
+ }
+
+ ClientRect = hwnd.ClientRect;
+ GdkClientWindow = IntPtr.Zero;
+
+ gdk_window_attributes.x = X;
+ gdk_window_attributes.y = Y;
+ gdk_window_attributes.width = Width;
+ gdk_window_attributes.height = Height;
+ gdk_window_attributes.window_type = gdk_window_type;
+
+ attributes_mask |= GdkWindowAttributesType.GDK_WA_X | GdkWindowAttributesType.GDK_WA_Y;
+
+ gdk_window_attributes.wclass = GdkWindowClass.GDK_INPUT_OUTPUT;
+
+ lock (XlibLock) {
+ GdkWholeWindow = gdk_window_new (GdkParentHandle, ref gdk_window_attributes, (int)attributes_mask);
+
+ if (GdkWholeWindow != IntPtr.Zero) {
+ attributes_mask &= ~GdkWindowAttributesType.GDK_WA_NOREDIR;
+
+ if (GdkCustomVisual != IntPtr.Zero && GdkCustomColormap != IntPtr.Zero) {
+ attributes_mask |= GdkWindowAttributesType.GDK_WA_COLORMAP | GdkWindowAttributesType.GDK_WA_VISUAL;
+ gdk_window_attributes.colormap = GdkCustomColormap;
+ gdk_window_attributes.visual = GdkCustomVisual;
+ }
+
+ gdk_window_attributes.x = ClientRect.X;
+ gdk_window_attributes.y = ClientRect.Y;
+ gdk_window_attributes.width = ClientRect.Width;
+ gdk_window_attributes.height = ClientRect.Height;
+
+ GdkClientWindow = gdk_window_new (GdkWholeWindow, ref gdk_window_attributes, (int)attributes_mask);
+ }
+ }
+
+ if ((GdkWholeWindow == IntPtr.Zero) || (GdkClientWindow == IntPtr.Zero)) {
+ throw new Exception ("Could not create X11 Gdk windows");
+ }
+
+ hwnd.WholeWindow = gdk_x11_drawable_get_xid (GdkWholeWindow);
+ hwnd.ClientWindow = gdk_x11_drawable_get_xid (GdkClientWindow);
+
+ #if DriverDebug
+ Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0);
+ #endif
+
+ lock (XlibLock) {
+ gdk_window_set_events (GdkWholeWindow, (int)GdkSelectInputMask);
+ gdk_window_set_events (GdkClientWindow, (int)GdkSelectInputMask);
+
+ if ((cp.Style & (int)WindowStyles.WS_VISIBLE) != 0) {
+ gdk_window_show (GdkWholeWindow);
+ gdk_window_show (GdkClientWindow);
+ hwnd.visible = true;
+ }
+ }
+
+ SetWMStyles (hwnd, cp);
+
+ if ((cp.Style & (int)WindowStyles.WS_MINIMIZE) != 0) {
+ SetWindowState (hwnd.Handle, FormWindowState.Minimized);
+ } else if ((cp.Style & (int)WindowStyles.WS_MAXIMIZE) != 0) {
+ SetWindowState (hwnd.Handle, FormWindowState.Maximized);
+ }
+
+ // for now make all windows dnd enabled
+ Dnd.SetAllowDrop (hwnd, true);
+
+ // Set caption/window title
+ Text (hwnd.Handle, cp.Caption);
+
+ 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.DefaultClassName;
+ create_params.ClassStyle = 0;
+ create_params.ExStyle = 0;
+ create_params.Parent = IntPtr.Zero;
+ create_params.Param = 0;
+
+ return CreateWindow (create_params);
+ }
+
+ internal override IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
+ {
+ IntPtr cursor;
+ Bitmap cursor_bitmap;
+ Bitmap cursor_mask;
+ Byte[] cursor_bits;
+ Byte[] mask_bits;
+ Color c_pixel;
+ Color m_pixel;
+ int width;
+ int height;
+ IntPtr cursor_pixmap;
+ IntPtr mask_pixmap;
+ XColor fg;
+ XColor bg;
+ bool and;
+ bool xor;
+
+ Size cursor_size = CursorSize;
+ width = cursor_size.Width;
+ height = cursor_size.Height;
+
+ // Win32 only allows creation cursors of a certain size
+ if ((bitmap.Width != width) || (bitmap.Width != height)) {
+ cursor_bitmap = new Bitmap (bitmap, new Size (width, height));
+ cursor_mask = new Bitmap (mask, new Size (width, height));
+ } else {
+ cursor_bitmap = bitmap;
+ cursor_mask = mask;
+ }
+
+ width = cursor_bitmap.Width;
+ height = cursor_bitmap.Height;
+
+ cursor_bits = new Byte [(width / 8) * height];
+ mask_bits = new Byte [(width / 8) * height];
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ c_pixel = cursor_bitmap.GetPixel (x, y);
+ m_pixel = cursor_mask.GetPixel (x, y);
+
+ and = c_pixel == cursor_pixel;
+ xor = m_pixel == mask_pixel;
+
+ if (!and && !xor) {
+ // Black
+ // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
+ mask_bits [y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+ } else if (and && !xor) {
+ // White
+ cursor_bits [y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+ mask_bits [y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
+ #if notneeded
+ } else if (and && !xor) {
+ // Screen
+ } else if (and && xor) {
+ // Inverse Screen
+
+ // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
+ // we want both to be 0 so nothing to be done
+ //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
+ //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
+ #endif
+ }
+ }
+ }
+
+ cursor_pixmap = XCreatePixmapFromBitmapData (DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
+ mask_pixmap = XCreatePixmapFromBitmapData (DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
+ fg = new XColor ();
+ bg = new XColor ();
+
+ fg.pixel = XWhitePixel (DisplayHandle, ScreenNo);
+ fg.red = (ushort)65535;
+ fg.green = (ushort)65535;
+ fg.blue = (ushort)65535;
+
+ bg.pixel = XBlackPixel (DisplayHandle, ScreenNo);
+
+ cursor = XCreatePixmapCursor (DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
+
+ XFreePixmap (DisplayHandle, cursor_pixmap);
+ XFreePixmap (DisplayHandle, mask_pixmap);
+
+ return cursor;
+ }
+
+ internal override IntPtr DefineStdCursor (StdCursor id)
+ {
+ CursorFontShape shape;
+ IntPtr cursor;
+
+ // FIXME - define missing shapes
+
+ switch (id) {
+ case StdCursor.AppStarting: {
+ shape = CursorFontShape.XC_watch;
+ break;
+ }
+
+ case StdCursor.Arrow: {
+ return IntPtr.Zero;
+ }
+
+ case StdCursor.Cross: {
+ shape = CursorFontShape.XC_crosshair;
+ break;
+ }
+
+ case StdCursor.Default: {
+ return IntPtr.Zero;
+ }
+
+ case StdCursor.Hand: {
+ shape = CursorFontShape.XC_hand1;
+ break;
+ }
+
+ case StdCursor.Help: {
+ shape = CursorFontShape.XC_question_arrow;
+ break;
+ }
+
+ case StdCursor.HSplit: {
+ shape = CursorFontShape.XC_sb_v_double_arrow;
+ break;
+ }
+
+ case StdCursor.IBeam: {
+ shape = CursorFontShape.XC_xterm;
+ break;
+ }
+
+ case StdCursor.No: {
+ shape = CursorFontShape.XC_circle;
+ break;
+ }
+
+ case StdCursor.NoMove2D: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.NoMoveHoriz: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.NoMoveVert: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanEast: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanNE: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanNorth: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanNW: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanSE: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanSouth: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanSW: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.PanWest: {
+ shape = CursorFontShape.XC_sizing;
+ break;
+ }
+
+ case StdCursor.SizeAll: {
+ shape = CursorFontShape.XC_fleur;
+ break;
+ }
+
+ case StdCursor.SizeNESW: {
+ shape = CursorFontShape.XC_top_right_corner;
+ break;
+ }
+
+ case StdCursor.SizeNS: {
+ shape = CursorFontShape.XC_sb_v_double_arrow;
+ break;
+ }
+
+ case StdCursor.SizeNWSE: {
+ shape = CursorFontShape.XC_top_left_corner;
+ break;
+ }
+
+ case StdCursor.SizeWE: {
+ shape = CursorFontShape.XC_sb_h_double_arrow;
+ break;
+ }
+
+ case StdCursor.UpArrow: {
+ shape = CursorFontShape.XC_center_ptr;
+ break;
+ }
+
+ case StdCursor.VSplit: {
+ shape = CursorFontShape.XC_sb_h_double_arrow;
+ break;
+ }
+
+ case StdCursor.WaitCursor: {
+ shape = CursorFontShape.XC_watch;
+ break;
+ }
+
+ default: {
+ return IntPtr.Zero;
+ }
+ }
+
+ lock (XlibLock) {
+ cursor = XCreateFontCursor (DisplayHandle, shape);
+ }
+ return cursor;
+ }
+
+ internal override IntPtr DefWndProc (ref Message msg)
+ {
+ return IntPtr.Zero;
+ }
+
+ internal override void DestroyCaret (IntPtr handle)
+ {
+ if (Caret.Hwnd == handle) {
+ if (Caret.Visible == 1) {
+ Caret.Timer.Stop ();
+ HideCaret ();
+ }
+ if (Caret.gc != IntPtr.Zero) {
+ XFreeGC (DisplayHandle, Caret.gc);
+ Caret.gc = IntPtr.Zero;
+ }
+ Caret.Hwnd = IntPtr.Zero;
+ Caret.Visible = 0;
+ Caret.On = false;
+ }
+ }
+
+ internal override void DestroyCursor (IntPtr cursor)
+ {
+ lock (XlibLock) {
+ XFreeCursor (DisplayHandle, cursor);
+ }
+ }
+
+ internal override void DestroyWindow (IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd == null) {
+ #if DriverDebug
+ Console.WriteLine("window {0:X} already destroyed", handle.ToInt32());
+ #endif
+ return;
+ }
+
+ #if DriverDebug
+ Console.WriteLine("Destroying window {0:X}", handle.ToInt32());
+ #endif
+
+ // Make sure if the caret is in the window, that we destroy the caret, too
+ if (Caret.Hwnd == hwnd.client_window) {
+ DestroyCaret (handle);
+ }
+
+ // Mark our children as gone as well
+ DestroyChildWindow (ShiftUI.Widget.ShiftUI.WidgetNativeWindow.ShiftUI.WidgetFromHandle (handle));
+
+ // Send destroy message
+ SendMessage (handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
+
+ lock (XlibLock) {
+ if (hwnd.client_window != IntPtr.Zero) {
+ gdk_window_destroy (gdk_window_lookup (hwnd.client_window));
+ }
+
+ if ((hwnd.whole_window != IntPtr.Zero) && (hwnd.whole_window != hwnd.client_window)) {
+ gdk_window_destroy (gdk_window_lookup (hwnd.whole_window));
+ }
+ }
+ hwnd.Dispose ();
+ }
+
+ internal override IntPtr DispatchMessage (ref MSG msg)
+ {
+ return NativeWindow.WndProc (msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ }
+
+ internal override void DrawReversibleRectangle (IntPtr handle, Rectangle rect, int line_width)
+ {
+ Hwnd hwnd;
+ XGCValues gc_values;
+ IntPtr gc;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ gc_values = new XGCValues ();
+
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+ gc_values.line_width = line_width;
+ gc_values.foreground = XBlackPixel (DisplayHandle, ScreenNo);
+
+ // This logic will give us true rubber bands: (libsx, SANE_XOR)
+ //mask = foreground ^ background;
+ //XSetForeground(DisplayHandle, gc, 0xffffffff);
+ //XSetBackground(DisplayHandle, gc, background);
+ //XSetFunction(DisplayHandle, gc, GXxor);
+ //XSetPlaneMask(DisplayHandle, gc, mask);
+
+
+ gc = XCreateGC (DisplayHandle, hwnd.client_window, GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground, ref gc_values);
+ uint foreground;
+ uint background;
+
+ ShiftUI.Widget Widget;
+ Widget = ShiftUI.Widget.FromHandle (handle);
+
+ XColor xcolor = new XColor ();
+
+ xcolor.red = (ushort)(ShiftUI.Widget.ForeColor.R * 257);
+ xcolor.green = (ushort)(ShiftUI.Widget.ForeColor.G * 257);
+ xcolor.blue = (ushort)(ShiftUI.Widget.ForeColor.B * 257);
+ XAllocColor (DisplayHandle, DefaultColormap, ref xcolor);
+ foreground = (uint)xcolor.pixel.ToInt32 ();
+
+ xcolor.red = (ushort)(ShiftUI.Widget.BackColor.R * 257);
+ xcolor.green = (ushort)(ShiftUI.Widget.BackColor.G * 257);
+ xcolor.blue = (ushort)(ShiftUI.Widget.BackColor.B * 257);
+ XAllocColor (DisplayHandle, DefaultColormap, ref xcolor);
+ background = (uint)xcolor.pixel.ToInt32 ();
+
+ uint mask = foreground ^ background;
+
+ XSetForeground (DisplayHandle, gc, 0xffffffff);
+ XSetBackground (DisplayHandle, gc, background);
+ XSetFunction (DisplayHandle, gc, GXFunction.GXxor);
+ XSetPlaneMask (DisplayHandle, gc, mask);
+
+ if ((rect.Width > 0) && (rect.Height > 0)) {
+ XDrawRectangle (DisplayHandle, hwnd.client_window, gc, rect.Left, rect.Top, rect.Width, rect.Height);
+ } else {
+ if (rect.Width > 0) {
+ XDrawLine (DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.Right, rect.Y);
+ } else {
+ XDrawLine (DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.X, rect.Bottom);
+ }
+ }
+ XFreeGC (DisplayHandle, gc);
+ }
+
+ internal override void DoEvents ()
+ {
+ MSG msg = new MSG ();
+
+ if (OverrideCursorHandle != IntPtr.Zero) {
+ OverrideCursorHandle = IntPtr.Zero;
+ }
+
+ while (PeekMessage (ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
+ TranslateMessage (ref msg);
+ DispatchMessage (ref msg);
+ }
+ }
+
+ internal override void EnableWindow (IntPtr handle, bool Enable)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ if (hwnd != null) {
+ hwnd.Enabled = Enable;
+ }
+ }
+
+ internal override void EndLoop (Thread thread)
+ {
+ // This is where we one day will shut down the loop for the thread
+ }
+
+
+ internal override IntPtr GetActive ()
+ {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr active = IntPtr.Zero;
+
+ XGetWindowProperty (DisplayHandle, RootWindow, NetAtoms [(int)NA._NET_ACTIVE_WINDOW], 0, 1, false, Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((nitems > 0) && (prop != IntPtr.Zero)) {
+ active = (IntPtr)Marshal.ReadInt32 (prop);
+ XFree (prop);
+ }
+
+ if (active != IntPtr.Zero) {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow (active);
+ if (hwnd != null) {
+ active = hwnd.Handle;
+ } else {
+ active = IntPtr.Zero;
+ }
+ }
+ return active;
+ }
+
+ internal override void GetCursorInfo (IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y)
+ {
+ throw new NotImplementedException ();
+ }
+
+ internal override void GetDisplaySize (out Size size)
+ {
+ XWindowAttributes attributes=new XWindowAttributes ();
+
+ lock (XlibLock) {
+ // FIXME - use _NET_WM messages instead?
+ XGetWindowAttributes (DisplayHandle, XRootWindow (DisplayHandle, ScreenNo), ref attributes);
+ }
+
+ size = new Size (attributes.width, attributes.height);
+ }
+
+ 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.FromHwnd (FosterParent);
+
+ width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
+ return new SizeF (width, font.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 void GetCursorPos (IntPtr handle, out int x, out int y)
+ {
+ IntPtr use_handle;
+ IntPtr root;
+ IntPtr child;
+ int root_x;
+ int root_y;
+ int win_x;
+ int win_y;
+ int keys_buttons;
+
+ if (handle != IntPtr.Zero) {
+ use_handle = Hwnd.ObjectFromHandle (handle).client_window;
+ } else {
+ use_handle = RootWindow;
+ }
+
+ lock (XlibLock) {
+ XQueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
+ }
+
+ if (handle != IntPtr.Zero) {
+ x = win_x;
+ y = win_y;
+ } else {
+ x = root_x;
+ y = root_y;
+ }
+ }
+
+ internal override bool GetFontMetrics (Graphics g, Font font, out int ascent, out int descent)
+ {
+ return GetFontMetrics (g.GetHdc (), font.ToHfont (), out ascent, out descent);
+ }
+
+ internal override Point GetMenuOrigin (IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd != null) {
+ return hwnd.MenuOrigin;
+ }
+ return Point.Empty;
+ }
+
+ internal bool GetMessage (ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax)
+ {
+ XEvent xevent;
+ bool client;
+ Hwnd hwnd;
+
+ ProcessNextMessage:
+
+ if (MessageQueue.Count > 0) {
+ xevent = (XEvent) MessageQueue.Dequeue ();
+ } else {
+ UpdateMessageQueue ();
+
+ if (MessageQueue.Count > 0) {
+ xevent = (XEvent) MessageQueue.Dequeue ();
+ } else {
+ if (!PostQuitState) {
+ msg.hwnd = IntPtr.Zero;
+ msg.message = Msg.WM_ENTERIDLE;
+ return true;
+ }
+
+ // We reset ourselves so GetMessage can be called again
+ PostQuitState = false;
+
+ return false;
+ }
+ }
+
+ // FIXME - handle filtering
+
+ hwnd = Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
+
+ // Handle messages for windows that are already or are about to be destroyed
+ if (hwnd == null) {
+ #if DriverDebug
+ Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
+ #endif
+ goto ProcessNextMessage;
+ }
+
+ if (hwnd.client_window == xevent.AnyEvent.window) {
+ client = true;
+ //Console.WriteLine("Client message, sending to window {0:X}", msg.hwnd.ToInt32());
+ } else {
+ client = false;
+ //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32());
+ }
+
+ msg.hwnd = hwnd.Handle;
+
+ //
+ // If you add a new event to this switch make sure to add it in
+ // UpdateMessage also unless it is not coming through the X event system.
+ //
+ switch (xevent.type) {
+ case XEventName.KeyPress: {
+ Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
+ break;
+ }
+
+ case XEventName.KeyRelease: {
+ Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
+ break;
+ }
+
+ case XEventName.ButtonPress: {
+ switch (xevent.ButtonEvent.button) {
+ case 1: {
+ MouseState |= MouseButtons.Left;
+ if (client) {
+ msg.message = Msg.WM_LBUTTONDOWN;
+ } else {
+ msg.message = Msg.WM_NCLBUTTONDOWN;
+ WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
+ msg.wParam = GetMousewParam (0);
+ break;
+ }
+
+ case 2: {
+ MouseState |= MouseButtons.Middle;
+ if (client) {
+ msg.message = Msg.WM_MBUTTONDOWN;
+ } else {
+ msg.message = Msg.WM_NCMBUTTONDOWN;
+ WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ msg.wParam = GetMousewParam (0);
+ break;
+ }
+
+ case 3: {
+ MouseState |= MouseButtons.Right;
+ if (client) {
+ msg.message = Msg.WM_RBUTTONDOWN;
+ } else {
+ msg.message = Msg.WM_NCRBUTTONDOWN;
+ WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ msg.wParam = GetMousewParam (0);
+ break;
+ }
+
+ case 4: {
+ msg.message = Msg.WM_MOUSEWHEEL;
+ msg.wParam = GetMousewParam (120);
+ break;
+ }
+
+ case 5: {
+ msg.message = Msg.WM_MOUSEWHEEL;
+ msg.wParam = GetMousewParam (-120);
+ break;
+ }
+
+ }
+
+ msg.lParam = (IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ MousePosition.X = xevent.ButtonEvent.x;
+ MousePosition.Y = xevent.ButtonEvent.y;
+
+ if (!hwnd.Enabled) {
+ IntPtr dummy;
+
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy);
+ msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
+ }
+
+ if (Grab.Hwnd != IntPtr.Zero) {
+ msg.hwnd = Grab.Hwnd;
+ }
+
+ if (!ClickPending.Pending) {
+ ClickPending.Pending = true;
+ ClickPending.Hwnd = msg.hwnd;
+ ClickPending.Message = msg.message;
+ ClickPending.wParam = msg.wParam;
+ ClickPending.lParam = msg.lParam;
+ ClickPending.Time = (long)xevent.ButtonEvent.time;
+ } else {
+ if ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message)) {
+ // Looks like a genuine double click, clicked twice on the same spot with the same keys
+ switch (xevent.ButtonEvent.button) {
+ case 1: {
+ msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
+ break;
+ }
+
+ case 2: {
+ msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
+ break;
+ }
+
+ case 3: {
+ msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
+ break;
+ }
+ }
+ }
+ ClickPending.Pending = false;
+ }
+
+ break;
+ }
+
+ case XEventName.ButtonRelease: {
+ Dnd.HandleButtonRelease (ref xevent);
+ switch (xevent.ButtonEvent.button) {
+ case 1: {
+ if (client) {
+ msg.message = Msg.WM_LBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCLBUTTONUP;
+ WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ msg.wParam = GetMousewParam (0);
+ MouseState &= ~MouseButtons.Left;
+ break;
+ }
+
+ case 2: {
+ if (client) {
+ msg.message = Msg.WM_MBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCMBUTTONUP;
+ WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ msg.wParam = GetMousewParam (0);
+ MouseState &= ~MouseButtons.Middle;
+ break;
+ }
+
+ case 3: {
+ if (client) {
+ msg.message = Msg.WM_RBUTTONUP;
+ } else {
+ msg.message = Msg.WM_NCRBUTTONUP;
+ WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
+ }
+ msg.wParam = GetMousewParam (0);
+ MouseState &= ~MouseButtons.Right;
+ break;
+ }
+
+ case 4: {
+ goto ProcessNextMessage;
+ }
+
+ case 5: {
+ goto ProcessNextMessage;
+ }
+ }
+
+ if (!hwnd.Enabled) {
+ IntPtr dummy;
+
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy);
+ msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
+ }
+
+ if (Grab.Hwnd != IntPtr.Zero) {
+ msg.hwnd = Grab.Hwnd;
+ }
+
+ msg.lParam = (IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ MousePosition.X = xevent.ButtonEvent.x;
+ MousePosition.Y = xevent.ButtonEvent.y;
+ break;
+ }
+
+ case XEventName.MotionNotify: {
+ if (client) {
+ #if DriverDebugExtra
+ Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y);
+ #endif
+
+ if (Dnd.HandleMotionNotify (ref xevent))
+ goto ProcessNextMessage;
+ if (Grab.Hwnd != IntPtr.Zero) {
+ msg.hwnd = Grab.Hwnd;
+ } else {
+ NativeWindow.WndProc (msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
+ }
+
+ msg.message = Msg.WM_MOUSEMOVE;
+ msg.wParam = GetMousewParam (0);
+ msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
+
+ if (!hwnd.Enabled) {
+ IntPtr dummy;
+
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy);
+ msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
+ }
+
+ HoverState.X = MousePosition.X = xevent.MotionEvent.x;
+ HoverState.Y = MousePosition.Y = xevent.MotionEvent.y;
+
+ break;
+ } else {
+ #if DriverDebugExtra
+ Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y);
+ #endif
+ msg.message = Msg.WM_NCMOUSEMOVE;
+ msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
+
+ if (!hwnd.Enabled) {
+ IntPtr dummy;
+
+ msg.hwnd = hwnd.EnabledHwnd;
+ XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy);
+ msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
+ }
+
+ #if notyet
+ // Not sure we need this...
+ HitTest ht;
+ ht = NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam);
+ #endif
+
+ MousePosition.X = xevent.MotionEvent.x;
+ MousePosition.Y = xevent.MotionEvent.y;
+ }
+
+ break;
+ }
+
+ case XEventName.EnterNotify: {
+ if (!hwnd.Enabled) {
+ goto ProcessNextMessage;
+ }
+ if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
+ goto ProcessNextMessage;
+ }
+ msg.message = Msg.WM_MOUSE_ENTER;
+ HoverState.Timer.Enabled = true;
+ HoverState.Window = xevent.CrossingEvent.window;
+ break;
+ }
+
+ case XEventName.LeaveNotify: {
+ if (!hwnd.Enabled) {
+ goto ProcessNextMessage;
+ }
+ if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
+ goto ProcessNextMessage;
+ }
+ msg.message = Msg.WM_MOUSELEAVE;
+ HoverState.Timer.Enabled = false;
+ HoverState.Window = IntPtr.Zero;
+ break;
+ }
+
+ #if later
+ case XEventName.CreateNotify: {
+ if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
+ msg.message = WM_CREATE;
+ // Set up CreateStruct
+ } else {
+ goto ProcessNextMessage;
+ }
+ break;
+ }
+ #endif
+
+
+ case XEventName.ReparentNotify: {
+ if (hwnd.parent == null) { // Toplevel
+ if (xevent.ReparentEvent.parent != IntPtr.Zero) {
+ // We need to adjust x/y
+ int dummy_int;
+
+ hwnd.Reparented = true;
+
+ gdk_window_get_geometry (gdk_window_lookup (hwnd.whole_window), out hwnd.x, out hwnd.y, out dummy_int, out dummy_int, out dummy_int);
+ msg.message = Msg.WM_WINDOWPOSCHANGED;
+ if (hwnd.opacity != 0xffffffff) {
+ uint opacity;
+
+ opacity = hwnd.opacity;
+ XChangeProperty (DisplayHandle, XGetParent (hwnd.whole_window), NetAtoms [(int)NA._NET_WM_WINDOW_OPACITY], Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
+ }
+ } else {
+ hwnd.Reparented = false;
+ goto ProcessNextMessage;
+ }
+ }
+ break;
+ }
+
+ case XEventName.ConfigureNotify: {
+ if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+ XplatUIWin32.NCCALCSIZE_PARAMS ncp;
+ IntPtr ptr;
+ Rectangle rect;
+
+ #if DriverDebugExtra
+ Console.WriteLine("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}", hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
+ #endif
+ msg.message = Msg.WM_WINDOWPOSCHANGED;
+ hwnd.configure_pending = false;
+
+ // We need to adjust our client window to track the resize of whole_window
+ rect = hwnd.DefaultClientRect;
+
+ 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);
+
+ // FIXME - debug this with Menus, need to set hwnd.ClientRect
+
+ rect = new Rectangle (ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
+ //Console.WriteLine("CreateOffscreenbuffer...");
+// CreateOffscreenBuffer (ref hwnd.client_offscreen, rect.Width, rect.Height);
+
+ XMoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
+ } else {
+ goto ProcessNextMessage;
+ }
+
+ msg.lParam = IntPtr.Zero; // FIXME - Generate LPWINDOWPOS structure and pass on
+ break;
+ }
+
+ case XEventName.FocusIn: {
+ if (!hwnd.Enabled) {
+ goto ProcessNextMessage;
+ }
+ msg.message = Msg.WM_SETFOCUS;
+ msg.wParam = IntPtr.Zero;
+ break;
+ }
+
+ case XEventName.FocusOut: {
+ if (!hwnd.Enabled) {
+ goto ProcessNextMessage;
+ }
+ msg.message = Msg.WM_KILLFOCUS;
+ msg.wParam = IntPtr.Zero;
+ break;
+ }
+
+ case XEventName.Expose: {
+ if (PostQuitState) {
+ goto ProcessNextMessage;
+ }
+
+
+ if (client) {
+ if (!hwnd.expose_pending) {
+ goto ProcessNextMessage;
+ }
+ } else {
+ if (!hwnd.nc_expose_pending) {
+ goto ProcessNextMessage;
+ }
+
+ switch (hwnd.border_style) {
+ case FormBorderStyle.Fixed3D: {
+ Graphics g;
+
+ g = Graphics.FromHwnd (hwnd.whole_window);
+ ShiftUI.WidgetPaint.DrawBorder3D (g, new Rectangle (0, 0, hwnd.Width, hwnd.Height));
+ g.Dispose ();
+ break;
+ }
+
+ case FormBorderStyle.FixedSingle: {
+ Graphics g;
+
+ g = Graphics.FromHwnd (hwnd.whole_window);
+ ShiftUI.WidgetPaint.DrawBorder (g, new Rectangle (0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
+ g.Dispose ();
+ break;
+ }
+ }
+ #if DriverDebugExtra
+ Console.WriteLine("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ #endif
+
+ Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ Region region = new Region (rect);
+ IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
+ msg.message = Msg.WM_NCPAINT;
+ msg.wParam = hrgn;
+ hwnd.nc_expose_pending = false;
+ break;
+ }
+ #if DriverDebugExtra
+ Console.WriteLine("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+ #endif
+ if (Caret.Visible == 1) {
+ Caret.Paused = true;
+ HideCaret ();
+ }
+
+ if (Caret.Visible == 1) {
+ ShowCaret ();
+ Caret.Paused = false;
+ }
+ msg.message = Msg.WM_PAINT;
+ break;
+ }
+
+ case XEventName.DestroyNotify: {
+
+ // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
+ hwnd = Hwnd.ObjectFromHandle (xevent.DestroyWindowEvent.window);
+
+ // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
+ if (hwnd.client_window == xevent.DestroyWindowEvent.window) {
+ msg.hwnd = hwnd.client_window;
+ msg.message = Msg.WM_DESTROY;
+ hwnd.Dispose ();
+
+ #if DriverDebug
+ Console.WriteLine("Got DestroyNotify on Window {0:X}", msg.hwnd.ToInt32());
+ #endif
+ } else {
+ goto ProcessNextMessage;
+ }
+
+ break;
+ }
+
+ case XEventName.ClientMessage: {
+ if (Dnd.HandleClientMessage (ref xevent)) {
+ goto ProcessNextMessage;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)AsyncAtom) {
+ XplatUIDriverSupport.ExecuteClientMessage ((GCHandle)xevent.ClientMessageEvent.ptr1);
+ break;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)HoverState.Atom) {
+ msg.message = Msg.WM_MOUSEHOVER;
+ msg.wParam = GetMousewParam (0);
+ msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
+ break;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
+ msg.hwnd = xevent.ClientMessageEvent.ptr1;
+ msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
+ msg.wParam = xevent.ClientMessageEvent.ptr3;
+ msg.lParam = xevent.ClientMessageEvent.ptr4;
+ break;
+ }
+
+ #if dontcare
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)NetAtoms[(int)NA._XEMBED]) {
+ Console.WriteLine("GOT EMBED MESSAGE {0:X}", xevent.ClientMessageEvent.ptr2.ToInt32());
+ break;
+ }
+ #endif
+
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)NetAtoms [(int)NA.WM_PROTOCOLS]) {
+ if (xevent.ClientMessageEvent.ptr1 == (IntPtr)NetAtoms [(int)NA.WM_DELETE_WINDOW]) {
+ msg.message = Msg.WM_CLOSE;
+ Graphics.FromHdcInternal (IntPtr.Zero);
+ break;
+ }
+
+ // We should not get this, but I'll leave the code in case we need it in the future
+ if (xevent.ClientMessageEvent.ptr1 == (IntPtr)NetAtoms [(int)NA.WM_TAKE_FOCUS]) {
+ goto ProcessNextMessage;
+ }
+ }
+ break;
+ }
+
+ case XEventName.TimerNotify: {
+ xevent.TimerNotifyEvent.handler (this, EventArgs.Empty);
+ break;
+ }
+
+ default: {
+ goto ProcessNextMessage;
+ }
+ }
+
+ return true;
+ }
+
+ internal override bool GetText (IntPtr handle, out string text)
+ {
+ IntPtr textptr;
+
+ textptr = IntPtr.Zero;
+
+ lock (XlibLock) {
+ // FIXME - use _NET properties
+ XFetchName (DisplayHandle, Hwnd.ObjectFromHandle (handle).whole_window, ref textptr);
+ }
+ if (textptr != IntPtr.Zero) {
+ text = Marshal.PtrToStringAnsi (textptr);
+ XFree (textptr);
+ return true;
+ } else {
+ text = "";
+ return false;
+ }
+ }
+
+ 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;
+ Rectangle rect;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd != null) {
+ x = hwnd.x;
+ y = hwnd.y;
+ width = hwnd.width;
+ height = hwnd.height;
+
+ rect = Hwnd.GetClientRectangle (hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height);
+
+ client_width = rect.Width;
+ client_height = rect.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 handle)
+ {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr atom;
+ int maximized;
+ bool minimized;
+ XWindowAttributes attributes;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ maximized = 0;
+ minimized = false;
+ XGetWindowProperty (DisplayHandle, hwnd.whole_window, NetAtoms [(int)NA._NET_WM_STATE], 0, 256, false, Atom.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((nitems > 0) && (prop != IntPtr.Zero)) {
+ for (int i = 0; i < nitems; i++) {
+ atom = (IntPtr)Marshal.ReadInt32 (prop, i * 4);
+ if ((atom == (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ]) || (atom == (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT])) {
+ maximized++;
+ } else if (atom == (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_HIDDEN]) {
+ minimized = true;
+ }
+ }
+ XFree (prop);
+ }
+
+ if (minimized) {
+ return FormWindowState.Minimized;
+ } else if (maximized == 2) {
+ return FormWindowState.Maximized;
+ }
+
+ attributes = new XWindowAttributes ();
+ XGetWindowAttributes (DisplayHandle, handle, ref attributes);
+ if (attributes.map_state == MapState.IsUnmapped) {
+ throw new NotSupportedException ("Cannot retrieve the state of an unmapped window");
+ }
+
+
+ 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)
+ {
+ Hwnd hwnd;
+ IntPtr confine_to_window;
+
+ confine_to_window = IntPtr.Zero;
+
+ if (confine_to_handle != IntPtr.Zero) {
+ XWindowAttributes attributes = new XWindowAttributes ();
+
+ hwnd = Hwnd.ObjectFromHandle (confine_to_handle);
+
+ lock (XlibLock) {
+ XGetWindowAttributes (DisplayHandle, hwnd.client_window, ref attributes);
+ }
+ Grab.Area.X = attributes.x;
+ Grab.Area.Y = attributes.y;
+ Grab.Area.Width = attributes.width;
+ Grab.Area.Height = attributes.height;
+ Grab.Confined = true;
+ confine_to_window = hwnd.client_window;
+ }
+
+ Grab.Hwnd = handle;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ lock (XlibLock) {
+ XGrabPointer (DisplayHandle, hwnd.client_window, false,
+ EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
+ EventMask.ButtonReleaseMask | EventMask.PointerMotionMask,
+ GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, 0, 0);
+ }
+ }
+
+ internal override void UngrabWindow (IntPtr hwnd)
+ {
+ lock (XlibLock) {
+ XUngrabPointer (DisplayHandle, 0);
+ XFlush (DisplayHandle);
+ }
+ Grab.Hwnd = IntPtr.Zero;
+ Grab.Confined = false;
+ }
+
+ internal override void HandleException (Exception e)
+ {
+ StackTrace st = new StackTrace (e, true);
+ 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;
+ XEvent xevent;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+
+ xevent = new XEvent ();
+ xevent.type = XEventName.Expose;
+ xevent.ExposeEvent.display = DisplayHandle;
+ xevent.ExposeEvent.window = hwnd.client_window;
+
+ if (clear) {
+ xevent.ExposeEvent.x = hwnd.X;
+ xevent.ExposeEvent.y = hwnd.Y;
+ xevent.ExposeEvent.width = hwnd.Width;
+ xevent.ExposeEvent.height = hwnd.Height;
+ } else {
+ xevent.ExposeEvent.x = rc.X;
+ xevent.ExposeEvent.y = rc.Y;
+ xevent.ExposeEvent.width = rc.Width;
+ xevent.ExposeEvent.height = rc.Height;
+ }
+
+ AddExpose (xevent);
+ }
+
+ 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 MenuToScreen (IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates (DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ internal override void OverrideCursor (IntPtr cursor)
+ {
+ OverrideCursorHandle = cursor;
+ }
+
+ internal PaintEventArgs PaintEventStart (IntPtr handle, bool client)
+ {
+ PaintEventArgs paint_event;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (Caret.Visible == 1) {
+ Caret.Paused = true;
+ HideCaret ();
+ }
+
+ if (client) {
+ // handle backing store
+ IntPtr gdk_window = gdk_window_lookup (hwnd.client_window);
+ IntPtr gdk_pixmap = NewPixmap (gdk_window, hwnd.ClientRect.Width, hwnd.ClientRect.Height);
+
+ backing_store [gdk_window] = gdk_pixmap;
+
+ hwnd.client_dc = Graphics.FromHwnd (gdk_x11_drawable_get_xid (gdk_pixmap));
+ hwnd.client_dc.SetClip (hwnd.invalid);
+ paint_event = new PaintEventArgs (hwnd.client_dc, hwnd.invalid);
+ hwnd.expose_pending = false;
+
+ return paint_event;
+ } else {
+ hwnd.client_dc = Graphics.FromHwnd (hwnd.whole_window);
+ paint_event = new PaintEventArgs (hwnd.client_dc, new Rectangle (0, 0, hwnd.width, hwnd.height));
+ hwnd.nc_expose_pending = false;
+
+ return paint_event;
+ }
+ }
+
+ internal void PaintEventEnd (IntPtr handle, bool client)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ hwnd.client_dc.Flush ();
+
+ if (client) {
+ // clients are already drawn to a backing store pixmap
+ IntPtr gdk_window = gdk_window_lookup (hwnd.client_window);
+ IntPtr gdk_pixmap = (IntPtr)backing_store [gdk_window];
+
+ BlitOffscreenPixmap (gdk_pixmap, gdk_window, hwnd.Invalid);
+
+ g_object_unref (gdk_pixmap);
+ backing_store.Remove (gdk_pixmap);
+
+ hwnd.ClearInvalidArea ();
+ }
+
+ hwnd.client_dc.Dispose ();
+ hwnd.client_dc = null;
+
+ if (Caret.Visible == 1) {
+ ShowCaret ();
+ Caret.Paused = false;
+ }
+ }
+
+ internal bool PeekMessage (ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
+ {
+ bool pending;
+
+ // FIXME - imlement filtering
+
+ if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
+ throw new NotImplementedException ("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
+ }
+
+ pending = false;
+ if (MessageQueue.Count > 0) {
+ pending = true;
+ } else {
+ // Only call UpdateMessageQueue if real events are pending
+ // otherwise we go to sleep on the socket
+ if (XPending (DisplayHandle) != 0) {
+ UpdateMessageQueue ();
+ pending = true;
+ }
+ }
+
+ CheckTimers (DateTime.Now);
+
+ if (!pending) {
+ return false;
+ }
+ return GetMessage (ref msg, hWnd, wFilterMin, wFilterMax);
+ }
+
+ // FIXME - I think this should just enqueue directly
+ internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam)
+ {
+ XEvent xevent = new XEvent ();
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = DisplayHandle;
+
+ if (hwnd != null) {
+ xevent.ClientMessageEvent.window = hwnd.whole_window;
+ } else {
+ xevent.ClientMessageEvent.window = IntPtr.Zero;
+ }
+
+ xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = handle;
+ xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
+ xevent.ClientMessageEvent.ptr3 = wparam;
+ xevent.ClientMessageEvent.ptr4 = lparam;
+
+ MessageQueue.Enqueue (xevent);
+
+ return true;
+ }
+
+ internal override void PostQuitMessage (int exitCode)
+ {
+ XFlush (DisplayHandle);
+ PostQuitState = true;
+
+ // Remove our display handle from S.D
+ Graphics.FromHdcInternal (IntPtr.Zero);
+ }
+
+ internal override void ScreenToClient (IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ internal override void ScreenToMenu (IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ lock (XlibLock) {
+ XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
+ }
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ internal override void ScrollWindow (IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children)
+ {
+ Hwnd hwnd;
+ IntPtr gc;
+ XGCValues gc_values;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd.invalid != Rectangle.Empty) {
+ // BIG FAT WARNING. This only works with how we use this function right now
+ // where we basically still scroll the whole window, but work around areas
+ // that are covered by our children
+
+ hwnd.invalid.X += XAmount;
+ hwnd.invalid.Y += YAmount;
+
+ if (hwnd.invalid.X < 0) {
+ hwnd.invalid.Width += hwnd.invalid.X;
+ hwnd.invalid.X = 0;
+ }
+
+ if (hwnd.invalid.Y < 0) {
+ hwnd.invalid.Height += hwnd.invalid.Y;
+ hwnd.invalid.Y = 0;
+ }
+ }
+
+ gc_values = new XGCValues ();
+
+ if (with_children) {
+ gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
+ }
+
+ gc = XCreateGC (DisplayHandle, hwnd.client_window, 0, ref gc_values);
+
+ XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, area.X - XAmount, area.Y - YAmount, area.Width, area.Height, area.X, area.Y);
+
+ // Generate an expose for the area exposed by the horizontal scroll
+ if (XAmount > 0) {
+ hwnd.AddInvalidArea (area.X, area.Y, XAmount, area.Height);
+ } else if (XAmount < 0) {
+ hwnd.AddInvalidArea (XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
+ }
+
+ // Generate an expose for the area exposed by the vertical scroll
+ if (YAmount > 0) {
+ hwnd.AddInvalidArea (area.X, area.Y, area.Width, YAmount);
+ } else if (YAmount < 0) {
+ hwnd.AddInvalidArea (area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
+ }
+ XFreeGC (DisplayHandle, gc);
+
+ UpdateWindow (handle);
+ }
+
+ internal override void ScrollWindow (IntPtr handle, int XAmount, int YAmount, bool with_children)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.GetObjectFromWindow (handle);
+
+ ScrollWindow (handle, hwnd.ClientRect, XAmount, YAmount, with_children);
+ }
+
+ internal override void SendAsyncMethod (AsyncMethodData method)
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = DisplayHandle;
+ xevent.ClientMessageEvent.window = FosterParent;
+ xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
+
+ MessageQueue.EnqueueLocked (xevent);
+
+ WakeupMain ();
+ }
+
+ internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
+ {
+ return NativeWindow.WndProc (hwnd, message, wParam, lParam);
+ }
+
+ internal override void SetAllowDrop (IntPtr handle, bool value)
+ {
+ // We allow drop on all windows
+ }
+
+ 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)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ hwnd.border_style = border_style;
+
+ XMoveResizeWindow (DisplayHandle, hwnd.client_window, hwnd.ClientRect.X, hwnd.ClientRect.Y, hwnd.ClientRect.Width, hwnd.ClientRect.Height);
+
+ InvalidateWholeWindow (handle);
+ }
+
+ internal override void SetCaretPos (IntPtr handle, int x, int y)
+ {
+ if (Caret.Hwnd == handle) {
+ Caret.Timer.Stop ();
+ HideCaret ();
+
+ Caret.X = x;
+ Caret.Y = y;
+
+ if (Caret.Visible == 1) {
+ ShowCaret ();
+ Caret.Timer.Start ();
+ }
+ }
+ }
+
+ internal override void SetCursor (IntPtr handle, IntPtr cursor)
+ {
+ Hwnd hwnd;
+
+ if (OverrideCursorHandle == IntPtr.Zero) {
+ if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
+ return;
+ }
+
+ LastCursorHandle = cursor;
+ LastCursorWindow = handle;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ lock (XlibLock) {
+ if (cursor != IntPtr.Zero) {
+ XDefineCursor (DisplayHandle, hwnd.whole_window, cursor);
+ } else {
+ XUndefineCursor (DisplayHandle, hwnd.whole_window);
+ }
+ }
+ return;
+ }
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ lock (XlibLock) {
+ XDefineCursor (DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
+ }
+ }
+
+ internal override void SetCursorPos (IntPtr handle, int x, int y)
+ {
+ if (handle == IntPtr.Zero) {
+ lock (XlibLock) {
+ XWarpPointer (DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x, y);
+ }
+ return;
+ } else {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ lock (XlibLock) {
+ XWarpPointer (DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
+ }
+ return;
+ }
+ }
+
+ internal override void SetFocus (IntPtr handle)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (FocusWindow != IntPtr.Zero) {
+ PostMessage (FocusWindow, Msg.WM_KILLFOCUS, hwnd.client_window, IntPtr.Zero);
+ }
+ PostMessage (hwnd.client_window, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero);
+ FocusWindow = hwnd.client_window;
+
+ //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
+ }
+
+ internal override void SetIcon (IntPtr handle, Icon icon)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ if (hwnd != null) {
+ SetIcon (hwnd, icon);
+ }
+ }
+
+ internal override void SetMenu (IntPtr handle, Menu menu)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ hwnd.menu = menu;
+
+ // FIXME - do we need to trigger some resize?
+ }
+
+ internal override void SetModal (IntPtr handle, bool Modal)
+ {
+ if (Modal) {
+ ModalWindows.Push (handle);
+ } else {
+ if (ModalWindows.Contains (handle)) {
+ ModalWindows.Pop ();
+ }
+ if (ModalWindows.Count > 0) {
+ Activate ((IntPtr)ModalWindows.Peek ());
+ }
+ }
+ }
+
+ internal override IntPtr SetParent (IntPtr handle, IntPtr parent)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ hwnd.parent = Hwnd.ObjectFromHandle (parent);
+
+ lock (XlibLock) {
+ #if DriverDebug
+ Console.WriteLine("Parent for window {0:X} / {1:X} = {2:X} (Handle:{3:X})", hwnd.ClientWindow.ToInt32(), hwnd.WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0, parent.ToInt32());
+ #endif
+ XReparentWindow (DisplayHandle, hwnd.whole_window, hwnd.parent.client_window, hwnd.x, hwnd.y);
+ }
+
+ return IntPtr.Zero;
+ }
+
+ internal override void SetTimer (Timer timer)
+ {
+ lock (TimerList) {
+ TimerList.Add (timer);
+ }
+ WakeupMain ();
+ }
+
+ internal bool SetTopmost (IntPtr handle, IntPtr handle_owner, bool enabled)
+ {
+ Hwnd hwnd;
+ Hwnd hwnd_owner;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (handle_owner != IntPtr.Zero) {
+ hwnd_owner = Hwnd.ObjectFromHandle (handle_owner);
+ } else {
+ hwnd_owner = null;
+ }
+
+ if (enabled) {
+ lock (XlibLock) {
+ if (hwnd_owner != null) {
+ XSetTransientForHint (DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
+ } else {
+ XSetTransientForHint (DisplayHandle, hwnd.whole_window, FosterParent);
+ }
+ }
+ } else {
+ lock (XlibLock) {
+ XDeleteProperty (DisplayHandle, hwnd.whole_window, (int)Atom.XA_WM_TRANSIENT_FOR);
+ }
+ }
+ return true;
+ }
+
+ internal bool SetVisible (IntPtr handle, bool visible)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ hwnd.visible = visible;
+
+ lock (XlibLock) {
+ if (visible) {
+ if (ShiftUI.Widget.FromHandle (handle) is Form) {
+ FormWindowState s;
+
+ s = ((Form)ShiftUI.Widget.FromHandle (handle)).WindowState;
+
+ XMapWindow (DisplayHandle, hwnd.whole_window);
+ XMapWindow (DisplayHandle, hwnd.client_window);
+
+ switch (s) {
+ case FormWindowState.Minimized: SetWindowState (handle, FormWindowState.Minimized); break;
+ case FormWindowState.Maximized: SetWindowState (handle, FormWindowState.Maximized); break;
+ }
+ } else {
+ XMapWindow (DisplayHandle, hwnd.whole_window);
+ XMapWindow (DisplayHandle, hwnd.client_window);
+ }
+ } else {
+ XUnmapWindow (DisplayHandle, hwnd.whole_window);
+ }
+ }
+ return true;
+ }
+
+ internal override void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max)
+ {
+ Hwnd hwnd;
+ XSizeHints hints;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ if (hwnd == null) {
+ return;
+ }
+
+ hints = new XSizeHints ();
+
+ if (min != Size.Empty) {
+ hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
+ hints.min_width = min.Width;
+ hints.min_height = min.Height;
+ }
+
+ if (max != Size.Empty) {
+ hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
+ hints.max_width = max.Width;
+ hints.max_height = max.Height;
+ }
+
+ XSetWMNormalHints (DisplayHandle, hwnd.whole_window, ref hints);
+
+ if (maximized != Rectangle.Empty) {
+ hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
+ hints.x = maximized.X;
+ hints.y = maximized.Y;
+ hints.width = maximized.Width;
+ hints.height = maximized.Height;
+
+ // Metacity does not seem to follow this constraint for maximized (zoomed) windows
+ XSetZoomHints (DisplayHandle, hwnd.whole_window, ref hints);
+ }
+ }
+
+
+ internal override void SetWindowPos (IntPtr handle, int x, int y, int width, int height)
+ {
+ Hwnd hwnd;
+ Rectangle client_rect;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ // X requires a sanity check for width & height; otherwise it dies
+ if (hwnd.zero_sized && width > 0 && height > 0) {
+ if (hwnd.visible) {
+ XMapWindow (DisplayHandle, hwnd.whole_window);
+ }
+ hwnd.zero_sized = false;
+ }
+
+ if (width < 1) {
+ hwnd.zero_sized = true;
+ XUnmapWindow (DisplayHandle, hwnd.whole_window);
+ }
+
+ if (height < 1) {
+ hwnd.zero_sized = true;
+ XUnmapWindow (DisplayHandle, hwnd.whole_window);
+ }
+
+ client_rect = Hwnd.GetClientRectangle (hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height);
+
+ // Save a server roundtrip (and prevent a feedback loop)
+ if ((hwnd.x == x) && (hwnd.y == y) &&
+ (hwnd.width == width) && (hwnd.height == height) &&
+ (hwnd.ClientRect == client_rect)) {
+ return;
+ }
+
+ if (!hwnd.zero_sized) {
+ lock (XlibLock) {
+ XMoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, width, height);
+ XMoveResizeWindow (DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
+ }
+ }
+
+ // Prevent an old queued ConfigureNotify from setting our width with outdated data, set it now
+ hwnd.width = width;
+ hwnd.height = height;
+ }
+
+ internal override void SetWindowState (IntPtr handle, FormWindowState state)
+ {
+ FormWindowState current_state;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ current_state = GetWindowState (handle);
+
+ if (current_state == state) {
+ return;
+ }
+
+ switch (state) {
+ case FormWindowState.Normal: {
+ lock (XlibLock) {
+ if (current_state == FormWindowState.Minimized) {
+ XMapWindow (DisplayHandle, hwnd.whole_window);
+ XMapWindow (DisplayHandle, hwnd.client_window);
+ } else if (current_state == FormWindowState.Maximized) {
+ SendNetWMMessage (hwnd.whole_window, (IntPtr)(uint)NetAtoms [(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT]);
+ }
+ }
+ Activate (handle);
+ return;
+ }
+
+ case FormWindowState.Minimized: {
+ lock (XlibLock) {
+ if (current_state == FormWindowState.Maximized) {
+ SendNetWMMessage (hwnd.whole_window, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT]);
+ }
+ XIconifyWindow (DisplayHandle, hwnd.whole_window, ScreenNo);
+ }
+ return;
+ }
+
+ case FormWindowState.Maximized: {
+ lock (XlibLock) {
+ if (current_state == FormWindowState.Minimized) {
+ XMapWindow (DisplayHandle, hwnd.whole_window);
+ XMapWindow (DisplayHandle, hwnd.client_window);
+ }
+
+ SendNetWMMessage (hwnd.whole_window, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE], (IntPtr)1 /* Add */, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT]);
+ }
+ Activate (handle);
+ return;
+ }
+ }
+ }
+
+ internal override void SetWindowStyle (IntPtr handle, CreateParams cp)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ SetHwndStyles (hwnd, cp);
+ SetWMStyles (hwnd, cp);
+ }
+
+ internal override void SetWindowTransparency (IntPtr handle, double transparency, Color key)
+ {
+ Hwnd hwnd;
+ uint opacity;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (hwnd == null) {
+ return;
+ }
+
+ hwnd.opacity = (uint)(0xffffffff * transparency);
+ opacity = hwnd.opacity;
+
+ if (hwnd.reparented) {
+ XChangeProperty (DisplayHandle, XGetParent (hwnd.whole_window), NetAtoms [(int)NA._NET_WM_WINDOW_OPACITY], Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
+ }
+ }
+
+ internal override bool SetZOrder (IntPtr handle, IntPtr after_handle, bool top, bool bottom)
+ {
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (top) {
+ lock (XlibLock) {
+ XRaiseWindow (DisplayHandle, hwnd.whole_window);
+ }
+ return true;
+ } else if (!bottom) {
+ Hwnd after_hwnd = null;
+
+ if (after_handle != IntPtr.Zero) {
+ after_hwnd = Hwnd.ObjectFromHandle (after_handle);
+ }
+
+ XWindowChanges values = new XWindowChanges ();
+
+ if (after_hwnd == null) {
+ throw new ArgumentNullException ("after_handle", "Need sibling to adjust z-order");
+ }
+ values.sibling = after_hwnd.whole_window;
+ values.stack_mode = StackMode.Below;
+
+ lock (XlibLock) {
+ XConfigureWindow (DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
+ }
+ } else {
+ // Bottom
+ lock (XlibLock) {
+ XLowerWindow (DisplayHandle, hwnd.whole_window);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ internal override void ShowCursor (bool show)
+ {
+ ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
+ }
+
+ internal override object StartLoop (Thread thread)
+ {
+ // Future place for prepping a new queue for this specific thread
+ return thread;
+ }
+
+ internal override TransparencySupport SupportsTransparency ()
+ {
+ // We need to check if the x compositing manager is running
+ return TransparencySupport.Get;
+ }
+
+ internal override bool SystrayAdd (IntPtr handle, string tip, Icon icon, out ToolTip tt)
+ {
+ GetSystrayManagerWindow ();
+
+ if (SystrayMgrWindow != IntPtr.Zero) {
+ uint[] atoms;
+ XSizeHints size_hints;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+ #if DriverDebug
+ Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
+ #endif
+
+ XUnmapWindow (DisplayHandle, hwnd.whole_window);
+ XUnmapWindow (DisplayHandle, hwnd.client_window);
+
+ // Oh boy.
+ gdk_window_destroy (gdk_window_lookup (hwnd.client_window));
+ hwnd.client_window = hwnd.whole_window;
+
+ size_hints = new XSizeHints ();
+
+ size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
+ size_hints.min_width = icon.Width;
+ size_hints.min_height = icon.Height;
+
+ size_hints.max_width = icon.Width;
+ size_hints.max_height = icon.Height;
+
+ size_hints.base_width = icon.Width;
+ size_hints.base_height = icon.Height;
+ XSetWMNormalHints (DisplayHandle, hwnd.whole_window, ref size_hints);
+
+ atoms = new uint [2];
+ atoms [0] = 1; // Version 1
+ atoms [1] = 0; // We're not mapped
+
+ // This line cost me 3 days...
+ XChangeProperty (DisplayHandle, hwnd.whole_window, NetAtoms [(int)NA._XEMBED_INFO], NetAtoms [(int)NA._XEMBED_INFO], 32, PropertyMode.Replace, atoms, 2);
+
+ // Need to pick some reasonable defaults
+ tt = new ToolTip ();
+ tt.AutomaticDelay = 100;
+ tt.InitialDelay = 250;
+ tt.ReshowDelay = 250;
+ tt.ShowAlways = true;
+
+ if ((tip != null) && (tip != string.Empty)) {
+ tt.SetToolTip (ShiftUI.Widget.FromHandle (handle), tip);
+ tt.Active = true;
+ } else {
+ tt.Active = false;
+ }
+
+ // Make sure the window exists
+ XSync (DisplayHandle, hwnd.whole_window);
+
+ SendNetClientMessage (SystrayMgrWindow, (IntPtr)NetAtoms [(int)NA._NET_SYSTEM_TRAY_OPCODE], IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
+ return true;
+ }
+
+ tt = null;
+ return false;
+ }
+
+ internal override bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt)
+ {
+ ShiftUI.Widget Widget;
+
+ Widget = ShiftUI.Widget.FromHandle (handle);
+ if (Widget != null && tt != null) {
+ tt.SetToolTip (Widget, tip);
+ tt.Active = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ internal override void SystrayRemove (IntPtr handle, ref ToolTip tt)
+ {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ XUnmapWindow (DisplayHandle, hwnd.whole_window);
+ SetParent (hwnd.whole_window, FosterParent);
+
+ // The caller can now re-dock it later...
+ if (tt != null) {
+ tt.Dispose ();
+ tt = null;
+ }
+ }
+
+ internal override bool Text (IntPtr handle, string text)
+ {
+ lock (XlibLock) {
+ gdk_window_set_title (gdk_window_lookup (Hwnd.ObjectFromHandle (handle).whole_window), text);
+ }
+ return true;
+ }
+
+ internal override bool TranslateMessage (ref MSG msg)
+ {
+ return Keyboard.TranslateMessage (ref msg);
+ }
+
+ internal override void UpdateWindow (IntPtr handle)
+ {
+ XEvent xevent;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle (handle);
+
+ if (!hwnd.visible || hwnd.expose_pending) {
+ return;
+ }
+
+ #if not
+ SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+ #else
+ xevent = new XEvent ();
+ xevent.type = XEventName.Expose;
+ xevent.ExposeEvent.display = DisplayHandle;
+ xevent.ExposeEvent.window = hwnd.client_window;
+
+ MessageQueue.Enqueue (xevent);
+ hwnd.expose_pending = true;
+ #endif
+ }
+
+ internal static IntPtr NewPixmap (IntPtr gdk_window, int width, int height)
+ {
+ return gdk_pixmap_new (gdk_window, width, height, 24); // FIXME: instead of 24, get the correct display depth
+ }
+
+ internal static void BlitOffscreenPixmap (IntPtr gdk_pixmap, IntPtr dest_drawable, Rectangle area)
+ {
+ IntPtr gdk_gc = gdk_gc_new (gdk_pixmap);
+
+ gdk_draw_drawable (dest_drawable, gdk_gc, gdk_pixmap, area.X, area.Y, area.X, area.Y, area.Width, area.Height);
+
+ g_object_unref (gdk_gc);
+ }
+ #endregion // Public Static Methods
+
+ #region Events
+ internal override event EventHandler Idle;
+ #endregion // Events
+
+ #region X11 Imports
+ [DllImport ("libX11", EntryPoint="XSynchronize")]
+ internal extern static IntPtr XSynchronize (IntPtr display, bool onoff);
+
+ [DllImport ("libX11", EntryPoint="XCreateWindow")]
+ internal extern static IntPtr XCreateWindow (IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, SetWindowValuemask valuemask, ref XSetWindowAttributes attributes);
+ [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
+ internal extern static IntPtr XCreateSimpleWindow (IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int border, int background);
+ [DllImport ("libX11", EntryPoint="XMapWindow")]
+ internal extern static int XMapWindow (IntPtr display, IntPtr window);
+ [DllImport ("libX11", EntryPoint="XUnmapWindow")]
+ internal extern static int XUnmapWindow (IntPtr display, IntPtr window);
+ [DllImport ("libX11", EntryPoint="XMapSubwindows")]
+ internal extern static int XMapSubindows (IntPtr display, IntPtr window);
+ [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
+ internal extern static int XUnmapSubwindows (IntPtr display, IntPtr window);
+ [DllImport ("libX11", EntryPoint="XRootWindow")]
+ internal extern static IntPtr XRootWindow (IntPtr display, int screen_number);
+ [DllImport ("libX11", EntryPoint="XNextEvent")]
+ internal extern static IntPtr XNextEvent (IntPtr display, ref XEvent xevent);
+ [DllImport ("libX11")]
+ internal extern static int XConnectionNumber (IntPtr diplay);
+ [DllImport ("libX11")]
+ internal extern static int XPending (IntPtr diplay);
+ [DllImport ("libX11")]
+ internal extern static bool XCheckWindowEvent (IntPtr display, IntPtr window, EventMask mask, ref XEvent xevent);
+ [DllImport ("libX11")]
+ internal extern static bool XCheckMaskEvent (IntPtr display, EventMask mask, ref XEvent xevent);
+ [DllImport ("libX11", EntryPoint="XSelectInput")]
+ internal extern static IntPtr XSelectInput (IntPtr display, IntPtr window, EventMask mask);
+
+ [DllImport ("libX11", EntryPoint="XReparentWindow")]
+ internal extern static int XReparentWindow (IntPtr display, IntPtr window, IntPtr parent, int x, int y);
+ [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
+ internal extern static int XMoveResizeWindow (IntPtr display, IntPtr window, int x, int y, int width, int height);
+
+ [DllImport ("libX11", EntryPoint="XResizeWindow")]
+ internal extern static int XResizeWindow (IntPtr display, IntPtr window, int width, int height);
+
+ [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
+ internal extern static int XGetWindowAttributes (IntPtr display, IntPtr window, ref XWindowAttributes attributes);
+
+ [DllImport ("libX11", EntryPoint="XFlush")]
+ internal extern static int XFlush (IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XSetWMName")]
+ internal extern static int XSetWMName (IntPtr display, IntPtr window, ref XTextProperty text_prop);
+
+ [DllImport ("libX11", EntryPoint="XStoreName")]
+ internal extern static int XStoreName (IntPtr display, IntPtr window, string window_name);
+
+ [DllImport ("libX11", EntryPoint="XFetchName")]
+ internal extern static int XFetchName (IntPtr display, IntPtr window, ref IntPtr window_name);
+
+ [DllImport ("libX11", EntryPoint="XSendEvent")]
+ internal extern static int XSendEvent (IntPtr display, IntPtr window, bool propagate, EventMask event_mask, ref XEvent send_event);
+
+ [DllImport ("libX11", EntryPoint="XQueryTree")]
+ internal extern static int XQueryTree (IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return);
+
+ [DllImport ("libX11", EntryPoint="XFree")]
+ internal extern static int XFree (IntPtr data);
+
+ [DllImport ("libX11", EntryPoint="XRaiseWindow")]
+ internal extern static int XRaiseWindow (IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XLowerWindow")]
+ internal extern static uint XLowerWindow (IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XConfigureWindow")]
+ internal extern static uint XConfigureWindow (IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
+
+ [DllImport ("libX11", EntryPoint="XInternAtom")]
+ internal extern static int XInternAtom (IntPtr display, string atom_name, bool only_if_exists);
+
+ [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
+ internal extern static int XSetWMProtocols (IntPtr display, IntPtr window, uint[] protocols, int count);
+
+ [DllImport ("libX11", EntryPoint="XGrabPointer")]
+ internal extern static int XGrabPointer (IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, uint cursor, uint timestamp);
+
+ [DllImport ("libX11", EntryPoint="XUngrabPointer")]
+ internal extern static int XUngrabPointer (IntPtr display, uint timestamp);
+
+ [DllImport ("libX11", EntryPoint="XQueryPointer")]
+ internal extern static bool XQueryPointer (IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons);
+
+ [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
+ internal extern static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return);
+
+ [DllImport ("libX11", EntryPoint="XWarpPointer")]
+ internal extern static uint XWarpPointer (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y);
+
+ [DllImport ("libX11", EntryPoint="XClearWindow")]
+ internal extern static int XClearWindow (IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XClearArea")]
+ internal extern static int XClearArea (IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
+
+ // Colormaps
+ [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
+ internal extern static IntPtr XDefaultScreenOfDisplay (IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
+ internal extern static int XScreenNumberOfScreen (IntPtr display, IntPtr Screen);
+
+ [DllImport ("libX11", EntryPoint="XDefaultVisual")]
+ internal extern static IntPtr XDefaultVisual (IntPtr display, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XDefaultDepth")]
+ internal extern static uint XDefaultDepth (IntPtr display, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XDefaultColormap")]
+ internal extern static IntPtr XDefaultColormap (IntPtr display, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XLookupColor")]
+ internal extern static int XLookupColor (IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
+
+ [DllImport ("libX11", EntryPoint="XAllocColor")]
+ internal extern static int XAllocColor (IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
+
+ [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
+ internal extern static int XSetTransientForHint (IntPtr display, IntPtr window, IntPtr prop_window);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, uint[] atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, ref uint value, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, uint[] atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, IntPtr atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, IntPtr atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
+ internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int type, int format, PropertyMode mode, string text, int text_length);
+
+ [DllImport ("libX11", EntryPoint="XDeleteProperty")]
+ internal extern static int XDeleteProperty (IntPtr display, IntPtr window, int property);
+
+ // Drawing
+ [DllImport ("libX11", EntryPoint="XCreateGC")]
+ internal extern static IntPtr XCreateGC (IntPtr display, IntPtr window, GCFunction valuemask, ref XGCValues values);
+
+ [DllImport ("libX11", EntryPoint="XFreeGC")]
+ internal extern static int XFreeGC (IntPtr display, IntPtr gc);
+
+ [DllImport ("libX11", EntryPoint="XSetFunction")]
+ internal extern static int XSetFunction (IntPtr display, IntPtr gc, GXFunction function);
+
+ [DllImport ("libX11", EntryPoint="XDrawLine")]
+ internal extern static int XDrawLine (IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
+
+ [DllImport ("libX11", EntryPoint="XDrawRectangle")]
+ internal extern static int XDrawRectangle (IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
+
+ [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
+ internal extern static int XSetWindowBackground (IntPtr display, IntPtr window, IntPtr background);
+
+ [DllImport ("libX11", EntryPoint="XCopyArea")]
+ internal extern static int XCopyArea (IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
+
+ [DllImport ("libX11", EntryPoint="XGetAtomName")]
+ internal extern static string XGetAtomName (IntPtr display, int atom);
+
+ [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
+ internal extern static int XGetWindowProperty (IntPtr display, IntPtr window, int atom, int long_offset, int long_length, bool delete, Atom req_type, out Atom actual_type, out int actual_format, out int nitems, out int bytes_after, ref IntPtr prop);
+
+ [DllImport ("libX11", EntryPoint="XSetInputFocus")]
+ internal extern static int XSetInputFocus (IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XIconifyWindow")]
+ internal extern static int XIconifyWindow (IntPtr display, IntPtr window, int screen_number);
+
+ [DllImport ("libX11", EntryPoint="XDefineCursor")]
+ internal extern static int XDefineCursor (IntPtr display, IntPtr window, IntPtr cursor);
+
+ [DllImport ("libX11", EntryPoint="XUndefineCursor")]
+ internal extern static int XUndefineCursor (IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XFreeCursor")]
+ internal extern static int XFreeCursor (IntPtr display, IntPtr cursor);
+
+ [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
+ internal extern static IntPtr XCreateFontCursor (IntPtr display, CursorFontShape shape);
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
+ internal extern static IntPtr XCreatePixmapCursor (IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot);
+
+ [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
+ internal extern static IntPtr XCreatePixmapFromBitmapData (IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
+
+ [DllImport ("libX11", EntryPoint="XFreePixmap")]
+ internal extern static IntPtr XFreePixmap (IntPtr display, IntPtr pixmap);
+
+ [DllImport ("libX11", EntryPoint="XWhitePixel")]
+ internal extern static IntPtr XWhitePixel (IntPtr display, int screen_no);
+
+ [DllImport ("libX11", EntryPoint="XBlackPixel")]
+ internal extern static IntPtr XBlackPixel (IntPtr display, int screen_no);
+
+ [DllImport ("libX11", EntryPoint="XGrabServer")]
+ internal extern static void XGrabServer (IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XUngrabServer")]
+ internal extern static void XUngrabServer (IntPtr display);
+
+ [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
+ internal extern static void XSetWMNormalHints (IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport ("libX11", EntryPoint="XSetZoomHints")]
+ internal extern static void XSetZoomHints (IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport ("libX11", EntryPoint="XSetWMHints")]
+ internal extern static void XSetWMHints (IntPtr display, IntPtr window, ref XWMHints wmhints);
+
+ [DllImport ("libX11", EntryPoint="XSync")]
+ internal extern static void XSync (IntPtr display, IntPtr window);
+
+ [DllImport ("libX11", EntryPoint="XGetIconSizes")]
+ internal extern static int XGetIconSizes (IntPtr display, IntPtr window, out IntPtr size_list, out int count);
+
+ [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
+ internal extern static IntPtr XSetErrorHandler (XErrorHandler error_handler);
+
+ [DllImport ("libX11", EntryPoint="XGetErrorText")]
+ internal extern static IntPtr XGetErrorText (IntPtr display, byte code, StringBuilder buffer, int length);
+
+ [DllImport ("libX11", EntryPoint="XInitThreads")]
+ internal extern static int XInitThreads ();
+
+ [DllImport ("libX11", EntryPoint="XConvertSelection")]
+ internal extern static int XConvertSelection (IntPtr display, int selection, int target, int property, IntPtr requestor, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
+ internal extern static IntPtr XGetSelectionOwner (IntPtr display, int selection);
+
+ [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
+ internal extern static int XSetSelectionOwner (IntPtr display, int selection, IntPtr owner, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
+ internal extern static int XSetPlaneMask (IntPtr display, IntPtr gc, uint mask);
+
+ [DllImport ("libX11", EntryPoint="XSetForeground")]
+ internal extern static int XSetForeground (IntPtr display, IntPtr gc, uint foreground);
+
+ [DllImport ("libX11", EntryPoint="XSetBackground")]
+ internal extern static int XSetBackground (IntPtr display, IntPtr gc, uint background);
+
+ #endregion
+
+ #region gdk imports
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern bool gdk_init_check (IntPtr argc, IntPtr argv);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ internal static extern IntPtr gdk_x11_display_get_xdisplay (IntPtr display);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ internal static extern IntPtr gdk_display_get_default ();
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_pixmap_new (IntPtr drawable, int width, int height, int depth);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_x11_drawable_get_xid (IntPtr gdkdrawable);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_draw_drawable (IntPtr drawable_dest, IntPtr gdk_gc, IntPtr drawable_src, int xsrc, int ysrc, int xdest, int ydest, int width, int height);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_gc_new (IntPtr drawable);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_window_foreign_new (IntPtr anid);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_x11_lookup_xdisplay (IntPtr xdisplay);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_display_close (IntPtr display);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_display_beep (IntPtr display);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_display_sync (IntPtr display);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_get_default_root_window ();
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_colormap_get_system ();
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_x11_colormap_get_xcolormap (IntPtr gdk_colormap);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_destroy (IntPtr gdk_window);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_x11_grab_server ();
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_x11_ungrab_server ();
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_display_flush (IntPtr gdk_display);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_iconify (IntPtr gdk_window);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_deiconify (IntPtr gdk_window);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_set_decorations (IntPtr gdk_window, int decorations);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_screen_get_default ();
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern int gdk_screen_get_number (IntPtr gdk_screen);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_window_lookup (IntPtr anid);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_window_new (IntPtr gdk_parent, ref GdkWindowAttr gdk_window_attributes, int attributes_mask);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_set_events (IntPtr gdk_window, int event_mask);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_show (IntPtr window);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_set_title (IntPtr gdk_window, string title);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern int gdk_window_get_origin (IntPtr gdk_window, out int x, out int y);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_window_get_geometry (IntPtr gdk_window, out int x, out int y, out int width, out int height, out int depth);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_property_change (IntPtr gdk_window, /*GdkAtom*/IntPtr property, /*GdkAtom*/IntPtr type, int format, int gdk_prop_mode, /*const guchar **/ IntPtr data, int nelements);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern IntPtr gdk_window_get_parent (IntPtr gdk_window);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern void gdk_display_get_maximal_cursor_size (IntPtr gdk_display, out uint width, out uint height);
+
+ [DllImport("libgdk-x11-2.0.so")]
+ static extern int gdk_visual_get_best_depth ();
+ #endregion
+
+ #region gobject imports
+ [DllImport("libglib-2.0.so")]
+ static extern void g_free (IntPtr mem);
+
+ [DllImport("libgobject-2.0.so")]
+ static extern void g_object_unref (IntPtr nativeObject);
+ #endregion
+ }
+}