-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGtk3FileDialog.cs
More file actions
144 lines (118 loc) · 5.58 KB
/
Copy pathGtk3FileDialog.cs
File metadata and controls
144 lines (118 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace NativeFileBrowser
{
public static class Gtk3FileDialog
{
// Steam's runtime does not provide gtk4 (which is nicer), so, use gtk3, which *is* provided by steam
// TODO: Somehow check if this is actually loading Steam's version and not the system one?
private const string So = "libgtk-3.so.0";
[DllImport(So)]
private static extern void gtk_init(IntPtr argc, IntPtr argv);
[DllImport(So)]
private static extern int gtk_main_iteration_do(int blocking);
// gtk_file_chooser_dialog_new is a varargs function, hardcode one set of buttons
[DllImport(So)]
private static extern IntPtr gtk_file_chooser_dialog_new([MarshalAs(UnmanagedType.LPUTF8Str)] string title, IntPtr parent, int action, [MarshalAs(UnmanagedType.LPUTF8Str)] string buttonName, int responseType, IntPtr zero);
[DllImport(So)]
private static extern void gtk_file_chooser_set_select_multiple(IntPtr dialog, int selectMultiple);
[DllImport(So)]
private static extern void gtk_file_chooser_set_current_folder(IntPtr dialog, [MarshalAs(UnmanagedType.LPUTF8Str)] string folder);
[DllImport(So)]
private static extern IntPtr gtk_file_chooser_get_filenames(IntPtr dialog);
[DllImport(So)]
private static extern void gtk_file_chooser_add_filter(IntPtr chooser, IntPtr filter);
[DllImport(So)]
private static extern IntPtr gtk_file_filter_new();
[DllImport(So)]
private static extern void gtk_file_filter_set_name(IntPtr filter, [MarshalAs(UnmanagedType.LPUTF8Str)] string name);
[DllImport(So)]
private static extern void gtk_file_filter_add_pattern(IntPtr filter, [MarshalAs(UnmanagedType.LPUTF8Str)] string pattern);
[DllImport(So)]
private static extern void gtk_file_filter_add_mime_type(IntPtr filter, [MarshalAs(UnmanagedType.LPUTF8Str)] string mimeType);
[DllImport(So)]
private static extern uint g_slist_length(IntPtr list);
[DllImport(So)]
private static extern IntPtr g_slist_nth_data(IntPtr list, uint n);
[DllImport(So)]
private static extern void g_free(IntPtr mem);
[DllImport(So)]
private static extern void g_slist_free(IntPtr mem);
[DllImport(So)]
private static extern int gtk_dialog_run(IntPtr dialog);
[DllImport(So)]
private static extern int gtk_widget_destroy(IntPtr widget);
static Gtk3FileDialog()
{
gtk_init(IntPtr.Zero, IntPtr.Zero);
}
public static string[] Pick(FileBrowserSettings settings)
{
var action = settings.DialogKind == DialogKind.File ? 0 : 2;
const int accept = -3;
var dialog = gtk_file_chooser_dialog_new(settings.Title, IntPtr.Zero, action, "Select", accept, IntPtr.Zero);
if (settings.MultiSelectKind == MultiSelectKind.Multiple)
{
gtk_file_chooser_set_select_multiple(dialog, 1);
}
if (settings.InitialFolder != null)
{
gtk_file_chooser_set_current_folder(dialog, settings.InitialFolder);
}
if (settings.FileExtensionFilters != null)
{
foreach (var filterSetting in settings.FileExtensionFilters)
{
var filter = gtk_file_filter_new();
if (filterSetting.Name != null)
{
var name = filterSetting.Name;
// windows automatically appends the pattern, do the same here
if (filterSetting.Patterns != null)
name += $" ({string.Join(", ", filterSetting.Patterns)})";
gtk_file_filter_set_name(filter, name);
}
if (filterSetting.Patterns != null)
foreach (var pattern in filterSetting.Patterns)
gtk_file_filter_add_pattern(filter, pattern);
if (filterSetting.MimeTypes != null)
foreach (var pattern in filterSetting.MimeTypes)
gtk_file_filter_add_mime_type(filter, pattern);
gtk_file_chooser_add_filter(dialog, filter);
}
}
var res = gtk_dialog_run(dialog);
string[] result;
if (res == accept)
{
var gslist = gtk_file_chooser_get_filenames(dialog);
result = new string[g_slist_length(gslist)];
for (var i = 0u; i < result.Length; i++)
{
var filename = g_slist_nth_data(gslist, i);
result[i] = Marshal.PtrToStringUTF8(filename);
g_free(filename);
}
g_slist_free(gslist);
}
else
{
result = Array.Empty<string>();
}
gtk_widget_destroy(dialog);
// calling main_iteration_do is required to close the window once accepted
UpdateObject.EnsureOpen();
return result;
}
private class UpdateObject : MonoBehaviour
{
private static UpdateObject _instance;
private void Update() => gtk_main_iteration_do(0);
public static void EnsureOpen()
{
if (!_instance) _instance = new GameObject(nameof(Gtk3FileDialog)).AddComponent<UpdateObject>();
}
}
}
}