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)
109 MemoryStream stream = new MemoryStream ();
110 BinaryFormatter bf = new BinaryFormatter ();
112 bf.Serialize (stream, data);
114 IntPtr buffer = Marshal.AllocHGlobal ((int) stream.Length);
117 for (int i = 0; i < stream.Length; i++) {
118 Marshal.WriteByte (buffer, i, (byte) stream.ReadByte ());
121 dnd.SetProperty (ref xevent, buffer, (int) stream.Length);
125 private class HtmlConverter : IDataConverter {
127 public void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent)
129 string text = dnd.GetText (ref xevent, false);
132 data.SetData (DataFormats.Text, text);
133 data.SetData (DataFormats.UnicodeText, text);
136 public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
141 if (xevent.SelectionRequestEvent.target == (int) Atom.XA_STRING) {
142 byte [] bytes = Encoding.ASCII.GetBytes ((string) data);
143 buffer = Marshal.AllocHGlobal (bytes.Length);
145 for (int i = 0; i < len; i++)
146 Marshal.WriteByte (buffer, i, bytes [i]);
148 buffer = Marshal.StringToHGlobalAnsi ((string) data);
150 while (Marshal.ReadByte (buffer, len) != 0)
154 dnd.SetProperty (ref xevent, buffer, len);
156 Marshal.FreeHGlobal (buffer);
160 private class TextConverter : IDataConverter {
162 public void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent)
164 string text = dnd.GetText (ref xevent, true);
167 data.SetData (DataFormats.Text, text);
168 data.SetData (DataFormats.UnicodeText, text);
171 public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
176 if (xevent.SelectionRequestEvent.target == (int) Atom.XA_STRING) {
177 byte [] bytes = Encoding.ASCII.GetBytes ((string) data);
178 buffer = Marshal.AllocHGlobal (bytes.Length);
180 for (int i = 0; i < len; i++)
181 Marshal.WriteByte (buffer, i, bytes [i]);
183 buffer = Marshal.StringToHGlobalAnsi ((string) data);
185 while (Marshal.ReadByte (buffer, len) != 0)
189 dnd.SetProperty (ref xevent, buffer, len);
191 Marshal.FreeHGlobal (buffer);
195 private class UriListConverter : IDataConverter {
197 public void GetData (X11Dnd dnd, DataObject data, ref XEvent xevent)
199 string text = dnd.GetText (ref xevent, false);
203 // TODO: Do this in a loop instead of just splitting
204 ArrayList uri_list = new ArrayList ();
205 string [] lines = text.Split (new char [] { '\r', '\n' });
206 foreach (string line in lines) {
207 // # is a comment line (see RFC 2483)
208 if (line.StartsWith ("#"))
211 Uri uri = new Uri (line);
212 uri_list.Add (uri.LocalPath);
216 string [] l = (string []) uri_list.ToArray (typeof (string));
219 data.SetData (DataFormats.FileDrop, l);
220 data.SetData ("FileName", l [0]);
221 data.SetData ("FileNameW", l [0]);
224 public void SetData (X11Dnd dnd, object data, ref XEvent xevent)
226 string [] uri_list = (string []) data;
227 StringBuilder res = new StringBuilder ();
229 foreach (string uri_str in uri_list) {
230 Uri uri = new Uri (uri_str);
231 res.Append (uri.ToString ());
235 IntPtr buffer = Marshal.StringToHGlobalAnsi ((string) data);
237 while (Marshal.ReadByte (buffer, len) != 0)
240 dnd.SetProperty (ref xevent, buffer, len);
244 private class DragData {
245 public IntPtr Window;
246 public DragState State;
248 public IntPtr [] SupportedTypes;
250 public IntPtr LastWindow;
251 public IntPtr LastTopLevel;
253 public bool WillAccept;
257 State = DragState.None;
259 SupportedTypes = null;
264 private class DropData {
268 // This version seems to be the most common
269 private static readonly uint [] XdndVersion = new uint [] { 4 };
271 private IntPtr display;
272 private DragData drag_data;
274 private IntPtr XdndAware;
275 private IntPtr XdndSelection;
276 private IntPtr XdndEnter;
277 private IntPtr XdndLeave;
278 private IntPtr XdndPosition;
279 private IntPtr XdndDrop;
280 private IntPtr XdndFinished;
281 private IntPtr XdndStatus;
282 private IntPtr XdndTypeList;
283 private IntPtr XdndActionCopy;
284 private IntPtr XdndActionMove;
285 private IntPtr XdndActionLink;
286 private IntPtr XdndActionPrivate;
287 private IntPtr XdndActionList;
288 private IntPtr XdndActionDescription;
289 private IntPtr XdndActionAsk;
293 private int converts_pending;
294 private bool position_recieved;
295 private bool status_sent;
296 private IntPtr target;
297 private IntPtr source;
298 private IntPtr toplevel;
299 private DataObject data;
301 private IntPtr drag_action;
302 private Control control;
303 private int pos_x, pos_y;
304 private DragDropEffects allowed;
305 private DragEventArgs drag_event;
307 public X11Dnd (IntPtr display)
309 this.display = display;
313 public void SetAllowDrop (Hwnd hwnd, bool allow)
315 // if (hwnd.allow_drop == allow)
318 XChangeProperty (display, hwnd.whole_window, XdndAware,
319 (IntPtr) Atom.XA_ATOM, 32,
320 PropertyMode.Replace, XdndVersion, allow ? 1 : 0);
321 // hwnd.allow_drop = allow;
324 public DragDropEffects StartDrag (IntPtr handle, object data,
325 DragDropEffects allowed_effects)
327 drag_data = new DragData ();
328 drag_data.Window = handle;
329 drag_data.State = DragState.Beginning;
331 drag_data.Data = data;
332 drag_data.SupportedTypes = DetermineSupportedTypes (data);
334 // drag_action = ActionFromEffect (allowed_effects);
336 drag_data.LastTopLevel = IntPtr.Zero;
337 return DragDropEffects.Copy;
340 public void HandleButtonRelease (ref XEvent xevent)
343 if (drag_data == null)
346 if (drag_data.State == DragState.Beginning) {
347 state = State.Accepting;
348 } else if (drag_data.State != DragState.None) {
350 if (drag_data.WillAccept) {
351 SendDrop (drag_data.LastTopLevel, xevent.AnyEvent.window,
352 xevent.ButtonEvent.time);
355 XplatUIX11.XUngrabPointer (display, 0);
360 public void HandleMotionNotify (ref XEvent xevent)
362 if (drag_data == null)
365 if (drag_data.State == DragState.Beginning) {
368 drag_data.State = DragState.Dragging;
370 suc = XplatUIX11.XSetSelectionOwner (display, (int) XdndSelection,
372 xevent.ButtonEvent.time);
375 Console.Error.WriteLine ("Could not take ownership of XdndSelection aborting drag.");
380 suc = XGrabPointer (display, xevent.AnyEvent.window,
382 EventMask.ButtonMotionMask |
383 EventMask.PointerMotionMask |
384 EventMask.ButtonPressMask |
385 EventMask.ButtonReleaseMask,
386 GrabMode.GrabModeAsync,
387 GrabMode.GrabModeAsync,
388 IntPtr.Zero, IntPtr.Zero, 0);
391 Console.Error.WriteLine ("Could not grab pointer aborting drag.");
396 drag_data.State = DragState.Dragging;
397 } else if (drag_data.State != DragState.None) {
398 XAllowEvents (display, 1 /* SyncPointer */, IntPtr.Zero);
400 bool dnd_aware = false;
401 IntPtr toplevel = IntPtr.Zero;
402 IntPtr window = XplatUIX11.RootWindowHandle;
408 while (XQueryPointer (display,
411 out x_temp, out y_temp,
412 out xevent.MotionEvent.x,
413 out xevent.MotionEvent.y,
417 dnd_aware = IsWindowDndAware (window);
420 xevent.MotionEvent.x_root = x_temp;
421 xevent.MotionEvent.y_root = y_temp;
425 if (child == IntPtr.Zero)
431 if (window != drag_data.LastWindow && drag_data.State == DragState.Entered) {
432 drag_data.State = DragState.Dragging;
434 // TODO: Send a Leave if this is an MWF window
436 if (toplevel != drag_data.LastTopLevel)
437 SendLeave (drag_data.LastTopLevel, xevent.MotionEvent.window);
440 drag_data.State = DragState.Entered;
441 if (toplevel != drag_data.LastTopLevel) {
442 // Entering a new toplevel window
443 SendEnter (toplevel, drag_data.Window, drag_data.SupportedTypes);
445 // Already in a toplevel window, so send a position
446 IntPtr action = XdndActionCopy;
447 SendPosition (toplevel, drag_data.Window, action,
448 xevent.MotionEvent.x_root,
449 xevent.MotionEvent.y_root,
450 xevent.MotionEvent.time);
453 drag_data.LastTopLevel = toplevel;
454 drag_data.LastWindow = window;
459 private string GetText (IntPtr handle) {
460 string text = String.Empty;
463 textptr = IntPtr.Zero;
465 XFetchName (display, handle, ref textptr);
466 if (textptr != IntPtr.Zero) {
467 text = Marshal.PtrToStringAnsi(textptr);
475 // return true if the event is handled here
476 public bool HandleClientMessage (ref XEvent xevent)
478 // most common so we check it first
479 if (xevent.ClientMessageEvent.message_type == XdndPosition)
480 return Accepting_HandlePositionEvent (ref xevent);
481 if (xevent.ClientMessageEvent.message_type == XdndEnter)
482 return Accepting_HandleEnterEvent (ref xevent);
483 if (xevent.ClientMessageEvent.message_type == XdndDrop)
484 return Accepting_HandleDropEvent (ref xevent);
485 if (xevent.ClientMessageEvent.message_type == XdndLeave)
486 return Accepting_HandleLeaveEvent (ref xevent);
487 if (xevent.ClientMessageEvent.message_type == XdndStatus)
488 return HandleStatusEvent (ref xevent);
493 public bool HandleSelectionNotifyEvent (ref XEvent xevent)
495 if (source != XGetSelectionOwner (display, XdndSelection))
498 MimeHandler handler = FindHandler ((IntPtr) xevent.SelectionEvent.target);
502 data = new DataObject ();
504 handler.Converter.GetData (this, data, ref xevent);
507 if (converts_pending <= 0 && position_recieved)
512 public bool HandleSelectionRequestEvent (ref XEvent xevent)
514 if (xevent.SelectionRequestEvent.selection != (int) XdndSelection)
517 MimeHandler handler = FindHandler ((IntPtr) xevent.SelectionRequestEvent.target);
521 handler.Converter.SetData (this, drag_data.Data, ref xevent);
526 private void SetProperty (ref XEvent xevent, IntPtr data, int length)
528 XEvent sel = new XEvent();
529 sel.SelectionEvent.type = XEventName.SelectionNotify;
530 sel.SelectionEvent.send_event = true;
531 sel.SelectionEvent.display = display;
532 sel.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
533 sel.SelectionEvent.target = xevent.SelectionRequestEvent.target;
534 sel.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
535 sel.SelectionEvent.time = xevent.SelectionRequestEvent.time;
536 sel.SelectionEvent.property = 0;
538 XplatUIX11.XChangeProperty (display, xevent.SelectionRequestEvent.requestor,
539 xevent.SelectionRequestEvent.property,
540 xevent.SelectionRequestEvent.target,
541 8, PropertyMode.Replace, data, length);
542 sel.SelectionEvent.property = xevent.SelectionRequestEvent.property;
544 XSendEvent (display, xevent.SelectionRequestEvent.requestor, false,
545 EventMask.NoEventMask, ref sel);
549 private void Reset ()
555 private void ResetSourceData ()
557 converts_pending = 0;
561 private void ResetTargetData ()
563 position_recieved = false;
567 private bool Accepting_HandleEnterEvent (ref XEvent xevent)
571 source = xevent.ClientMessageEvent.ptr1;
572 toplevel = xevent.AnyEvent.window;
573 target = IntPtr.Zero;
575 ConvertData (ref xevent);
580 private bool Accepting_HandlePositionEvent (ref XEvent xevent)
582 int x = (int) xevent.ClientMessageEvent.ptr3 >> 16;
583 int y = (int) xevent.ClientMessageEvent.ptr3 & 0xFFFF;
585 allowed = EffectFromAction (xevent.ClientMessageEvent.ptr5);
587 IntPtr parent, child, new_child;
588 parent = XplatUIX11.XRootWindow (display, 0);
592 new_child = IntPtr.Zero;
594 if (!XplatUIX11.XTranslateCoordinates (display,
596 out xd, out yd, out new_child))
598 if (new_child == IntPtr.Zero)
603 if (target != child) {
604 // We have moved into a new control
605 // or into a control for the first time
609 Hwnd hwnd = Hwnd.ObjectFromHandle (target);
610 Control c = Control.FromHandle (hwnd.client_window);
614 // if (!c.AllowDrop) {
620 position_recieved = true;
622 if (converts_pending > 0)
628 control.DndOver (drag_event);
634 private void Finish ()
636 if (control != null) {
637 if (drag_event == null) {
639 data = new DataObject ();
640 drag_event = new DragEventArgs (data,
642 allowed, DragDropEffects.None);
644 control.DndLeave (drag_event);
649 private bool Accepting_HandleDropEvent (ref XEvent xevent)
651 if (control != null && drag_event != null) {
652 drag_event = new DragEventArgs (data,
654 allowed, DragDropEffects.None);
655 control.DndDrop (drag_event);
661 private bool Accepting_HandleLeaveEvent (ref XEvent xevent)
663 if (control != null && drag_event != null)
664 control.DndLeave (drag_event);
669 private bool HandleStatusEvent (ref XEvent xevent)
671 if (drag_data.State == DragState.Entered) {
672 // bool want_position = ((int) xevent.ClientMessageEvent.ptr2 & 0x2) != 0;
673 drag_data.WillAccept = ((int) xevent.ClientMessageEvent.ptr2 & 0x1) != 0;
674 // IntPtr action = xevent.ClientMessageEvent.ptr5;
679 private DragDropEffects EffectFromAction (IntPtr action)
681 DragDropEffects allowed = DragDropEffects.None;
682 if (action == XdndActionCopy)
683 allowed = DragDropEffects.Copy;
684 if (action == XdndActionMove)
685 allowed = DragDropEffects.Move;
686 if (action == XdndActionLink)
687 allowed = DragDropEffects.Link;
691 private IntPtr ActionFromEffect (DragDropEffects effect)
693 IntPtr action = IntPtr.Zero;
694 if (effect == DragDropEffects.Copy)
695 action = XdndActionCopy;
696 if (effect == DragDropEffects.Move)
697 action = XdndActionMove;
698 if (effect == DragDropEffects.Link)
699 action = XdndActionLink;
703 private bool ConvertData (ref XEvent xevent)
707 XplatUIX11.XGetSelectionOwner (display, (int) XdndSelection);
709 foreach (IntPtr atom in SourceSupportedList (ref xevent)) {
710 MimeHandler handler = FindHandler (atom);
711 Console.WriteLine ("handler: {0} atom: {1}", handler, atom);
714 XConvertSelection (display, XdndSelection, handler.Type,
715 handler.NonProtocol, toplevel, 0 /* CurrentTime */);
722 private MimeHandler FindHandler (IntPtr atom)
724 if (atom == IntPtr.Zero)
726 foreach (MimeHandler handler in MimeHandlers) {
727 if (handler.Type == atom)
733 private MimeHandler FindHandler (string name)
735 foreach (MimeHandler handler in MimeHandlers) {
736 if (handler.Name == name)
742 private void SendStatus ()
744 DragDropEffects action = drag_event.Effect;
745 XEvent xevent = new XEvent ();
747 xevent.AnyEvent.type = XEventName.ClientMessage;
748 xevent.AnyEvent.display = display;
749 xevent.ClientMessageEvent.window = source;
750 xevent.ClientMessageEvent.message_type = XdndStatus;
751 xevent.ClientMessageEvent.format = 32;
752 xevent.ClientMessageEvent.ptr1 = toplevel;
753 if (drag_event.Effect != DragDropEffects.None)
754 xevent.ClientMessageEvent.ptr2 = (IntPtr) 1;
756 xevent.ClientMessageEvent.ptr5 = ActionFromEffect (action);
757 XSendEvent (display, source, false, 0, ref xevent);
760 private void SendEnterStatus ()
762 drag_event = new DragEventArgs (data, 0, pos_x, pos_y,
763 allowed, DragDropEffects.None);
764 control.DndEnter (drag_event);
766 XEvent xevent = new XEvent ();
768 xevent.AnyEvent.type = XEventName.ClientMessage;
769 xevent.AnyEvent.display = display;
770 xevent.ClientMessageEvent.window = source;
771 xevent.ClientMessageEvent.message_type = XdndStatus;
772 xevent.ClientMessageEvent.format = 32;
773 xevent.ClientMessageEvent.ptr1 = toplevel;
774 if (drag_event.Effect != DragDropEffects.None)
775 xevent.ClientMessageEvent.ptr2 = (IntPtr) 1;
777 xevent.ClientMessageEvent.ptr5 = ActionFromEffect (drag_event.Effect);
778 XSendEvent (display, source, false, 0, ref xevent);
783 private void SendEnter (IntPtr handle, IntPtr from, IntPtr [] supported)
785 XEvent xevent = new XEvent ();
787 xevent.AnyEvent.type = XEventName.ClientMessage;
788 xevent.AnyEvent.display = display;
789 xevent.ClientMessageEvent.window = handle;
790 xevent.ClientMessageEvent.message_type = XdndEnter;
791 xevent.ClientMessageEvent.format = 32;
792 xevent.ClientMessageEvent.ptr1 = from;
794 // (int) xevent.ClientMessageEvent.ptr2 & 0x1)
796 // xevent.ClientMessageEvent.ptr2 = (IntPtr) ptr2;
797 xevent.ClientMessageEvent.ptr2 = IntPtr.Zero;
799 if (supported.Length > 0)
800 xevent.ClientMessageEvent.ptr3 = supported [0];
801 if (supported.Length > 1)
802 xevent.ClientMessageEvent.ptr4 = supported [1];
803 if (supported.Length > 2)
804 xevent.ClientMessageEvent.ptr5 = supported [2];
806 XSendEvent (display, handle, false, 0, ref xevent);
809 private void SendDrop (IntPtr handle, IntPtr from, IntPtr time)
811 XEvent xevent = new XEvent ();
813 xevent.AnyEvent.type = XEventName.ClientMessage;
814 xevent.AnyEvent.display = display;
815 xevent.ClientMessageEvent.window = handle;
816 xevent.ClientMessageEvent.message_type = XdndDrop;
817 xevent.ClientMessageEvent.format = 32;
818 xevent.ClientMessageEvent.ptr1 = from;
819 xevent.ClientMessageEvent.ptr3 = time;
821 XSendEvent (display, handle, false, 0, ref xevent);
824 private void SendPosition (IntPtr handle, IntPtr from, IntPtr action, int x, int y, IntPtr time)
826 XEvent xevent = new XEvent ();
828 xevent.AnyEvent.type = XEventName.ClientMessage;
829 xevent.AnyEvent.display = display;
830 xevent.ClientMessageEvent.window = handle;
831 xevent.ClientMessageEvent.message_type = XdndPosition;
832 xevent.ClientMessageEvent.format = 32;
833 xevent.ClientMessageEvent.ptr1 = from;
834 xevent.ClientMessageEvent.ptr3 = (IntPtr) ((x << 16) | (y & 0xFFFF));
835 xevent.ClientMessageEvent.ptr4 = time;
836 xevent.ClientMessageEvent.ptr5 = action;
838 XSendEvent (display, handle, false, 0, ref xevent);
841 private void SendLeave (IntPtr handle, IntPtr from)
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 = XdndLeave;
849 xevent.ClientMessageEvent.format = 32;
850 xevent.ClientMessageEvent.ptr1 = from;
852 XSendEvent (display, handle, false, 0, ref xevent);
855 private void SendFinished ()
857 XEvent xevent = new XEvent ();
859 xevent.AnyEvent.type = XEventName.ClientMessage;
860 xevent.AnyEvent.display = display;
861 xevent.ClientMessageEvent.window = source;
862 xevent.ClientMessageEvent.message_type = XdndFinished;
863 xevent.ClientMessageEvent.format = 32;
864 xevent.ClientMessageEvent.ptr1 = toplevel;
866 XSendEvent (display, source, false, 0, ref xevent);
869 // There is a somewhat decent amount of overhead
870 // involved in setting up dnd so we do it lazily
871 // as a lot of applications do not even use it.
874 XdndAware = XInternAtom (display, "XdndAware", false);
875 XdndEnter = XInternAtom (display, "XdndEnter", false);
876 XdndLeave = XInternAtom (display, "XdndLeave", false);
877 XdndPosition = XInternAtom (display, "XdndPosition", false);
878 XdndStatus = XInternAtom (display, "XdndStatus", false);
879 XdndDrop = XInternAtom (display, "XdndDrop", false);
880 XdndSelection = XInternAtom (display, "XdndSelection", false);
881 XdndFinished = XInternAtom (display, "XdndFinished", false);
882 XdndTypeList = XInternAtom (display, "XdndTypeList", false);
883 XdndActionCopy = XInternAtom (display, "XdndActionCopy", false);
884 XdndActionMove = XInternAtom (display, "XdndActionMove", false);
885 XdndActionLink = XInternAtom (display, "XdndActionLink", false);
886 XdndActionPrivate = XInternAtom (display, "XdndActionPrivate", false);
887 XdndActionList = XInternAtom (display, "XdndActionList", false);
888 XdndActionDescription = XInternAtom (display, "XdndActionDescription", false);
889 XdndActionAsk = XInternAtom (display, "XdndActionAsk", false);
891 foreach (MimeHandler handler in MimeHandlers) {
892 handler.Type = XInternAtom (display, handler.Name, false);
893 handler.NonProtocol = XInternAtom (display,
894 String.Concat ("MWFNonP+", handler.Name), false);
899 private IntPtr [] SourceSupportedList (ref XEvent xevent)
904 if (((int) xevent.ClientMessageEvent.ptr2 & 0x1) == 0) {
905 res = new IntPtr [3];
906 res [0] = xevent.ClientMessageEvent.ptr3;
907 res [1] = xevent.ClientMessageEvent.ptr4;
908 res [2] = xevent.ClientMessageEvent.ptr5;
911 int format, count, remaining;
912 IntPtr data = IntPtr.Zero;
914 XGetWindowProperty (display, source, XdndTypeList,
915 0, 32, false, (IntPtr) Atom.XA_ATOM,
916 out type, out format, out count,
917 out remaining, out data);
919 res = new IntPtr [count];
920 for (int i = 0; i < count; i++) {
921 res [i] = (IntPtr) Marshal.ReadInt32 (data, i *
922 Marshal.SizeOf (typeof (int)));
931 private string GetText (ref XEvent xevent, bool unicode)
937 StringBuilder builder = new StringBuilder ();
941 IntPtr data = IntPtr.Zero;
943 if (0 != XGetWindowProperty (display,
944 xevent.AnyEvent.window,
945 (IntPtr) xevent.SelectionEvent.property,
947 (IntPtr) Atom.AnyPropertyType, out actual_type,
948 out actual_fmt, out nitems, out bytes_after,
955 builder.Append (Marshal.PtrToStringUni (data));
957 builder.Append (Marshal.PtrToStringAnsi (data));
961 } while (bytes_after > 0);
964 return builder.ToString ();
967 private MemoryStream GetData (ref XEvent xevent)
973 MemoryStream res = new MemoryStream ();
977 IntPtr data = IntPtr.Zero;
979 if (0 != XGetWindowProperty (display,
980 xevent.AnyEvent.window,
981 (IntPtr) xevent.SelectionEvent.property,
983 (IntPtr) Atom.AnyPropertyType, out actual_type,
984 out actual_fmt, out nitems, out bytes_after,
990 for (int i = 0; i < nitems; i++)
991 res.WriteByte (Marshal.ReadByte (data, i * sizeof (byte)));
995 } while (bytes_after > 0);
999 private bool IsWindowDndAware (IntPtr handle)
1002 // Check the version number, we need greater than 3
1004 int format, count, remaining;
1005 IntPtr data = IntPtr.Zero;
1007 XGetWindowProperty (display, handle, XdndAware, 0, 0x8000000, false,
1008 (IntPtr) Atom.XA_ATOM, out actual, out format,
1009 out count, out remaining, out data);
1011 if (actual != (IntPtr) Atom.XA_ATOM || format != 32 ||
1012 count == 0 || data == IntPtr.Zero) {
1013 if (data != IntPtr.Zero)
1018 int version = Marshal.ReadInt32 (data, 0);
1021 Console.Error.WriteLine ("XDND Version too old (" + version + ").");
1026 // First type is actually the XDND version
1029 for (int i = 1; i < count; i++) {
1030 IntPtr type = (IntPtr) Marshal.ReadInt32 (data, i *
1031 Marshal.SizeOf (typeof (int)));
1032 for (int j = 0; j < drag_data.SupportedTypes.Length; j++) {
1033 if (drag_data.SupportedTypes [j] == type) {
1045 private IntPtr [] DetermineSupportedTypes (object data)
1047 ArrayList res = new ArrayList ();
1049 if (data is string) {
1050 MimeHandler handler = FindHandler ("text/plain");
1051 if (handler != null)
1052 res.Add (handler.Type);
1053 }/* else if (data is Bitmap)
1058 if (data is IDataObject) {
1063 if (data is ISerializable) {
1064 MimeHandler handler = FindHandler ("application/x-mono-serialized-object");
1065 if (handler != null)
1066 res.Add (handler.Type);
1069 return (IntPtr []) res.ToArray (typeof (IntPtr));
1072 [DllImport ("libX11")]
1073 private extern static string XGetAtomName (IntPtr display, IntPtr atom);
1075 [DllImport ("libX11")]
1076 private extern static IntPtr XInternAtom (IntPtr display, string atom_name, bool only_if_exists);
1078 [DllImport ("libX11")]
1079 private extern static int XChangeProperty (IntPtr display, IntPtr window, IntPtr property,
1080 IntPtr format, int type, PropertyMode mode, uint [] atoms, int nelements);
1082 [DllImport ("libX11")]
1083 private extern static int XGetWindowProperty (IntPtr display, IntPtr window,
1084 IntPtr atom, int long_offset, int long_length, bool delete,
1085 IntPtr req_type, out IntPtr actual_type, out int actual_format,
1086 out int nitems, out int bytes_after, out IntPtr prop);
1088 [DllImport ("libX11")]
1089 internal extern static int XSendEvent (IntPtr display, IntPtr window,
1090 bool propagate, EventMask event_mask, ref XEvent send_event);
1092 [DllImport ("libX11")]
1093 internal extern static int XConvertSelection (IntPtr display, IntPtr selection,
1094 IntPtr target, IntPtr property, IntPtr requestor, int time);
1096 [DllImport ("libX11")]
1097 internal extern static IntPtr XGetSelectionOwner (IntPtr display, IntPtr selection);
1099 [DllImport ("libX11")]
1100 internal extern static int XGrabPointer (IntPtr display, IntPtr window,
1101 bool owner_events, EventMask event_mask, GrabMode pointer_mode,
1102 GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, uint timestamp);
1104 [DllImport ("libX11")]
1105 internal extern static bool XQueryPointer (IntPtr display, IntPtr window, out IntPtr root,
1106 out IntPtr child, out int root_x, out int root_y, out int win_x,
1107 out int win_y, out int keys_buttons);
1109 [DllImport ("libX11")]
1110 internal extern static int XAllowEvents (IntPtr display, int event_mode, IntPtr time);
1112 [DllImport ("libX11")]
1113 internal extern static int XFree(IntPtr data);
1115 [DllImport ("libX11")]
1116 internal extern static int XFetchName (IntPtr display, IntPtr window, ref IntPtr window_name);