mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-07-21 09:18:23 +00:00
Add Xdnd support
This commit is contained in:
parent
c65f1fb7bc
commit
dc2f4fef21
|
@ -52,6 +52,13 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
// X11 has some defined values
|
||||||
|
internal static class Consts
|
||||||
|
{
|
||||||
|
public static readonly IntPtr None = IntPtr.Zero;
|
||||||
|
public static readonly IntPtr CurrentTime = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
#region internal static class API
|
#region internal static class API
|
||||||
|
|
||||||
internal static class API
|
internal static class API
|
||||||
|
|
|
@ -76,6 +76,11 @@ namespace OpenTK.Platform.X11
|
||||||
IntPtr _atom_net_wm_state_maximized_horizontal;
|
IntPtr _atom_net_wm_state_maximized_horizontal;
|
||||||
IntPtr _atom_net_wm_state_maximized_vertical;
|
IntPtr _atom_net_wm_state_maximized_vertical;
|
||||||
|
|
||||||
|
|
||||||
|
IntPtr xdndFormat;
|
||||||
|
long sourceXdndVersion;
|
||||||
|
IntPtr sourceHandler;
|
||||||
|
|
||||||
// Xdnd atoms
|
// Xdnd atoms
|
||||||
IntPtr _atom_xdnd_enter;
|
IntPtr _atom_xdnd_enter;
|
||||||
IntPtr _atom_xdnd_position;
|
IntPtr _atom_xdnd_position;
|
||||||
|
@ -85,6 +90,9 @@ namespace OpenTK.Platform.X11
|
||||||
IntPtr _atom_xdnd_drop;
|
IntPtr _atom_xdnd_drop;
|
||||||
IntPtr _atom_xdnd_finished;
|
IntPtr _atom_xdnd_finished;
|
||||||
IntPtr _atom_xdnd_selection;
|
IntPtr _atom_xdnd_selection;
|
||||||
|
IntPtr _atom_xdnd_leave;
|
||||||
|
|
||||||
|
IntPtr _atom_xdnd_primary;
|
||||||
|
|
||||||
#pragma warning disable 414 // assigned but never used
|
#pragma warning disable 414 // assigned but never used
|
||||||
IntPtr _atom_net_wm_allowed_actions;
|
IntPtr _atom_net_wm_allowed_actions;
|
||||||
|
@ -325,18 +333,33 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
#region Utils
|
#region Utils
|
||||||
|
|
||||||
private void ReadProperty(IntPtr property, IntPtr type, ref IntPtr data, ref IntPtr itemsCount)
|
private void ReadProperty(IntPtr window, IntPtr property, IntPtr type, ref IntPtr data, ref IntPtr itemsCount)
|
||||||
{
|
{
|
||||||
int format;
|
int format;
|
||||||
IntPtr length = new IntPtr(int.MaxValue);
|
IntPtr length = new IntPtr(int.MaxValue);
|
||||||
IntPtr actualType;
|
IntPtr actualType;
|
||||||
IntPtr bytesLeft;
|
IntPtr bytesLeft;
|
||||||
|
|
||||||
Functions.XGetWindowProperty(this.window.Display, this.window.Handle, property, IntPtr.Zero,
|
Functions.XGetWindowProperty(this.window.Display, window, property, IntPtr.Zero,
|
||||||
length, false, type,
|
length, false, type,
|
||||||
out actualType, out format, out itemsCount, out bytesLeft, ref data);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region private void RegisterAtoms()
|
#region private void RegisterAtoms()
|
||||||
|
@ -382,9 +405,12 @@ namespace OpenTK.Platform.X11
|
||||||
_atom_xdnd_type_list = Functions.XInternAtom(window.Display, "XdndTypeList", false);
|
_atom_xdnd_type_list = Functions.XInternAtom(window.Display, "XdndTypeList", false);
|
||||||
_atom_xdnd_action_copy = Functions.XInternAtom(window.Display, "XdndActionCopy", false);
|
_atom_xdnd_action_copy = Functions.XInternAtom(window.Display, "XdndActionCopy", false);
|
||||||
_atom_xdnd_drop = Functions.XInternAtom(window.Display, "XdndDrop", false);
|
_atom_xdnd_drop = Functions.XInternAtom(window.Display, "XdndDrop", false);
|
||||||
_atom_xdnd_finished = Functions.XInternAtom(window.Display, "Xdndfinished", false);
|
_atom_xdnd_finished = Functions.XInternAtom(window.Display, "XdndFinished", false);
|
||||||
_atom_xdnd_selection = Functions.XInternAtom(window.Display, "XdndSelection", 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[]
|
// string[] atom_names = new string[]
|
||||||
// {
|
// {
|
||||||
// //"WM_TITLE",
|
// //"WM_TITLE",
|
||||||
|
@ -835,10 +861,12 @@ namespace OpenTK.Platform.X11
|
||||||
// Process all pending events
|
// Process all pending events
|
||||||
while (Exists && window != null)
|
while (Exists && window != null)
|
||||||
{
|
{
|
||||||
|
//Functions.XNextEvent(window.Display, ref e);
|
||||||
using (new XLock(window.Display))
|
using (new XLock(window.Display))
|
||||||
{
|
{
|
||||||
if (!Functions.XCheckWindowEvent(window.Display, window.Handle, window.EventMask, ref e) &&
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,45 +909,114 @@ namespace OpenTK.Platform.X11
|
||||||
OnClosed(EventArgs.Empty);
|
OnClosed(EventArgs.Empty);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (e.ClientMessageEvent.message_type == _atom_xdnd_enter) {
|
}
|
||||||
|
else if (e.ClientMessageEvent.message_type == _atom_xdnd_enter)
|
||||||
|
{
|
||||||
// Xdnd started
|
// Xdnd started
|
||||||
bool useList = ((e.ClientMessageEvent.ptr2.ToInt64() & 1) == 1);
|
bool useList = ((e.ClientMessageEvent.ptr2.ToInt64() & 1) == 1);
|
||||||
//long source = e.ClientMessageEvent.ptr1.ToInt64();
|
sourceHandler = e.ClientMessageEvent.ptr1;
|
||||||
//long version = e.ClientMessageEvent.ptr2.ToInt64() >> 24;
|
sourceXdndVersion = e.ClientMessageEvent.ptr2.ToInt64() >> 24;
|
||||||
|
|
||||||
IntPtr formats = IntPtr.Zero;
|
IntPtr formats = IntPtr.Zero;
|
||||||
int formatCount;
|
int formatCount;
|
||||||
if (useList) {
|
if (useList)
|
||||||
|
{
|
||||||
IntPtr count = IntPtr.Zero;
|
IntPtr count = IntPtr.Zero;
|
||||||
ReadProperty(_atom_xdnd_type_list, (IntPtr)AtomName.XA_ATOM, ref formats, ref count);
|
ReadProperty(sourceHandler, _atom_xdnd_type_list, (IntPtr)AtomName.XA_ATOM, ref formats, ref count);
|
||||||
formatCount = count.ToInt32();
|
formatCount = count.ToInt32();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Bad code it will save only 1 format
|
||||||
|
formats = Marshal.AllocHGlobal(3 * IntPtr.Size);
|
||||||
Marshal.WriteIntPtr(formats, e.ClientMessageEvent.ptr3);
|
Marshal.WriteIntPtr(formats, e.ClientMessageEvent.ptr3);
|
||||||
Marshal.WriteIntPtr(formats, e.ClientMessageEvent.ptr4);
|
Marshal.WriteIntPtr(formats, IntPtr.Size * 2, e.ClientMessageEvent.ptr4);
|
||||||
Marshal.WriteIntPtr(formats, e.ClientMessageEvent.ptr5);
|
Marshal.WriteIntPtr(formats, IntPtr.Size * 3, e.ClientMessageEvent.ptr5);
|
||||||
formatCount = 3;
|
formatCount = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntPtr atom = IntPtr.Zero;
|
xdndFormat = Consts.None;
|
||||||
for (int i = 0; i < formatCount && atom == IntPtr.Zero; i++) {
|
for (int i = 0; i < formatCount && xdndFormat == Consts.None; ++i)
|
||||||
|
{
|
||||||
IntPtr tempAtom = Marshal.ReadIntPtr(formats, IntPtr.Size * i);
|
IntPtr tempAtom = Marshal.ReadIntPtr(formats, IntPtr.Size * i);
|
||||||
IntPtr atomName = Functions.XGetAtomName(this.window.Display, tempAtom);
|
IntPtr atomName = Functions.XGetAtomName(this.window.Display, tempAtom);
|
||||||
|
|
||||||
string str = Marshal.PtrToStringUni(atomName);
|
string str = Marshal.PtrToStringAnsi(atomName);
|
||||||
if (str == "text/uri-list") {
|
if (str == "text/uri-list")
|
||||||
atom = tempAtom;
|
{
|
||||||
|
xdndFormat = tempAtom;
|
||||||
}
|
}
|
||||||
|
|
||||||
Functions.XFree(atomName);
|
Functions.XFree(atomName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useList && formats != IntPtr.Zero) {
|
if (useList && formats != IntPtr.Zero)
|
||||||
|
{
|
||||||
Functions.XFree(formats);
|
Functions.XFree(formats);
|
||||||
}
|
}
|
||||||
} else if (e.ClientMessageEvent.message_type == _atom_xdnd_position) {
|
else
|
||||||
// Ignore for now it handle position of mouse when d&d happens
|
{
|
||||||
} else if (e.ClientMessageEvent.message_type == _atom_xdnd_drop) {
|
Marshal.FreeHGlobal(formats);
|
||||||
// Ignore for now it handle actual d&d
|
}
|
||||||
|
}
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
|
@ -1088,6 +1185,34 @@ namespace OpenTK.Platform.X11
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XEventName.SelectionNotify:
|
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++)
|
||||||
|
{
|
||||||
|
OnDrop(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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in a new issue