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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
23 // Geoff Norton (gnorton@novell.com)
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
);
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
);
53 InstallTrackingHandler (DragTrackingHandler
, IntPtr
.Zero
, IntPtr
.Zero
);
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
;
75 internal static DataObject
DragToDataObject (IntPtr dragref
) {
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
;
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
);
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
) {
104 DragEventArgs drag_event
;
105 DragDropEffects allowed
;
106 QDPoint point
= new QDPoint ();
108 IntPtr dragref
= IntPtr
.Zero
;
109 Hwnd hwnd
= Hwnd
.ObjectFromHandle (handle
);
111 if (hwnd
== null || hwnd
.Handle
!= handle
)
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
);
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
;
131 case ControlHandler
.kEventControlDragWithin
:
132 control
.DndOver (drag_event
);
133 effects
= drag_event
.Effect
;
135 case ControlHandler
.kEventControlDragLeave
:
136 control
.DndLeave (drag_event
);
138 case ControlHandler
.kEventControlDragReceive
:
139 control
.DndDrop (drag_event
);
145 public void SetAllowDrop (Hwnd hwnd
, bool allow
) {
146 if (hwnd
.allow_drop
== allow
)
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
);
174 public void StoreObjectInDrag (IntPtr handle
, IntPtr dragref
, object data
) {
175 IntPtr type
= IntPtr
.Zero
;
176 IntPtr dataptr
= IntPtr
.Zero
;
179 if (data
is string) {
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
);
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
;
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
;
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
;
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
{
295 internal DataObject
Convert (ArrayList flavorlist
) {
298 return ConvertToFileDrop (flavorlist
);
300 return ConvertToObject (flavorlist
);
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)
317 data
.SetData (bf
.Deserialize (stream
));
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
);
334 internal DataObject
ConvertToFileDrop (ArrayList flavorlist
) {
335 DataObject data
= new DataObject ();
336 ArrayList uri_list
= new ArrayList ();
338 foreach (FlavorHandler flavor
in flavorlist
) {
340 uri_list
.Add (new Uri (flavor
.DataString
).LocalPath
);
344 string [] l
= (string []) uri_list
.ToArray (typeof (string));
347 data
.SetData (DataFormats
.FileDrop
, l
);
348 data
.SetData ("FileName", l
[0]);
349 data
.SetData ("FileNameW", l
[0]);
354 public override string ToString () {
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
);