Dnd.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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.
  19. //
  20. // Copyright (c) 2007 Novell, Inc.
  21. //
  22. // Authors:
  23. // Geoff Norton ([email protected])
  24. //
  25. //
  26. using System;
  27. using System.IO;
  28. using System.Text;
  29. using System.Drawing;
  30. using System.Threading;
  31. using System.Collections;
  32. using System.Windows.Forms;
  33. using System.Runtime.Serialization;
  34. using System.Runtime.InteropServices;
  35. using System.Runtime.Serialization.Formatters.Binary;
  36. namespace System.Windows.Forms.CarbonInternal {
  37. internal delegate void DragTrackingDelegate (short message, IntPtr window, IntPtr data, IntPtr dragref);
  38. internal class Dnd {
  39. internal const uint kEventParamDragRef = 1685217639;
  40. internal const uint typeDragRef = 1685217639;
  41. internal const uint typeMono = 1836019311;
  42. internal const uint typeMonoSerializedObject = 1836279154;
  43. private static DragDropEffects effects = DragDropEffects.None;
  44. private static DragTrackingDelegate DragTrackingHandler = new DragTrackingDelegate (TrackingCallback);
  45. static Dnd () {
  46. try {
  47. InstallTrackingHandler (DragTrackingHandler, IntPtr.Zero, IntPtr.Zero);
  48. } catch (EntryPointNotFoundException) {
  49. // it is deprecated in 10.6 and does not exist anymore.
  50. }
  51. }
  52. internal Dnd () {
  53. }
  54. internal static void TrackingCallback (short message, IntPtr window, IntPtr data, IntPtr dragref) {
  55. XplatUICarbon.GetInstance ().FlushQueue ();
  56. }
  57. internal static DragDropEffects DragActionsToEffects (UInt32 actions) {
  58. DragDropEffects effects = DragDropEffects.None;
  59. if ((actions & 1) != 0)
  60. effects |= DragDropEffects.Copy;
  61. if ((actions & (1 << 4)) != 0)
  62. effects |= DragDropEffects.Move;
  63. if ((actions & 0xFFFFFFFF) != 0)
  64. effects |= DragDropEffects.All;
  65. return effects;
  66. }
  67. internal static DataObject DragToDataObject (IntPtr dragref) {
  68. UInt32 items = 0;
  69. ArrayList flavorlist = new ArrayList ();
  70. CountDragItems (dragref, ref items);
  71. for (uint item_counter = 1; item_counter <= items; item_counter++) {
  72. IntPtr itemref = IntPtr.Zero;
  73. UInt32 flavors = 0;
  74. GetDragItemReferenceNumber (dragref, item_counter, ref itemref);
  75. CountDragItemFlavors (dragref, itemref, ref flavors);
  76. for (uint flavor_counter = 1; flavor_counter <= flavors; flavor_counter++) {
  77. FlavorHandler flavor = new FlavorHandler (dragref, itemref, flavor_counter);
  78. if (flavor.Supported)
  79. flavorlist.Add (flavor);
  80. }
  81. }
  82. if (flavorlist.Count > 0) {
  83. return ((FlavorHandler) flavorlist [0]).Convert (flavorlist);
  84. }
  85. return new DataObject ();
  86. }
  87. internal static bool HandleEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
  88. Control control;
  89. DataObject data;
  90. DragEventArgs drag_event;
  91. DragDropEffects allowed;
  92. QDPoint point = new QDPoint ();
  93. UInt32 actions = 0;
  94. IntPtr dragref = IntPtr.Zero;
  95. Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
  96. if (hwnd == null || hwnd.Handle != handle)
  97. return false;
  98. GetEventParameter (eventref, kEventParamDragRef, typeDragRef, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref dragref);
  99. XplatUICarbon.GetGlobalMouse (ref point);
  100. GetDragAllowableActions (dragref, ref actions);
  101. control = Control.FromHandle (hwnd.Handle);
  102. allowed = DragActionsToEffects (actions);
  103. data = DragToDataObject (dragref);
  104. drag_event = new DragEventArgs (data, 0, point.x, point.y, allowed, DragDropEffects.None);
  105. switch (kind) {
  106. case ControlHandler.kEventControlDragEnter: {
  107. bool accept = control.AllowDrop;
  108. SetEventParameter (eventref, ControlHandler.kEventParamControlLikesDrag, ControlHandler.typeBoolean, (uint)Marshal.SizeOf (typeof (bool)), ref accept);
  109. control.DndEnter (drag_event);
  110. effects = drag_event.Effect;
  111. return false;
  112. }
  113. case ControlHandler.kEventControlDragWithin:
  114. control.DndOver (drag_event);
  115. effects = drag_event.Effect;
  116. break;
  117. case ControlHandler.kEventControlDragLeave:
  118. control.DndLeave (drag_event);
  119. break;
  120. case ControlHandler.kEventControlDragReceive:
  121. control.DndDrop (drag_event);
  122. break;
  123. }
  124. return true;
  125. }
  126. public void SetAllowDrop (Hwnd hwnd, bool allow) {
  127. if (hwnd.allow_drop == allow)
  128. return;
  129. hwnd.allow_drop = allow;
  130. SetControlDragTrackingEnabled (hwnd.whole_window, true);
  131. SetControlDragTrackingEnabled (hwnd.client_window, true);
  132. }
  133. public void SendDrop (IntPtr handle, IntPtr from, IntPtr time) {
  134. }
  135. public DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowed_effects) {
  136. IntPtr dragref = IntPtr.Zero;
  137. EventRecord eventrecord = new EventRecord ();
  138. effects = DragDropEffects.None;
  139. NewDrag (ref dragref);
  140. XplatUICarbon.GetGlobalMouse (ref eventrecord.mouse);
  141. StoreObjectInDrag (handle, dragref, data);
  142. TrackDrag (dragref, ref eventrecord, IntPtr.Zero);
  143. DisposeDrag (dragref);
  144. return effects;
  145. }
  146. public void StoreObjectInDrag (IntPtr handle, IntPtr dragref, object data) {
  147. IntPtr type = IntPtr.Zero;
  148. IntPtr dataptr = IntPtr.Zero;
  149. Int32 size = 0;
  150. if (data is string) {
  151. // implement me
  152. throw new NotSupportedException ("Implement me.");
  153. } else if (data is ISerializable) {
  154. MemoryStream stream = new MemoryStream ();
  155. BinaryFormatter bf = new BinaryFormatter ();
  156. bf.Serialize (stream, data);
  157. dataptr = Marshal.AllocHGlobal ((int) stream.Length);
  158. stream.Seek (0, 0);
  159. for (int i = 0; i < stream.Length; i++) {
  160. Marshal.WriteByte (dataptr, i, (byte) stream.ReadByte ());
  161. }
  162. type = (IntPtr) typeMonoSerializedObject;
  163. size = (int) stream.Length;
  164. } else {
  165. dataptr = (IntPtr) GCHandle.Alloc (data);
  166. type = (IntPtr) typeMono;
  167. size = Marshal.SizeOf (typeof (IntPtr));
  168. }
  169. AddDragItemFlavor (dragref, handle, type, ref dataptr, size, 1 << 0);
  170. }
  171. [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  172. static extern int InstallTrackingHandler (DragTrackingDelegate callback, IntPtr window, IntPtr data);
  173. [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  174. static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data);
  175. [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  176. static extern int SetEventParameter (IntPtr eventref, uint name, uint type, uint size, ref bool data);
  177. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  178. extern static int SetControlDragTrackingEnabled (IntPtr view, bool enabled);
  179. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  180. extern static int AddDragItemFlavor (IntPtr dragref, IntPtr itemref, IntPtr flavortype, ref IntPtr data, Int32 size, UInt32 flags);
  181. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  182. extern static int CountDragItems (IntPtr dragref, ref UInt32 count);
  183. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  184. extern static int CountDragItemFlavors (IntPtr dragref, IntPtr itemref, ref UInt32 count);
  185. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  186. extern static int GetDragItemReferenceNumber (IntPtr dragref, UInt32 index, ref IntPtr itemref);
  187. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  188. extern static int NewDrag (ref IntPtr dragref);
  189. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  190. extern static int TrackDrag (IntPtr dragref, ref EventRecord eventrecord, IntPtr region);
  191. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  192. extern static int DisposeDrag (IntPtr dragref);
  193. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  194. extern static int GetDragAllowableActions (IntPtr dragref, ref UInt32 actions);
  195. }
  196. internal struct EventRecord {
  197. internal UInt16 what;
  198. internal UInt32 message;
  199. internal UInt32 when;
  200. internal QDPoint mouse;
  201. internal UInt16 modifiers;
  202. }
  203. internal class FlavorHandler {
  204. internal IntPtr flavorref;
  205. internal IntPtr dragref;
  206. internal IntPtr itemref;
  207. internal Int32 size;
  208. internal UInt32 flags;
  209. internal byte [] data;
  210. internal string fourcc;
  211. internal FlavorHandler (IntPtr dragref, IntPtr itemref, uint counter) {
  212. GetFlavorType (dragref, itemref, counter, ref flavorref);
  213. GetFlavorFlags (dragref, itemref, flavorref, ref flags);
  214. byte [] fourcc_b = BitConverter.GetBytes ((Int32)flavorref);
  215. this.fourcc = String.Format ("{0}{1}{2}{3}", (char)fourcc_b [3], (char)fourcc_b [2], (char)fourcc_b [1], (char)fourcc_b [0]);
  216. this.dragref = dragref;
  217. this.itemref = itemref;
  218. this.GetData ();
  219. }
  220. internal void GetData () {
  221. GetFlavorDataSize (dragref, itemref, flavorref, ref size);
  222. data = new byte [size];
  223. GetFlavorData (dragref, itemref, flavorref, data, ref size, 0);
  224. }
  225. internal string DataString {
  226. get { return Encoding.Default.GetString (this.data); }
  227. }
  228. internal byte[] DataArray {
  229. get { return this.data; }
  230. }
  231. internal IntPtr DataPtr {
  232. get { return (IntPtr) BitConverter.ToInt32 (this.data, 0); }
  233. }
  234. internal bool Supported {
  235. get {
  236. switch (fourcc) {
  237. case "furl":
  238. return true;
  239. case "mono":
  240. return true;
  241. case "mser":
  242. return true;
  243. }
  244. return false;
  245. }
  246. }
  247. internal DataObject Convert (ArrayList flavorlist) {
  248. switch (fourcc) {
  249. case "furl":
  250. return ConvertToFileDrop (flavorlist);
  251. case "mono":
  252. return ConvertToObject (flavorlist);
  253. case "mser":
  254. return DeserializeObject (flavorlist);
  255. }
  256. return new DataObject ();
  257. }
  258. internal DataObject DeserializeObject (ArrayList flavorlist) {
  259. DataObject data = new DataObject ();
  260. MemoryStream stream = new MemoryStream (this.DataArray);
  261. BinaryFormatter bf = new BinaryFormatter ();
  262. if (stream.Length == 0)
  263. return data;
  264. stream.Seek (0, 0);
  265. data.SetData (bf.Deserialize (stream));
  266. return data;
  267. }
  268. internal DataObject ConvertToObject (ArrayList flavorlist) {
  269. DataObject data = new DataObject ();
  270. foreach (FlavorHandler flavor in flavorlist) {
  271. GCHandle handle = (GCHandle) flavor.DataPtr;
  272. data.SetData (handle.Target);
  273. }
  274. return data;
  275. }
  276. internal DataObject ConvertToFileDrop (ArrayList flavorlist) {
  277. DataObject data = new DataObject ();
  278. ArrayList uri_list = new ArrayList ();
  279. foreach (FlavorHandler flavor in flavorlist) {
  280. try {
  281. uri_list.Add (new Uri (flavor.DataString).LocalPath);
  282. } catch { }
  283. }
  284. string [] l = (string []) uri_list.ToArray (typeof (string));
  285. if (l.Length < 1)
  286. return data;
  287. data.SetData (DataFormats.FileDrop, l);
  288. data.SetData ("FileName", l [0]);
  289. data.SetData ("FileNameW", l [0]);
  290. return data;
  291. }
  292. public override string ToString () {
  293. return fourcc;
  294. }
  295. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  296. extern static int GetFlavorDataSize (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref Int32 size);
  297. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  298. extern static int GetFlavorData (IntPtr dragref, IntPtr itemref, IntPtr flavorref, [In, Out] byte[] data, ref Int32 size, UInt32 offset);
  299. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  300. extern static int GetFlavorFlags (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref UInt32 flags);
  301. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  302. extern static int GetFlavorType (IntPtr dragref, IntPtr itemref, UInt32 index, ref IntPtr flavor);
  303. }
  304. }