fix typo
[mcs.git] / class / Managed.Windows.Forms / System.Windows.Forms.CarbonInternal / Dnd.cs
blob24e6bb9c1feedf8880a148c2e45f8534e1cb362a
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2007 Novell, Inc.
22 // Authors:
23 // Geoff Norton (gnorton@novell.com)
28 using System;
29 using System.IO;
30 using System.Text;
31 using System.Drawing;
32 using System.Threading;
33 using System.Collections;
34 using System.Windows.Forms;
35 using System.Runtime.Serialization;
36 using System.Runtime.InteropServices;
37 using System.Runtime.Serialization.Formatters.Binary;
39 namespace System.Windows.Forms.CarbonInternal {
40 internal delegate void DragTrackingDelegate (short message, IntPtr window, IntPtr data, IntPtr dragref);
42 internal class Dnd {
43 internal const uint kEventParamDragRef = 1685217639;
44 internal const uint typeDragRef = 1685217639;
46 internal const uint typeMono = 1836019311;
47 internal const uint typeMonoSerializedObject = 1836279154;
49 private static DragDropEffects effects = DragDropEffects.None;
50 private static DragTrackingDelegate DragTrackingHandler = new DragTrackingDelegate (TrackingCallback);
52 static Dnd () {
53 InstallTrackingHandler (DragTrackingHandler, IntPtr.Zero, IntPtr.Zero);
56 internal Dnd () {
59 internal static void TrackingCallback (short message, IntPtr window, IntPtr data, IntPtr dragref) {
60 XplatUICarbon.GetInstance ().FlushQueue ();
63 internal static DragDropEffects DragActionsToEffects (UInt32 actions) {
64 DragDropEffects effects = DragDropEffects.None;
65 if ((actions & 1) != 0)
66 effects |= DragDropEffects.Copy;
67 if ((actions & (1 << 4)) != 0)
68 effects |= DragDropEffects.Move;
69 if ((actions & 0xFFFFFFFF) != 0)
70 effects |= DragDropEffects.All;
72 return effects;
75 internal static DataObject DragToDataObject (IntPtr dragref) {
76 UInt32 items = 0;
77 ArrayList flavorlist = new ArrayList ();
79 CountDragItems (dragref, ref items);
81 for (uint item_counter = 1; item_counter <= items; item_counter++) {
82 IntPtr itemref = IntPtr.Zero;
83 UInt32 flavors = 0;
85 GetDragItemReferenceNumber (dragref, item_counter, ref itemref);
86 CountDragItemFlavors (dragref, itemref, ref flavors);
87 for (uint flavor_counter = 1; flavor_counter <= flavors; flavor_counter++) {
88 FlavorHandler flavor = new FlavorHandler (dragref, itemref, flavor_counter);
89 if (flavor.Supported)
90 flavorlist.Add (flavor);
94 if (flavorlist.Count > 0) {
95 return ((FlavorHandler) flavorlist [0]).Convert (flavorlist);
98 return new DataObject ();
101 internal static bool HandleEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
102 Control control;
103 DataObject data;
104 DragEventArgs drag_event;
105 DragDropEffects allowed;
106 QDPoint point = new QDPoint ();
107 UInt32 actions = 0;
108 IntPtr dragref = IntPtr.Zero;
109 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
111 if (hwnd == null || hwnd.Handle != handle)
112 return false;
114 GetEventParameter (eventref, kEventParamDragRef, typeDragRef, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref dragref);
115 XplatUICarbon.GetGlobalMouse (ref point);
116 GetDragAllowableActions (dragref, ref actions);
117 control = Control.FromHandle (hwnd.Handle);
118 allowed = DragActionsToEffects (actions);
119 data = DragToDataObject (dragref);
120 drag_event = new DragEventArgs (data, 0, point.x, point.y, allowed, DragDropEffects.None);
122 switch (kind) {
123 case ControlHandler.kEventControlDragEnter: {
124 bool accept = control.AllowDrop;
125 SetEventParameter (eventref, ControlHandler.kEventParamControlLikesDrag, ControlHandler.typeBoolean, (uint)Marshal.SizeOf (typeof (bool)), ref accept);
127 control.DndEnter (drag_event);
128 effects = drag_event.Effect;
129 return false;
131 case ControlHandler.kEventControlDragWithin:
132 control.DndOver (drag_event);
133 effects = drag_event.Effect;
134 break;
135 case ControlHandler.kEventControlDragLeave:
136 control.DndLeave (drag_event);
137 break;
138 case ControlHandler.kEventControlDragReceive:
139 control.DndDrop (drag_event);
140 break;
142 return true;
145 public void SetAllowDrop (Hwnd hwnd, bool allow) {
146 if (hwnd.allow_drop == allow)
147 return;
149 hwnd.allow_drop = allow;
150 SetControlDragTrackingEnabled (hwnd.whole_window, true);
151 SetControlDragTrackingEnabled (hwnd.client_window, true);
154 public void SendDrop (IntPtr handle, IntPtr from, IntPtr time) {
157 public DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowed_effects) {
158 IntPtr dragref = IntPtr.Zero;
159 EventRecord eventrecord = new EventRecord ();
161 effects = DragDropEffects.None;
163 NewDrag (ref dragref);
164 XplatUICarbon.GetGlobalMouse (ref eventrecord.mouse);
165 StoreObjectInDrag (handle, dragref, data);
167 TrackDrag (dragref, ref eventrecord, IntPtr.Zero);
169 DisposeDrag (dragref);
171 return effects;
174 public void StoreObjectInDrag (IntPtr handle, IntPtr dragref, object data) {
175 IntPtr type = IntPtr.Zero;
176 IntPtr dataptr = IntPtr.Zero;
177 Int32 size = 0;
179 if (data is string) {
180 // implement me
181 throw new NotSupportedException ("Implement me.");
182 } else if (data is ISerializable) {
183 MemoryStream stream = new MemoryStream ();
184 BinaryFormatter bf = new BinaryFormatter ();
186 bf.Serialize (stream, data);
188 dataptr = Marshal.AllocHGlobal ((int) stream.Length);
189 stream.Seek (0, 0);
191 for (int i = 0; i < stream.Length; i++) {
192 Marshal.WriteByte (dataptr, i, (byte) stream.ReadByte ());
195 type = (IntPtr) typeMonoSerializedObject;
196 size = (int) stream.Length;
197 } else {
198 dataptr = (IntPtr) GCHandle.Alloc (data);
200 type = (IntPtr) typeMono;
201 size = Marshal.SizeOf (typeof (IntPtr));
204 AddDragItemFlavor (dragref, handle, type, ref dataptr, size, 1 << 0);
207 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
208 static extern int InstallTrackingHandler (DragTrackingDelegate callback, IntPtr window, IntPtr data);
210 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
211 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data);
212 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
213 static extern int SetEventParameter (IntPtr eventref, uint name, uint type, uint size, ref bool data);
215 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
216 extern static int SetControlDragTrackingEnabled (IntPtr view, bool enabled);
217 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
218 extern static int AddDragItemFlavor (IntPtr dragref, IntPtr itemref, IntPtr flavortype, ref IntPtr data, Int32 size, UInt32 flags);
219 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
220 extern static int CountDragItems (IntPtr dragref, ref UInt32 count);
221 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
222 extern static int CountDragItemFlavors (IntPtr dragref, IntPtr itemref, ref UInt32 count);
223 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
224 extern static int GetDragItemReferenceNumber (IntPtr dragref, UInt32 index, ref IntPtr itemref);
225 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
226 extern static int NewDrag (ref IntPtr dragref);
227 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
228 extern static int TrackDrag (IntPtr dragref, ref EventRecord eventrecord, IntPtr region);
229 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
230 extern static int DisposeDrag (IntPtr dragref);
231 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
232 extern static int GetDragAllowableActions (IntPtr dragref, ref UInt32 actions);
235 internal struct EventRecord {
236 internal UInt16 what;
237 internal UInt32 message;
238 internal UInt32 when;
239 internal QDPoint mouse;
240 internal UInt16 modifiers;
243 internal class FlavorHandler {
244 internal IntPtr flavorref;
245 internal IntPtr dragref;
246 internal IntPtr itemref;
247 internal Int32 size;
248 internal UInt32 flags;
249 internal byte [] data;
250 internal string fourcc;
252 internal FlavorHandler (IntPtr dragref, IntPtr itemref, uint counter) {
253 GetFlavorType (dragref, itemref, counter, ref flavorref);
254 GetFlavorFlags (dragref, itemref, flavorref, ref flags);
255 byte [] fourcc_b = BitConverter.GetBytes ((Int32)flavorref);
256 this.fourcc = String.Format ("{0}{1}{2}{3}", (char)fourcc_b [3], (char)fourcc_b [2], (char)fourcc_b [1], (char)fourcc_b [0]);
257 this.dragref = dragref;
258 this.itemref = itemref;
260 this.GetData ();
263 internal void GetData () {
264 GetFlavorDataSize (dragref, itemref, flavorref, ref size);
265 data = new byte [size];
266 GetFlavorData (dragref, itemref, flavorref, data, ref size, 0);
269 internal string DataString {
270 get { return Encoding.Default.GetString (this.data); }
273 internal byte[] DataArray {
274 get { return this.data; }
277 internal IntPtr DataPtr {
278 get { return (IntPtr) BitConverter.ToInt32 (this.data, 0); }
281 internal bool Supported {
282 get {
283 switch (fourcc) {
284 case "furl":
285 return true;
286 case "mono":
287 return true;
288 case "mser":
289 return true;
291 return false;
295 internal DataObject Convert (ArrayList flavorlist) {
296 switch (fourcc) {
297 case "furl":
298 return ConvertToFileDrop (flavorlist);
299 case "mono":
300 return ConvertToObject (flavorlist);
301 case "mser":
302 return DeserializeObject (flavorlist);
305 return new DataObject ();
308 internal DataObject DeserializeObject (ArrayList flavorlist) {
309 DataObject data = new DataObject ();
310 MemoryStream stream = new MemoryStream (this.DataArray);
311 BinaryFormatter bf = new BinaryFormatter ();
313 if (stream.Length == 0)
314 return data;
316 stream.Seek (0, 0);
317 data.SetData (bf.Deserialize (stream));
319 return data;
322 internal DataObject ConvertToObject (ArrayList flavorlist) {
323 DataObject data = new DataObject ();
325 foreach (FlavorHandler flavor in flavorlist) {
326 GCHandle handle = (GCHandle) flavor.DataPtr;
328 data.SetData (handle.Target);
331 return data;
334 internal DataObject ConvertToFileDrop (ArrayList flavorlist) {
335 DataObject data = new DataObject ();
336 ArrayList uri_list = new ArrayList ();
338 foreach (FlavorHandler flavor in flavorlist) {
339 try {
340 uri_list.Add (new Uri (flavor.DataString).LocalPath);
341 } catch { }
344 string [] l = (string []) uri_list.ToArray (typeof (string));
345 if (l.Length < 1)
346 return data;
347 data.SetData (DataFormats.FileDrop, l);
348 data.SetData ("FileName", l [0]);
349 data.SetData ("FileNameW", l [0]);
351 return data;
354 public override string ToString () {
355 return fourcc;
358 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
359 extern static int GetFlavorDataSize (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref Int32 size);
360 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
361 extern static int GetFlavorData (IntPtr dragref, IntPtr itemref, IntPtr flavorref, [In, Out] byte[] data, ref Int32 size, UInt32 offset);
362 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
363 extern static int GetFlavorFlags (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref UInt32 flags);
364 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
365 extern static int GetFlavorType (IntPtr dragref, IntPtr itemref, UInt32 index, ref IntPtr flavor);