Gtk#のウィジェットにファイルをドラッグ&ドロップで渡します。
受け取る種類を指定しておくと、ドロップしたときにDragDataReceivedシグナルが発生します。ファイルは "text/uri-list" です。URIで渡されるため、ローカル名に変換が必要です。
using System;
using System.Text;
using Gtk;
class MainClass
{
public static void Main ()
{
Application.Init ();
var win = new Window ("Test DnD") {
DefaultSize = new Gdk.Size (100, 100)
};
win.DeleteEvent += (o, args) => {
Application.Quit ();
args.RetVal = true;
};
var vbox = new VBox (false, 5);
var label = new Label ();
var text = new TextView ();
vbox.Add (label);
vbox.Add (text);
win.Add (vbox);
var targets = new [] {
new TargetEntry ("text/uri-list", TargetFlags.OtherApp, 0)
};
Drag.DestSet (label, DestDefaults.All, targets, Gdk.DragAction.Copy);
Drag.DestSet (text, 0, targets, Gdk.DragAction.Copy);
label.DragDataReceived += HandleDragDataReceived;
text.DragDataReceived += HandleDragDataReceived;
win.ShowAll ();
Application.Run ();
}
static void HandleDragDataReceived (object o, DragDataReceivedArgs args)
{
Console.WriteLine (args.Time);
var uris = Encoding.ASCII.GetString (args.SelectionData.Data)
.Replace ("\r", "").Replace ("\0", "").Trim ().Split ('\n');
foreach (var s in uris) {
var uri = new Uri (s);
if (uri.IsFile)
Console.WriteLine (uri.LocalPath);
}
}
}
注意点
Drag.DestSet() はLabelとTextViewで挙動が異なります。Labelでは2番目の引数にDestDefaults.Allを指定する必要があります。しかしTextViewでDestDefaults.Allを指定するとなぜか2度イベントが通知され、Windowsでは2回目の通知で妙なファイルが渡されます(Xでは1回目と同じ)。そのためゼロを指定しておく必要があります。
【追記】WindowsではLabelにDestDefaults.Dropを指定してもドロップを受け付けますが、Xでははじかれました。
これはC言語からGTK+を直接使用しても同じ結果となりました。GTK+本来の挙動だと思われます。
C言語で同じコードを書いてみると、改めてGtk#が薄いラッパーだと思いました。