Merge pull request #542 from VPeruS/drag-and-drop

Drag and drop support
This commit is contained in:
varon 2017-07-04 21:40:26 +02:00 committed by GitHub
commit 09bd2d5d10
13 changed files with 440 additions and 10 deletions

View file

@ -279,9 +279,9 @@ namespace OpenTK
//event EventHandler<MouseEventArgs> MouseClick;
//event EventHandler<MouseEventArgs> MouseDoubleClick;
//event EventHandler<DragEventArgs> DragDrop;
//event EventHandler<DragEventArgs> DragEnter;
//event EventHandler<DragEventArgs> DragOver;
//event EventHandler<EventArgs> DragLeave;
/// <summary>
/// Occurs whenever file dropped on window.
/// </summary>
event EventHandler<OpenTK.Input.FileDropEventArgs> FileDrop;
}
}

View file

@ -0,0 +1,22 @@
using System;
namespace OpenTK.Input
{
/// <summary>
/// Defines the event data for <see cref="NativeWindow"/> events.
/// </summary>
public class FileDropEventArgs : EventArgs
{
string fileName;
/// <summary>
/// Gets the name of the file.
/// </summary>
/// <value>The name of the file.</value>
public string FileName
{
get;
internal set;
}
}
}

View file

@ -692,6 +692,11 @@ namespace OpenTK
/// </summary>
public event EventHandler<MouseWheelEventArgs> MouseWheel = delegate { };
/// <summary>
/// Occurs whenever a file dropped on window;
/// </summary>
public event EventHandler<FileDropEventArgs> FileDrop = delegate { };
#endregion
#endregion
@ -964,6 +969,18 @@ namespace OpenTK
MouseWheel(this, e);
}
/// <summary>
/// Raises the <see cref="FileDrop"/> event.
/// </summary>
/// <param name="e">
/// A <see cref="FileDropEventArgs"/> instance carrying file name.
/// The information carried by this instance is only valid within this method body.
/// </param>
protected virtual void OnFileDrop(FileDropEventArgs e)
{
FileDrop(this, e);
}
#region OnResize
/// <summary>
@ -1125,6 +1142,8 @@ namespace OpenTK
private void OnMouseMoveInternal(object sender, MouseMoveEventArgs e) { OnMouseMove(e); }
private void OnMouseWheelInternal(object sender, MouseWheelEventArgs e) { OnMouseWheel(e); }
private void OnFileDropInternal(object sender, FileDropEventArgs e) { OnFileDrop(e); }
#region OnMoveInternal
private void OnMoveInternal(object sender, EventArgs e) { OnMove(e); }
@ -1197,6 +1216,7 @@ namespace OpenTK
implementation.VisibleChanged += OnVisibleChangedInternal;
implementation.WindowBorderChanged += OnWindowBorderChangedInternal;
implementation.WindowStateChanged += OnWindowStateChangedInternal;
implementation.FileDrop += OnFileDropInternal;
events = true;
}
else if (events)
@ -1221,6 +1241,7 @@ namespace OpenTK
implementation.VisibleChanged -= OnVisibleChangedInternal;
implementation.WindowBorderChanged -= OnWindowBorderChangedInternal;
implementation.WindowStateChanged -= OnWindowStateChangedInternal;
implementation.FileDrop -= OnFileDropInternal;
events = false;
}
else

View file

@ -772,8 +772,10 @@
<Compile Include="Platform\Linux\Bindings\Evdev.cs" />
<Compile Include="Platform\Linux\DefaultCursor.cs" />
<Compile Include="Platform\Linux\Bindings\Kms.cs" />
<Compile Include="Input\FileDropEventArgs.cs" />
<None Include="OpenTK.csproj.paket.template" />
<None Include="paket.references" />
<Compile Include="Platform\MacOS\Cocoa\NSDragOperation.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

View file

@ -0,0 +1,23 @@
using System;
namespace OpenTK.Platform.MacOS
{
/// <summary>
/// Used by draggingSourceOperationMask() <see cref="CocoaNativeWindow.DraggingEntered"/> to get permission for dropped object
/// also used for respones to drag source
/// Values for enum can be found here https://developer.apple.com/documentation/appkit/nsdragoperation?language=objc
/// or for Mac users /System/Library/Frameworks/AppKit.framework/Headers
/// </summary>
internal enum NSDragOperation : int
{
None = 0,
Copy = 1,
Link = 2,
Generic = 4,
Private = 8,
AllObsolete = 15,
Move = 16,
Delete = 32,
Every = Int32.MaxValue,
}
}

View file

@ -116,6 +116,7 @@ namespace OpenTK.Platform.MacOS
static readonly IntPtr NSImage;
static readonly IntPtr NSBitmapImageRep;
static readonly IntPtr NSDeviceRGBColorSpace = Cocoa.ToNSString("NSDeviceRGBColorSpace");
static readonly IntPtr NSFilenamesPboardType;
static CocoaNativeWindow()
{
@ -125,6 +126,7 @@ namespace OpenTK.Platform.MacOS
NSCursor = Class.Get("NSCursor");
NSImage = Class.Get("NSImage");
NSBitmapImageRep = Class.Get("NSBitmapImageRep");
NSFilenamesPboardType = Cocoa.GetStringConstant(Cocoa.AppKitLibrary, "NSFilenamesPboardType");
}
private CocoaWindowInfo windowInfo;
@ -165,6 +167,8 @@ namespace OpenTK.Platform.MacOS
CanBecomeKeyWindowHandler = CanBecomeKeyWindow;
CanBecomeMainWindowHandler = CanBecomeMainWindow;
ResetCursorRectsHandler = ResetCursorRects;
PerformDragOperationHandler = PerformDragOperation;
DraggingEnteredHandler = DraggingEntered;
// Create the window class
int unique_id = Interlocked.Increment(ref UniqueId);
@ -182,6 +186,9 @@ namespace OpenTK.Platform.MacOS
Class.RegisterMethod(windowClass, AcceptsFirstResponderHandler, "acceptsFirstResponder", "b@:");
Class.RegisterMethod(windowClass, CanBecomeKeyWindowHandler, "canBecomeKeyWindow", "b@:");
Class.RegisterMethod(windowClass, CanBecomeMainWindowHandler, "canBecomeMainWindow", "b@:");
Class.RegisterMethod(windowClass, DraggingEnteredHandler, "draggingEntered:", "@@:@");
Class.RegisterMethod(windowClass, PerformDragOperationHandler, "performDragOperation:", "b@:@");
Class.RegisterClass(windowClass);
IntPtr viewClass = Class.AllocateClass("OpenTK_NSView" + unique_id, "NSView");
@ -257,6 +264,16 @@ namespace OpenTK.Platform.MacOS
exists = true;
NSApplication.Quit += ApplicationQuit;
// Enable drag and drop
Cocoa.SendIntPtr(
windowPtr,
Selector.Get("registerForDraggedTypes:"),
Cocoa.SendIntPtr(
Class.Get("NSArray"),
Selector.Get("arrayWithObjects:"),
NSFilenamesPboardType,
IntPtr.Zero));
}
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
@ -287,6 +304,10 @@ namespace OpenTK.Platform.MacOS
delegate bool CanBecomeMainWindowDelegate(IntPtr self, IntPtr cmd);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void ResetCursorRectsDelegate(IntPtr self, IntPtr cmd);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate IntPtr DraggingEnteredDelegate(IntPtr self, IntPtr cmd, IntPtr sender);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate bool PerformDragOperationDelegate(IntPtr self, IntPtr cmd, IntPtr sender);
WindowKeyDownDelegate WindowKeyDownHandler;
WindowDidResizeDelegate WindowDidResizeHandler;
@ -302,6 +323,37 @@ namespace OpenTK.Platform.MacOS
CanBecomeKeyWindowDelegate CanBecomeKeyWindowHandler;
CanBecomeMainWindowDelegate CanBecomeMainWindowHandler;
ResetCursorRectsDelegate ResetCursorRectsHandler;
DraggingEnteredDelegate DraggingEnteredHandler;
PerformDragOperationDelegate PerformDragOperationHandler;
private IntPtr DraggingEntered(IntPtr self, IntPtr cmd, IntPtr sender)
{
int mask = Cocoa.SendInt(sender, Selector.Get("draggingSourceOperationMask"));
if ((mask & (int)NSDragOperation.Generic) == (int)NSDragOperation.Generic)
{
return new IntPtr((int)NSDragOperation.Generic);
}
return new IntPtr((int)NSDragOperation.None);
}
private bool PerformDragOperation(IntPtr self, IntPtr cmd, IntPtr sender)
{
IntPtr pboard = Cocoa.SendIntPtr(sender, Selector.Get("draggingPasteboard"));
IntPtr files = Cocoa.SendIntPtr(pboard, Selector.Get("propertyListForType:"), NSFilenamesPboardType);
int count = Cocoa.SendInt(files, Selector.Get("count"));
for (int i = 0; i < count; ++i)
{
IntPtr obj = Cocoa.SendIntPtr(files, Selector.Get("objectAtIndex:"), new IntPtr(i));
IntPtr str = Cocoa.SendIntPtr(obj, Selector.Get("cStringUsingEncoding:"), new IntPtr(1));
OnFileDrop(Marshal.PtrToStringAuto(str));
}
return true;
}
private void WindowKeyDown(IntPtr self, IntPtr cmd, IntPtr notification)
{

View file

@ -49,6 +49,8 @@ namespace OpenTK.Platform
readonly KeyboardKeyEventArgs KeyUpArgs = new KeyboardKeyEventArgs();
readonly KeyPressEventArgs KeyPressArgs = new KeyPressEventArgs((char)0);
readonly FileDropEventArgs FileDropArgs = new FileDropEventArgs();
// In order to simplify mouse event implementation,
// we can store the current mouse state here.
protected MouseState MouseState = new MouseState();
@ -149,6 +151,13 @@ namespace OpenTK.Platform
KeyUp(this, e);
}
protected void OnFileDrop(string s)
{
var e = FileDropArgs;
FileDropArgs.FileName = s;
FileDrop(this, e);
}
/// \internal
/// <summary>
/// Call this method to simulate KeyDown/KeyUp events
@ -311,6 +320,7 @@ namespace OpenTK.Platform
public event EventHandler<MouseButtonEventArgs> MouseUp = delegate { };
public event EventHandler<MouseMoveEventArgs> MouseMove = delegate { };
public event EventHandler<MouseWheelEventArgs> MouseWheel = delegate { };
public event EventHandler<FileDropEventArgs> FileDrop = delegate { };
public abstract void Close();

View file

@ -139,6 +139,10 @@ namespace OpenTK.Platform.SDL2
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_FreeSurface", ExactSpelling = true)]
public static extern void FreeSurface(IntPtr surface);
[SuppressUnmanagedCodeSecurity]
[DllImport (lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_free", ExactSpelling = true)]
public static extern void Free(IntPtr memblock);
#region GameContoller
[SuppressUnmanagedCodeSecurity]
@ -1442,6 +1446,8 @@ namespace OpenTK.Platform.SDL2
public ControllerButtonEvent ControllerButton;
[FieldOffset(0)]
public ControllerDeviceEvent ControllerDevice;
[FieldOffset(0)]
public DropEvent Drop;
#if false
[FieldOffset(0)]
public QuitEvent quit;
@ -1455,8 +1461,6 @@ namespace OpenTK.Platform.SDL2
public MultiGestureEvent mgesture;
[FieldOffset(0)]
public DollarGestureEvent dgesture;
[FieldOffset(0)]
public DropEvent drop;
#endif
// Ensure the structure is big enough
@ -1755,6 +1759,17 @@ namespace OpenTK.Platform.SDL2
public Int32 Data2;
}
/// <summary>
/// Drop event for SDL2 interop. For detailed info look: https://wiki.libsdl.org/SDL_DropEvent
/// </summary>
struct DropEvent
{
public UInt32 Type;
public UInt32 Timestamp;
public IntPtr File;
public UInt32 WindowID;
}
#endregion
}

View file

@ -197,6 +197,15 @@ namespace OpenTK.Platform.SDL2
}
break;
case EventType.DROPFILE:
if (windows.TryGetValue(ev.Drop.WindowID, out window))
{
ProcessDropEvent(window, ev.Drop);
SDL.Free(ev.Drop.File);
processed = true;
}
break;
case EventType.QUIT:
Debug.WriteLine("Sdl2 application quit");
break;
@ -293,6 +302,12 @@ namespace OpenTK.Platform.SDL2
window.OnMouseWheel(ev.X, ev.Y);
}
static unsafe void ProcessDropEvent(Sdl2NativeWindow window, DropEvent ev)
{
string dropString = Marshal.PtrToStringAuto(ev.File);
window.OnFileDrop(dropString);
}
static void ProcessWindowEvent(Sdl2NativeWindow window, WindowEvent e)
{
switch (e.Event)

View file

@ -57,6 +57,8 @@ namespace OpenTK.Platform.Windows
using HKEY = System.IntPtr;
using PHKEY = System.IntPtr;
using HDROP = System.IntPtr;
using LRESULT = System.IntPtr;
using LPVOID = System.IntPtr;
using LPCTSTR = System.String;
@ -134,6 +136,25 @@ namespace OpenTK.Platform.Windows
{
#region Window functions
[DllImport("shell32.dll")]
internal static extern bool DragAcceptFiles(
IntPtr handle,
[MarshalAs(UnmanagedType.Bool)] bool fAccept
);
[DllImport("shell32.dll")]
internal static extern uint DragQueryFile(
HDROP hDrop,
uint iFile,
IntPtr lpszFile,
uint cch
);
[DllImport("shell32.dll")]
internal static extern void DragFinish(
HDROP hDrop
);
#region SetWindowPos
// WINUSERAPI BOOL WINAPI SetWindowPos(__in HWND hWnd, __in_opt HWND hWndInsertAfter,

View file

@ -150,6 +150,7 @@ namespace OpenTK.Platform.Windows
0, 0, ClientSize.Width, ClientSize.Height,
title, options, device, window.Handle),
window);
Functions.DragAcceptFiles(window.Handle, true);
exists = true;
}
@ -680,6 +681,27 @@ namespace OpenTK.Platform.Windows
OnClosed(EventArgs.Empty);
}
void HandleDropFiles(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
IntPtr hDrop = wParam;
uint filesCounter = Functions.DragQueryFile(hDrop, 0xFFFFFFFF, IntPtr.Zero, 0);
for (uint i = 0; i < filesCounter; ++i)
{
// Don't forget about \0 at the end
uint fileNameSize = Functions.DragQueryFile(hDrop, i, IntPtr.Zero, 0) + 1;
IntPtr str = Marshal.AllocHGlobal((int)fileNameSize);
Functions.DragQueryFile(hDrop, i, str, fileNameSize);
string dropString = Marshal.PtrToStringAuto(str);
OnFileDrop(dropString);
Marshal.FreeHGlobal(str);
}
Functions.DragFinish(hDrop);
}
#endregion
#region WindowProcedure
@ -800,6 +822,10 @@ namespace OpenTK.Platform.Windows
HandleKillFocus(handle, message, wParam, lParam);
break;
case WindowMessage.DROPFILES:
HandleDropFiles(handle, message, wParam, lParam);
break;
#endregion
#region Creation / Destruction events

View file

@ -52,6 +52,22 @@ namespace OpenTK.Platform.X11
#endregion
/// <summary>
/// X11 has some defined values they are defined with c's #define in X.h
/// </summary>
internal static class Consts
{
/// <summary>
/// Universal null resource or null atom. From header: #define None 0L
/// </summary>
public static readonly IntPtr None = IntPtr.Zero;
//
/// <summary>
/// Special time value. From header: #define CurrentTime 0L
/// </summary>
public static readonly IntPtr CurrentTime = IntPtr.Zero; //
}
#region internal static class API
internal static class API

View file

@ -76,6 +76,24 @@ namespace OpenTK.Platform.X11
IntPtr _atom_net_wm_state_maximized_horizontal;
IntPtr _atom_net_wm_state_maximized_vertical;
IntPtr xdndFormat;
long sourceXdndVersion;
IntPtr sourceHandler;
// Xdnd atoms
IntPtr _atom_xdnd_enter;
IntPtr _atom_xdnd_position;
IntPtr _atom_xdnd_status;
IntPtr _atom_xdnd_type_list;
IntPtr _atom_xdnd_action_copy;
IntPtr _atom_xdnd_drop;
IntPtr _atom_xdnd_finished;
IntPtr _atom_xdnd_selection;
IntPtr _atom_xdnd_leave;
IntPtr _atom_xdnd_primary;
#pragma warning disable 414 // assigned but never used
IntPtr _atom_net_wm_allowed_actions;
IntPtr _atom_net_wm_action_resize;
@ -264,6 +282,13 @@ namespace OpenTK.Platform.X11
xi2_version = XI2MouseKeyboard.XIVersion;
}
// Alow window recive Xdnd Events
IntPtr xdndAware = Functions.XInternAtom(window.Display, "XdndAware", false);
IntPtr xdndProtocol = new IntPtr(5);
using (new XLock (window.Display)) {
Functions.XChangeProperty(this.window.Display, this.Handle, xdndAware, (IntPtr)AtomName.XA_ATOM, 32, PropertyMode.Replace, ref xdndProtocol, 1);
}
exists = true;
}
@ -306,6 +331,33 @@ namespace OpenTK.Platform.X11
#region Private Members
private void ReadProperty(IntPtr window, IntPtr property, IntPtr type, ref IntPtr data, ref IntPtr itemsCount)
{
int format;
IntPtr length = new IntPtr(int.MaxValue);
IntPtr actualType;
IntPtr bytesLeft;
Functions.XGetWindowProperty(this.window.Display, window, property, IntPtr.Zero,
length, false, type,
out actualType, out format, out itemsCount, out bytesLeft, ref data);
}
private string[] parseUriList(string rawString)
{
string[] separator = new string[] {"\r", "\n"};
string[] splitted = rawString.Split(separator, StringSplitOptions.RemoveEmptyEntries);
string[] fileNames = new string[splitted.Length];
for (int i = 0; i < splitted.Length; i++)
{
// Delete start of name - file://
fileNames[i] = splitted[i].Substring(7);
}
return fileNames;
}
#region private void RegisterAtoms()
/// <summary>
@ -342,6 +394,19 @@ namespace OpenTK.Platform.X11
_atom_net_frame_extents =
Functions.XInternAtom(window.Display, "_NET_FRAME_EXTENTS", false);
// Some Xdnd atoms
_atom_xdnd_enter = Functions.XInternAtom(window.Display, "XdndEnter", false);
_atom_xdnd_position = Functions.XInternAtom(window.Display, "XdndPosition", false);
_atom_xdnd_status = Functions.XInternAtom(window.Display, "XdndStatus", false);
_atom_xdnd_type_list = Functions.XInternAtom(window.Display, "XdndTypeList", false);
_atom_xdnd_action_copy = Functions.XInternAtom(window.Display, "XdndActionCopy", false);
_atom_xdnd_drop = Functions.XInternAtom(window.Display, "XdndDrop", false);
_atom_xdnd_finished = Functions.XInternAtom(window.Display, "XdndFinished", false);
_atom_xdnd_selection = Functions.XInternAtom(window.Display, "XdndSelection", false);
_atom_xdnd_leave = Functions.XInternAtom(window.Display, "XdndLeave", false);
// Selection atoms
_atom_xdnd_primary = Functions.XInternAtom(window.Display, "PRIMARY", false);
// string[] atom_names = new string[]
// {
// //"WM_TITLE",
@ -795,7 +860,8 @@ namespace OpenTK.Platform.X11
using (new XLock(window.Display))
{
if (!Functions.XCheckWindowEvent(window.Display, window.Handle, window.EventMask, ref e) &&
!Functions.XCheckTypedWindowEvent(window.Display, window.Handle, XEventName.ClientMessage, ref e))
!Functions.XCheckTypedWindowEvent(window.Display, window.Handle, XEventName.ClientMessage, ref e) &&
!Functions.XCheckTypedWindowEvent(window.Display, window.Handle, XEventName.SelectionNotify, ref e))
break;
}
@ -839,7 +905,117 @@ namespace OpenTK.Platform.X11
break;
}
}
// For X11 drag and drop handling use https://freedesktop.org/wiki/Specifications/XDND/#index9h2
else if (e.ClientMessageEvent.message_type == _atom_xdnd_enter)
{
// Xdnd started
// ptr1 -> source window handler
// ptr2 bit 0 -> set to 1 if source support more than three data formats
// ptr2 third byte contains Xdnd version that source supports
bool useList = ((e.ClientMessageEvent.ptr2.ToInt64() & 1) == 1);
sourceHandler = e.ClientMessageEvent.ptr1;
sourceXdndVersion = e.ClientMessageEvent.ptr2.ToInt64() >> 24;
IntPtr formats = IntPtr.Zero;
int formatCount;
if (useList)
{
IntPtr count = IntPtr.Zero;
ReadProperty(sourceHandler, _atom_xdnd_type_list, (IntPtr)AtomName.XA_ATOM, ref formats, ref count);
formatCount = count.ToInt32();
}
else
{
formats = Marshal.AllocHGlobal(3 * IntPtr.Size);
Marshal.WriteIntPtr(formats, e.ClientMessageEvent.ptr3);
Marshal.WriteIntPtr(formats, IntPtr.Size * 2, e.ClientMessageEvent.ptr4);
Marshal.WriteIntPtr(formats, IntPtr.Size * 3, e.ClientMessageEvent.ptr5);
formatCount = 3;
}
xdndFormat = Consts.None;
for (int i = 0; i < formatCount && xdndFormat == Consts.None; ++i)
{
IntPtr tempAtom = Marshal.ReadIntPtr(formats, IntPtr.Size * i);
IntPtr atomName = Functions.XGetAtomName(this.window.Display, tempAtom);
string str = Marshal.PtrToStringAnsi(atomName);
if (str == "text/uri-list")
{
xdndFormat = tempAtom;
}
Functions.XFree(atomName);
}
if (useList && formats != IntPtr.Zero)
{
Functions.XFree(formats);
}
else
{
Marshal.FreeHGlobal(formats);
}
}
else if (e.ClientMessageEvent.message_type == _atom_xdnd_position)
{
XEvent reply = new XEvent ();
reply.ClientMessageEvent.type = XEventName.ClientMessage;
reply.ClientMessageEvent.display = this.window.Display;
reply.ClientMessageEvent.window = sourceHandler;
reply.ClientMessageEvent.message_type = _atom_xdnd_status;
reply.ClientMessageEvent.format = 32;
reply.ClientMessageEvent.ptr1 = this.window.Handle;
if (xdndFormat != Consts.None)
{
reply.ClientMessageEvent.ptr2 = (IntPtr)1;
}
else
{
reply.ClientMessageEvent.ptr2 = (IntPtr)0;
}
reply.ClientMessageEvent.ptr3 = (IntPtr)0;
reply.ClientMessageEvent.ptr4 = (IntPtr)0;
reply.ClientMessageEvent.ptr5 = _atom_xdnd_action_copy;
Functions.XSendEvent(this.window.Display, sourceHandler, false, (IntPtr)EventMask.NoEventMask, ref reply);
Functions.XFlush(this.window.Display);
}
else if (e.ClientMessageEvent.message_type == _atom_xdnd_drop)
{
if (xdndFormat == Consts.None)
{
XEvent reply = new XEvent ();
reply.ClientMessageEvent.type = XEventName.ClientMessage;
reply.ClientMessageEvent.display = this.window.Display;
reply.ClientMessageEvent.window = sourceHandler;
reply.ClientMessageEvent.message_type = _atom_xdnd_finished;
reply.ClientMessageEvent.format = 32;
reply.ClientMessageEvent.ptr1 = this.window.Handle;
reply.ClientMessageEvent.ptr2 = (IntPtr)0;
reply.ClientMessageEvent.ptr3 = Consts.None;
Functions.XSendEvent(this.window.Display, sourceHandler, false, (IntPtr)EventMask.NoEventMask, ref reply);
Functions.XFlush(this.window.Display);
}
else
{
if (sourceXdndVersion >= 1)
{
Functions.XConvertSelection(this.window.Display, _atom_xdnd_selection, xdndFormat, _atom_xdnd_primary, this.window.Handle, e.ClientMessageEvent.ptr3);
}
else
{
Functions.XConvertSelection(this.window.Display, _atom_xdnd_selection, xdndFormat, _atom_xdnd_primary, this.window.Handle, Consts.CurrentTime);
}
}
}
else if (e.ClientMessageEvent.message_type == _atom_xdnd_leave)
{
break;
}
break;
case XEventName.DestroyNotify:
@ -1006,6 +1182,37 @@ namespace OpenTK.Platform.X11
//}
break;
case XEventName.SelectionNotify:
if (e.SelectionEvent.property == _atom_xdnd_primary)
{
IntPtr data = IntPtr.Zero;
IntPtr count = IntPtr.Zero;
ReadProperty(e.SelectionEvent.requestor, e.SelectionEvent.property, e.SelectionEvent.target, ref data, ref count);
string rawString = Marshal.PtrToStringAnsi(data);
Functions.XFree(data);
string[] fileNames = parseUriList(rawString);
for (int i = 0; i < fileNames.Length; i++)
{
OnFileDrop(fileNames[i]);
}
XEvent reply = new XEvent ();
reply.ClientMessageEvent.type = XEventName.ClientMessage;
reply.ClientMessageEvent.display = this.window.Display;
reply.ClientMessageEvent.window = sourceHandler;
reply.ClientMessageEvent.message_type = _atom_xdnd_finished;
reply.ClientMessageEvent.format = 32;
reply.ClientMessageEvent.ptr1 = this.window.Handle;
reply.ClientMessageEvent.ptr2 = (IntPtr)1;
reply.ClientMessageEvent.ptr3 = _atom_xdnd_action_copy;
Functions.XSendEvent(this.window.Display, e.ClientMessageEvent.ptr1, false, (IntPtr)EventMask.NoEventMask, ref reply);
}
break;
default:
//Debug.WriteLine(String.Format("{0} event was not handled", e.type));
break;