aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Internal/Dnd.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Internal/Dnd.cs')
-rw-r--r--source/ShiftUI/Internal/Dnd.cs371
1 files changed, 371 insertions, 0 deletions
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);
+ }
+}