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) 2005 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
32 using System.Collections;
33 using System.Runtime.Serialization;
34 using System.Runtime.InteropServices;
35 using System.Runtime.Serialization.Formatters.Binary;
37 namespace System.Windows.Forms {
39 internal class X11Dnd {
46 private enum DragState {
53 private interface IDataConverter {
54 void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent);
55 void SetData (X11Dnd dnd, object data, ref XEvent xevent);
58 private delegate void MimeConverter (IntPtr dsp,
59 DataObject data, ref XEvent xevent);
61 private class MimeHandler {
64 public IntPtr NonProtocol;
65 public IDataConverter Converter;
67 public MimeHandler (string name, IDataConverter converter)
70 Converter = converter;
73 public override string ToString ()
75 return "MimeHandler {" + Name + "}";
79 private MimeHandler [] MimeHandlers = {
80 // new MimeHandler ("WCF_DIB"),
81 // new MimeHandler ("image/gif", new MimeConverter (ImageConverter)),
82 // new MimeHandler ("text/rtf", new MimeConverter (RtfConverter)),
83 // new MimeHandler ("text/richtext", new MimeConverter (RtfConverter)),
85 new MimeHandler ("text/plain", new TextConverter ()),
86 new MimeHandler ("text/html", new HtmlConverter ()),
87 new MimeHandler ("text/uri-list", new UriListConverter ()),
88 new MimeHandler ("application/x-mono-serialized-object",
89 new SerializedObjectConverter ())
92 private class SerializedObjectConverter : IDataConverter {
94 public void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent)
96 MemoryStream stream = dnd.GetData (ref xevent);
97 BinaryFormatter bf = new BinaryFormatter ();
99 if (stream.Length == 0)
103 object obj = bf.Deserialize (stream);
107 public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
112 MemoryStream stream = new MemoryStream ();
113 BinaryFormatter bf = new BinaryFormatter ();
115 bf.Serialize (stream, data);
117 IntPtr buffer = Marshal.AllocHGlobal ((int) stream.Length);
120 for (int i = 0; i < stream.Length; i++) {
121 Marshal.WriteByte (buffer, i, (byte) stream.ReadByte ());
124 dnd.SetProperty (ref xevent, buffer, (int) stream.Length);
128 private class HtmlConverter : IDataConverter {
130 public void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent)
132 string text = dnd.GetText (ref xevent, false);
135 data.SetData (DataFormats.Text, text);
136 data.SetData (DataFormats.UnicodeText, text);
139 public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
143 string str = data as string;
148 if (xevent.SelectionRequestEvent.target == (int) Atom.XA_STRING) {
149 byte [] bytes = Encoding.ASCII.GetBytes (str);
150 buffer = Marshal.AllocHGlobal (bytes.Length);
152 for (int i = 0; i < len; i++)
153 Marshal.WriteByte (buffer, i, bytes [i]);
155 buffer = Marshal.StringToHGlobalAnsi (str);
157 while (Marshal.ReadByte (buffer, len) != 0)
161 dnd.SetProperty (ref xevent, buffer, len);
163 Marshal.FreeHGlobal (buffer);
167 private class TextConverter : IDataConverter {
169 public void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent)
171 string text = dnd.GetText (ref xevent, true);
174 data.SetData (DataFormats.Text, text);
175 data.SetData (DataFormats.UnicodeText, text);
178 public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
182 string str = data as string;
187 if (xevent.SelectionRequestEvent.target == (int) Atom.XA_STRING) {
188 byte [] bytes = Encoding.ASCII.GetBytes (str);
189 buffer = Marshal.AllocHGlobal (bytes.Length);
191 for (int i = 0; i < len; i++)
192 Marshal.WriteByte (buffer, i, bytes [i]);
194 buffer = Marshal.StringToHGlobalAnsi (str);
196 while (Marshal.ReadByte (buffer, len) != 0)
200 dnd.SetProperty (ref xevent, buffer, len);
202 Marshal.FreeHGlobal (buffer);
206 private class UriListConverter : IDataConverter {
208 public void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent)
210 string text = dnd.GetText (ref xevent, false);
214 // TODO: Do this in a loop instead of just splitting
215 ArrayList uri_list = new ArrayList ();
216 string [] lines = text.Split (new char [] { '\r', '\n' });
217 foreach (string line in lines) {
218 // # is a comment line (see RFC 2483)
219 if (line.StartsWith ("#"))
222 Uri uri = new Uri (line);
223 uri_list.Add (uri.LocalPath);
227 string [] l = (string []) uri_list.ToArray (typeof (string));
230 data.SetData (DataFormats.FileDrop, l);
231 data.SetData ("FileName", l [0]);
232 data.SetData ("FileNameW", l [0]);
235 public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
237 string [] uri_list = data as string [];
239 if (uri_list == null)
242 StringBuilder res = new StringBuilder ();
243 foreach (string uri_str in uri_list) {
244 Uri uri = new Uri (uri_str);
245 res.Append (uri.ToString ());
249 IntPtr buffer = Marshal.StringToHGlobalAnsi ((string) data);
251 while (Marshal.ReadByte (buffer, len) != 0)
254 dnd.SetProperty (ref xevent, buffer, len);
258 private class DragData {
259 public IntPtr Window;
260 public DragState State;
262 public IntPtr [] SupportedTypes;
264 public IntPtr LastWindow;
265 public IntPtr LastTopLevel;
267 public bool WillAccept;
271 State = DragState.None;
273 SupportedTypes = null;
278 private class DropData {
282 // This version seems to be the most common
283 private static readonly uint [] XdndVersion = new uint [] { 4 };
285 private IntPtr display;
286 private DragData drag_data;
288 private IntPtr XdndAware;
289 private IntPtr XdndSelection;
290 private IntPtr XdndEnter;
291 private IntPtr XdndLeave;
292 private IntPtr XdndPosition;
293 private IntPtr XdndDrop;
294 private IntPtr XdndFinished;
295 private IntPtr XdndStatus;
296 private IntPtr XdndTypeList;
297 private IntPtr XdndActionCopy;
298 private IntPtr XdndActionMove;
299 private IntPtr XdndActionLink;
300 private IntPtr XdndActionPrivate;
301 private IntPtr XdndActionList;
302 private IntPtr XdndActionDescription;
303 private IntPtr XdndActionAsk;
307 private int converts_pending;
308 private bool position_recieved;
309 private bool status_sent;
310 private IntPtr target;
311 private IntPtr source;
312 private IntPtr toplevel;
313 private DataObject data;
315 private IntPtr drag_action;
316 private Control control;
317 private int pos_x, pos_y;
318 private DragDropEffects allowed;
319 private DragEventArgs drag_event;
321 public X11Dnd (IntPtr display)
323 this.display = display;
327 public void SetAllowDrop (Hwnd hwnd, bool allow)
329 if (hwnd.allow_drop == allow)
332 XChangeProperty (display, hwnd.whole_window, XdndAware,
333 (IntPtr) Atom.XA_ATOM, 32,
334 PropertyMode.Replace, XdndVersion, allow ? 1 : 0);
335 hwnd.allow_drop = allow;
338 public DragDropEffects StartDrag (IntPtr handle, object data,
339 DragDropEffects allowed_effects)
341 drag_data = new DragData ();
342 drag_data.Window = handle;
343 drag_data.State = DragState.Beginning;
345 drag_data.Data = data;
346 drag_data.SupportedTypes = DetermineSupportedTypes (data);
348 // drag_action = ActionFromEffect (allowed_effects);
350 drag_data.LastTopLevel = IntPtr.Zero;
351 return DragDropEffects.Copy;
354 public void HandleButtonRelease (ref XEvent xevent)
357 if (drag_data == null)
360 if (drag_data.State == DragState.Beginning) {
361 state = State.Accepting;
362 } else if (drag_data.State != DragState.None) {
364 if (drag_data.WillAccept) {
365 SendDrop (drag_data.LastTopLevel, xevent.AnyEvent.window,
366 xevent.ButtonEvent.time);
369 XplatUIX11.XUngrabPointer (display, 0);
370 drag_data.State = DragState.None;
371 // WE can't reset the drag data yet as it is still
372 // most likely going to be used by the SelectionRequest
377 public void HandleMotionNotify (ref XEvent xevent)
379 if (drag_data == null)
382 if (drag_data.State == DragState.Beginning) {
385 drag_data.State = DragState.Dragging;
387 suc = XplatUIX11.XSetSelectionOwner (display, (int) XdndSelection,
389 xevent.ButtonEvent.time);
392 Console.Error.WriteLine ("Could not take ownership of XdndSelection aborting drag.");
397 suc = XGrabPointer (display, xevent.AnyEvent.window,
399 EventMask.ButtonMotionMask |
400 EventMask.PointerMotionMask |
401 EventMask.ButtonPressMask |
402 EventMask.ButtonReleaseMask,
403 GrabMode.GrabModeAsync,
404 GrabMode.GrabModeAsync,
405 IntPtr.Zero, IntPtr.Zero, 0);
408 Console.Error.WriteLine ("Could not grab pointer aborting drag.");
413 drag_data.State = DragState.Dragging;
414 } else if (drag_data.State != DragState.None) {
415 XAllowEvents (display, 1 /* SyncPointer */, IntPtr.Zero);
417 bool dnd_aware = false;
418 IntPtr toplevel = IntPtr.Zero;
419 IntPtr window = XplatUIX11.RootWindowHandle;
425 while (XQueryPointer (display,
428 out x_temp, out y_temp,
429 out xevent.MotionEvent.x,
430 out xevent.MotionEvent.y,
434 dnd_aware = IsWindowDndAware (window);
437 xevent.MotionEvent.x_root = x_temp;
438 xevent.MotionEvent.y_root = y_temp;
442 if (child == IntPtr.Zero)
448 if (window != drag_data.LastWindow && drag_data.State == DragState.Entered) {
449 drag_data.State = DragState.Dragging;
451 // TODO: Send a Leave if this is an MWF window
453 if (toplevel != drag_data.LastTopLevel)
454 SendLeave (drag_data.LastTopLevel, xevent.MotionEvent.window);
457 drag_data.State = DragState.Entered;
458 if (toplevel != drag_data.LastTopLevel) {
459 // Entering a new toplevel window
460 SendEnter (toplevel, drag_data.Window, drag_data.SupportedTypes);
462 // Already in a toplevel window, so send a position
463 IntPtr action = XdndActionCopy;
464 SendPosition (toplevel, drag_data.Window, action,
465 xevent.MotionEvent.x_root,
466 xevent.MotionEvent.y_root,
467 xevent.MotionEvent.time);
470 drag_data.LastTopLevel = toplevel;
471 drag_data.LastWindow = window;
476 private string GetText (IntPtr handle) {
477 string text = String.Empty;
480 textptr = IntPtr.Zero;
482 XFetchName (display, handle, ref textptr);
483 if (textptr != IntPtr.Zero) {
484 text = Marshal.PtrToStringAnsi(textptr);
492 // return true if the event is handled here
493 public bool HandleClientMessage (ref XEvent xevent)
495 // most common so we check it first
496 if (xevent.ClientMessageEvent.message_type == XdndPosition)
497 return Accepting_HandlePositionEvent (ref xevent);
498 if (xevent.ClientMessageEvent.message_type == XdndEnter)
499 return Accepting_HandleEnterEvent (ref xevent);
500 if (xevent.ClientMessageEvent.message_type == XdndDrop)
501 return Accepting_HandleDropEvent (ref xevent);
502 if (xevent.ClientMessageEvent.message_type == XdndLeave)
503 return Accepting_HandleLeaveEvent (ref xevent);
504 if (xevent.ClientMessageEvent.message_type == XdndStatus)
505 return HandleStatusEvent (ref xevent);
510 public bool HandleSelectionNotifyEvent (ref XEvent xevent)
512 if (source != XGetSelectionOwner (display, XdndSelection))
515 MimeHandler handler = FindHandler ((IntPtr) xevent.SelectionEvent.target);
519 data = new DataObject ();
521 handler.Converter.GetData (this, data, ref xevent);
524 if (converts_pending <= 0 && position_recieved)
529 public bool HandleSelectionRequestEvent (ref XEvent xevent)
531 if (xevent.SelectionRequestEvent.selection != (int) XdndSelection)
534 MimeHandler handler = FindHandler ((IntPtr) xevent.SelectionRequestEvent.target);
538 handler.Converter.SetData (this, drag_data.Data, ref xevent);
543 private void SetProperty (ref XEvent xevent, IntPtr data, int length)
545 XEvent sel = new XEvent();
546 sel.SelectionEvent.type = XEventName.SelectionNotify;
547 sel.SelectionEvent.send_event = true;
548 sel.SelectionEvent.display = display;
549 sel.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
550 sel.SelectionEvent.target = xevent.SelectionRequestEvent.target;
551 sel.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
552 sel.SelectionEvent.time = xevent.SelectionRequestEvent.time;
553 sel.SelectionEvent.property = 0;
555 XplatUIX11.XChangeProperty (display, xevent.SelectionRequestEvent.requestor,
556 xevent.SelectionRequestEvent.property,
557 xevent.SelectionRequestEvent.target,
558 8, PropertyMode.Replace, data, length);
559 sel.SelectionEvent.property = xevent.SelectionRequestEvent.property;
561 XSendEvent (display, xevent.SelectionRequestEvent.requestor, false,
562 EventMask.NoEventMask, ref sel);
566 private void Reset ()
572 private void ResetSourceData ()
574 converts_pending = 0;
578 private void ResetTargetData ()
580 position_recieved = false;
584 private bool Accepting_HandleEnterEvent (ref XEvent xevent)
588 source = xevent.ClientMessageEvent.ptr1;
589 toplevel = xevent.AnyEvent.window;
590 target = IntPtr.Zero;
592 ConvertData (ref xevent);
597 private bool Accepting_HandlePositionEvent (ref XEvent xevent)
599 int x = (int) xevent.ClientMessageEvent.ptr3 >> 16;
600 int y = (int) xevent.ClientMessageEvent.ptr3 & 0xFFFF;
602 allowed = EffectFromAction (xevent.ClientMessageEvent.ptr5);
604 IntPtr parent, child, new_child;
605 parent = XplatUIX11.XRootWindow (display, 0);
609 new_child = IntPtr.Zero;
611 if (!XplatUIX11.XTranslateCoordinates (display,
613 out xd, out yd, out new_child))
615 if (new_child == IntPtr.Zero)
620 if (target != child) {
621 // We have moved into a new control
622 // or into a control for the first time
626 Hwnd hwnd = Hwnd.ObjectFromHandle (target);
627 Control c = Control.FromHandle (hwnd.client_window);
637 position_recieved = true;
639 if (converts_pending > 0)
645 control.DndOver (drag_event);
651 private void Finish ()
653 if (control != null) {
654 if (drag_event == null) {
656 data = new DataObject ();
657 drag_event = new DragEventArgs (data,
659 allowed, DragDropEffects.None);
661 control.DndLeave (drag_event);
666 private bool Accepting_HandleDropEvent (ref XEvent xevent)
668 if (control != null && drag_event != null) {
669 drag_event = new DragEventArgs (data,
671 allowed, DragDropEffects.None);
672 control.DndDrop (drag_event);
678 private bool Accepting_HandleLeaveEvent (ref XEvent xevent)
680 if (control != null && drag_event != null)
681 control.DndLeave (drag_event);
686 private bool HandleStatusEvent (ref XEvent xevent)
688 if (drag_data.State == DragState.Entered) {
689 // bool want_position = ((int) xevent.ClientMessageEvent.ptr2 & 0x2) != 0;
690 drag_data.WillAccept = ((int) xevent.ClientMessageEvent.ptr2 & 0x1) != 0;
691 // IntPtr action = xevent.ClientMessageEvent.ptr5;
696 private DragDropEffects EffectFromAction (IntPtr action)
698 DragDropEffects allowed = DragDropEffects.None;
699 if (action == XdndActionCopy)
700 allowed = DragDropEffects.Copy;
701 if (action == XdndActionMove)
702 allowed = DragDropEffects.Move;
703 if (action == XdndActionLink)
704 allowed = DragDropEffects.Link;
708 private IntPtr ActionFromEffect (DragDropEffects effect)
710 IntPtr action = IntPtr.Zero;
711 if (effect == DragDropEffects.Copy)
712 action = XdndActionCopy;
713 if (effect == DragDropEffects.Move)
714 action = XdndActionMove;
715 if (effect == DragDropEffects.Link)
716 action = XdndActionLink;
720 private bool ConvertData (ref XEvent xevent)
724 XplatUIX11.XGetSelectionOwner (display, (int) XdndSelection);
726 foreach (IntPtr atom in SourceSupportedList (ref xevent)) {
727 MimeHandler handler = FindHandler (atom);
730 XConvertSelection (display, XdndSelection, handler.Type,
731 handler.NonProtocol, toplevel, 0 /* CurrentTime */);
738 private MimeHandler FindHandler (IntPtr atom)
740 if (atom == IntPtr.Zero)
742 foreach (MimeHandler handler in MimeHandlers) {
743 if (handler.Type == atom)
749 private MimeHandler FindHandler (string name)
751 foreach (MimeHandler handler in MimeHandlers) {
752 if (handler.Name == name)
758 private void SendStatus ()
760 DragDropEffects action = drag_event.Effect;
761 XEvent xevent = new XEvent ();
763 xevent.AnyEvent.type = XEventName.ClientMessage;
764 xevent.AnyEvent.display = display;
765 xevent.ClientMessageEvent.window = source;
766 xevent.ClientMessageEvent.message_type = XdndStatus;
767 xevent.ClientMessageEvent.format = 32;
768 xevent.ClientMessageEvent.ptr1 = toplevel;
769 if (drag_event.Effect != DragDropEffects.None)
770 xevent.ClientMessageEvent.ptr2 = (IntPtr) 1;
772 xevent.ClientMessageEvent.ptr5 = ActionFromEffect (action);
773 XSendEvent (display, source, false, 0, ref xevent);
776 private void SendEnterStatus ()
778 drag_event = new DragEventArgs (data, 0, pos_x, pos_y,
779 allowed, DragDropEffects.None);
780 control.DndEnter (drag_event);
782 XEvent xevent = new XEvent ();
784 xevent.AnyEvent.type = XEventName.ClientMessage;
785 xevent.AnyEvent.display = display;
786 xevent.ClientMessageEvent.window = source;
787 xevent.ClientMessageEvent.message_type = XdndStatus;
788 xevent.ClientMessageEvent.format = 32;
789 xevent.ClientMessageEvent.ptr1 = toplevel;
790 if (drag_event.Effect != DragDropEffects.None)
791 xevent.ClientMessageEvent.ptr2 = (IntPtr) 1;
793 xevent.ClientMessageEvent.ptr5 = ActionFromEffect (drag_event.Effect);
794 XSendEvent (display, source, false, 0, ref xevent);
799 private void SendEnter (IntPtr handle, IntPtr from, IntPtr [] supported)
801 XEvent xevent = new XEvent ();
803 xevent.AnyEvent.type = XEventName.ClientMessage;
804 xevent.AnyEvent.display = display;
805 xevent.ClientMessageEvent.window = handle;
806 xevent.ClientMessageEvent.message_type = XdndEnter;
807 xevent.ClientMessageEvent.format = 32;
808 xevent.ClientMessageEvent.ptr1 = from;
810 // (int) xevent.ClientMessageEvent.ptr2 & 0x1)
812 // xevent.ClientMessageEvent.ptr2 = (IntPtr) ptr2;
813 // (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24)
814 xevent.ClientMessageEvent.ptr2 = (IntPtr) (XdndVersion [0] << 24);
816 if (supported.Length > 0)
817 xevent.ClientMessageEvent.ptr3 = supported [0];
818 if (supported.Length > 1)
819 xevent.ClientMessageEvent.ptr4 = supported [1];
820 if (supported.Length > 2)
821 xevent.ClientMessageEvent.ptr5 = supported [2];
823 XSendEvent (display, handle, false, 0, ref xevent);
826 private void SendDrop (IntPtr handle, IntPtr from, IntPtr time)
828 XEvent xevent = new XEvent ();
830 xevent.AnyEvent.type = XEventName.ClientMessage;
831 xevent.AnyEvent.display = display;
832 xevent.ClientMessageEvent.window = handle;
833 xevent.ClientMessageEvent.message_type = XdndDrop;
834 xevent.ClientMessageEvent.format = 32;
835 xevent.ClientMessageEvent.ptr1 = from;
836 xevent.ClientMessageEvent.ptr3 = time;
838 XSendEvent (display, handle, false, 0, ref xevent);
841 private void SendPosition (IntPtr handle, IntPtr from, IntPtr action, int x, int y, IntPtr time)
843 XEvent xevent = new XEvent ();
845 xevent.AnyEvent.type = XEventName.ClientMessage;
846 xevent.AnyEvent.display = display;
847 xevent.ClientMessageEvent.window = handle;
848 xevent.ClientMessageEvent.message_type = XdndPosition;
849 xevent.ClientMessageEvent.format = 32;
850 xevent.ClientMessageEvent.ptr1 = from;
851 xevent.ClientMessageEvent.ptr3 = (IntPtr) ((x << 16) | (y & 0xFFFF));
852 xevent.ClientMessageEvent.ptr4 = time;
853 xevent.ClientMessageEvent.ptr5 = action;
855 XSendEvent (display, handle, false, 0, ref xevent);
858 private void SendLeave (IntPtr handle, IntPtr from)
860 XEvent xevent = new XEvent ();
862 xevent.AnyEvent.type = XEventName.ClientMessage;
863 xevent.AnyEvent.display = display;
864 xevent.ClientMessageEvent.window = handle;
865 xevent.ClientMessageEvent.message_type = XdndLeave;
866 xevent.ClientMessageEvent.format = 32;
867 xevent.ClientMessageEvent.ptr1 = from;
869 XSendEvent (display, handle, false, 0, ref xevent);
872 private void SendFinished ()
874 XEvent xevent = new XEvent ();
876 xevent.AnyEvent.type = XEventName.ClientMessage;
877 xevent.AnyEvent.display = display;
878 xevent.ClientMessageEvent.window = source;
879 xevent.ClientMessageEvent.message_type = XdndFinished;
880 xevent.ClientMessageEvent.format = 32;
881 xevent.ClientMessageEvent.ptr1 = toplevel;
883 XSendEvent (display, source, false, 0, ref xevent);
886 // There is a somewhat decent amount of overhead
887 // involved in setting up dnd so we do it lazily
888 // as a lot of applications do not even use it.
891 XdndAware = XInternAtom (display, "XdndAware", false);
892 XdndEnter = XInternAtom (display, "XdndEnter", false);
893 XdndLeave = XInternAtom (display, "XdndLeave", false);
894 XdndPosition = XInternAtom (display, "XdndPosition", false);
895 XdndStatus = XInternAtom (display, "XdndStatus", false);
896 XdndDrop = XInternAtom (display, "XdndDrop", false);
897 XdndSelection = XInternAtom (display, "XdndSelection", false);
898 XdndFinished = XInternAtom (display, "XdndFinished", false);
899 XdndTypeList = XInternAtom (display, "XdndTypeList", false);
900 XdndActionCopy = XInternAtom (display, "XdndActionCopy", false);
901 XdndActionMove = XInternAtom (display, "XdndActionMove", false);
902 XdndActionLink = XInternAtom (display, "XdndActionLink", false);
903 XdndActionPrivate = XInternAtom (display, "XdndActionPrivate", false);
904 XdndActionList = XInternAtom (display, "XdndActionList", false);
905 XdndActionDescription = XInternAtom (display, "XdndActionDescription", false);
906 XdndActionAsk = XInternAtom (display, "XdndActionAsk", false);
908 foreach (MimeHandler handler in MimeHandlers) {
909 handler.Type = XInternAtom (display, handler.Name, false);
910 handler.NonProtocol = XInternAtom (display,
911 String.Concat ("MWFNonP+", handler.Name), false);
916 private IntPtr [] SourceSupportedList (ref XEvent xevent)
921 if (((int) xevent.ClientMessageEvent.ptr2 & 0x1) == 0) {
922 res = new IntPtr [3];
923 res [0] = xevent.ClientMessageEvent.ptr3;
924 res [1] = xevent.ClientMessageEvent.ptr4;
925 res [2] = xevent.ClientMessageEvent.ptr5;
928 int format, count, remaining;
929 IntPtr data = IntPtr.Zero;
931 XGetWindowProperty (display, source, XdndTypeList,
932 0, 32, false, (IntPtr) Atom.XA_ATOM,
933 out type, out format, out count,
934 out remaining, out data);
936 res = new IntPtr [count];
937 for (int i = 0; i < count; i++) {
938 res [i] = (IntPtr) Marshal.ReadInt32 (data, i *
939 Marshal.SizeOf (typeof (int)));
948 private string GetText (ref XEvent xevent, bool unicode)
954 StringBuilder builder = new StringBuilder ();
958 IntPtr data = IntPtr.Zero;
960 if (0 != XGetWindowProperty (display,
961 xevent.AnyEvent.window,
962 (IntPtr) xevent.SelectionEvent.property,
964 (IntPtr) Atom.AnyPropertyType, out actual_type,
965 out actual_fmt, out nitems, out bytes_after,
972 builder.Append (Marshal.PtrToStringUni (data));
974 builder.Append (Marshal.PtrToStringAnsi (data));
978 } while (bytes_after > 0);
981 return builder.ToString ();
984 private MemoryStream GetData (ref XEvent xevent)
990 MemoryStream res = new MemoryStream ();
994 IntPtr data = IntPtr.Zero;
996 if (0 != XGetWindowProperty (display,
997 xevent.AnyEvent.window,
998 (IntPtr) xevent.SelectionEvent.property,
1000 (IntPtr) Atom.AnyPropertyType, out actual_type,
1001 out actual_fmt, out nitems, out bytes_after,
1007 for (int i = 0; i < nitems; i++)
1008 res.WriteByte (Marshal.ReadByte (data, i));
1012 } while (bytes_after > 0);
1016 private bool IsWindowDndAware (IntPtr handle)
1019 // Check the version number, we need greater than 3
1021 int format, count, remaining;
1022 IntPtr data = IntPtr.Zero;
1024 XGetWindowProperty (display, handle, XdndAware, 0, 0x8000000, false,
1025 (IntPtr) Atom.XA_ATOM, out actual, out format,
1026 out count, out remaining, out data);
1028 if (actual != (IntPtr) Atom.XA_ATOM || format != 32 ||
1029 count == 0 || data == IntPtr.Zero) {
1030 if (data != IntPtr.Zero)
1035 int version = Marshal.ReadInt32 (data, 0);
1038 Console.Error.WriteLine ("XDND Version too old (" + version + ").");
1043 // First type is actually the XDND version
1046 for (int i = 1; i < count; i++) {
1047 IntPtr type = (IntPtr) Marshal.ReadInt32 (data, i *
1048 Marshal.SizeOf (typeof (int)));
1049 for (int j = 0; j < drag_data.SupportedTypes.Length; j++) {
1050 if (drag_data.SupportedTypes [j] == type) {
1062 private IntPtr [] DetermineSupportedTypes (object data)
1064 ArrayList res = new ArrayList ();
1066 if (data is string) {
1067 MimeHandler handler = FindHandler ("text/plain");
1068 if (handler != null)
1069 res.Add (handler.Type);
1070 }/* else if (data is Bitmap)
1075 if (data is IDataObject) {
1080 if (data is ISerializable) {
1081 MimeHandler handler = FindHandler ("application/x-mono-serialized-object");
1082 if (handler != null)
1083 res.Add (handler.Type);
1086 return (IntPtr []) res.ToArray (typeof (IntPtr));
1089 [DllImport ("libX11")]
1090 private extern static string XGetAtomName (IntPtr display, IntPtr atom);
1092 [DllImport ("libX11")]
1093 private extern static IntPtr XInternAtom (IntPtr display, string atom_name, bool only_if_exists);
1095 [DllImport ("libX11")]
1096 private extern static int XChangeProperty (IntPtr display, IntPtr window, IntPtr property,
1097 IntPtr format, int type, PropertyMode mode, uint [] atoms, int nelements);
1099 [DllImport ("libX11")]
1100 private extern static int XGetWindowProperty (IntPtr display, IntPtr window,
1101 IntPtr atom, int long_offset, int long_length, bool delete,
1102 IntPtr req_type, out IntPtr actual_type, out int actual_format,
1103 out int nitems, out int bytes_after, out IntPtr prop);
1105 [DllImport ("libX11")]
1106 internal extern static int XSendEvent (IntPtr display, IntPtr window,
1107 bool propagate, EventMask event_mask, ref XEvent send_event);
1109 [DllImport ("libX11")]
1110 internal extern static int XConvertSelection (IntPtr display, IntPtr selection,
1111 IntPtr target, IntPtr property, IntPtr requestor, int time);
1113 [DllImport ("libX11")]
1114 internal extern static IntPtr XGetSelectionOwner (IntPtr display, IntPtr selection);
1116 [DllImport ("libX11")]
1117 internal extern static int XGrabPointer (IntPtr display, IntPtr window,
1118 bool owner_events, EventMask event_mask, GrabMode pointer_mode,
1119 GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, uint timestamp);
1121 [DllImport ("libX11")]
1122 internal extern static bool XQueryPointer (IntPtr display, IntPtr window, out IntPtr root,
1123 out IntPtr child, out int root_x, out int root_y, out int win_x,
1124 out int win_y, out int keys_buttons);
1126 [DllImport ("libX11")]
1127 internal extern static int XAllowEvents (IntPtr display, int event_mode, IntPtr time);
1129 [DllImport ("libX11")]
1130 internal extern static int XFree(IntPtr data);
1132 [DllImport ("libX11")]
1133 internal extern static int XFetchName (IntPtr display, IntPtr window, ref IntPtr window_name);