-
-
Notifications
You must be signed in to change notification settings - Fork 77
/
Dialogs.vala
197 lines (162 loc) · 6.24 KB
/
Dialogs.vala
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
* Copyright 2021-2023 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-3.0-or-later
*/
namespace Gala {
[DBus (name = "org.freedesktop.impl.portal.Access")]
public interface AccessPortal : Object {
[DBus (timeout = 2147483647)] // timeout = int.MAX; value got from <limits.h>
public abstract async void access_dialog (
ObjectPath request_path,
string app_id,
string window_handle,
string title,
string sub_title,
string body,
HashTable<string, Variant> options,
out uint response
) throws IOError, DBusError;
}
[DBus (name = "org.freedesktop.impl.portal.Request")]
public interface Request : Object {
public abstract void close () throws DBusError, IOError;
}
public class AccessDialog : Object {
public signal void response (uint response);
public Meta.Window parent { owned get; construct set; }
public string title { get; construct; }
public string body { get; construct; }
public string icon { get; construct; }
public string accept_label { get; set; }
public string deny_label { get; set; }
private const string PANTHEON_PORTAL_NAME = "org.freedesktop.impl.portal.desktop.pantheon";
private const string FDO_PORTAL_PATH = "/org/freedesktop/portal/desktop";
private const string GALA_DIALOG_PATH = "/io/elementary/gala/dialog";
protected static AccessPortal? portal = null;
protected ObjectPath? path = null;
public static void watch_portal () {
Bus.watch_name (BusType.SESSION, PANTHEON_PORTAL_NAME, BusNameWatcherFlags.NONE,
() => {
try {
portal = Bus.get_proxy_sync (BusType.SESSION, PANTHEON_PORTAL_NAME, FDO_PORTAL_PATH);
} catch (Error e) {
warning ("can't reach portal session: %s", e.message);
}
},
() => {
portal = null;
}
);
}
public AccessDialog (string title, string body, string icon) {
Object (title: title, body: body, icon: icon);
}
[Signal (run = "first")]
public virtual signal void show () {
if (portal == null) {
return;
}
path = new ObjectPath (GALA_DIALOG_PATH + "/%i".printf (Random.int_range (0, int.MAX)));
string parent_handler = "";
var app_id = "";
if (parent != null) {
if (parent.get_client_type () == Meta.WindowClientType.X11) {
//TODO: wayland support
parent_handler = "x11:%x".printf ((uint) parent.get_xwindow ());
}
app_id = parent.get_sandboxed_app_id () ?? "";
}
var options = new HashTable<string, Variant> (str_hash, str_equal);
options["grant_label"] = accept_label;
options["deny_label"] = deny_label;
options["icon"] = icon;
if (this is CloseDialog) {
options["destructive"] = true;
}
portal.access_dialog.begin (path, app_id, parent_handler, title, body, "", options, (obj, res) => {
uint ret;
try {
portal.access_dialog.end (res, out ret);
} catch (Error e) {
warning (e.message);
ret = 2;
}
on_response (ret);
path = null;
});
}
public void close () {
try {
Bus.get_proxy_sync<Request> (BusType.SESSION, PANTHEON_PORTAL_NAME, path).close ();
path = null;
} catch (Error e) {
warning (e.message);
}
}
protected virtual void on_response (uint response_id) {
response (response_id);
}
}
public class CloseDialog : AccessDialog, Meta.CloseDialog {
public Meta.Window window {
owned get { return parent; }
construct { parent = value; }
}
public static Gee.Set<CloseDialog> open_dialogs = new Gee.HashSet<CloseDialog> ();
// this function isn't exported in glib.vapi
[CCode (cname = "g_locale_from_utf8")]
extern static string locale_from_utf8 (
string str,
ssize_t len = -1,
out size_t bytes_read = null,
out size_t bytes_wrriten = null,
out Error err = null
);
public CloseDialog (Meta.Window window) {
Object (window: window);
}
~CloseDialog () {
open_dialogs.remove (this);
}
construct {
icon = "computer-fail";
var window_title = locale_from_utf8 (window.title) ?? window.get_sandboxed_app_id ();
if (window_title != null) {
title = _("“%s” is not responding").printf (window_title);
} else {
title = _("Application is not responding");
}
body = _("You may choose to wait a short while for the application to continue, or force it to quit entirely.");
accept_label = _("Force Quit");
deny_label = _("Wait");
open_dialogs.add (this);
}
public override void show () {
if (path != null) {
return;
}
base.show ();
}
public void hide () {
if (path != null) {
close ();
}
}
public void focus () {
window.foreach_transient ((w) => {
if (w.get_role () == "AccessDialog") {
w.activate (w.get_display ().get_current_time ());
return false;
}
return true;
});
}
protected override void on_response (uint response_id) {
if (response_id == 0) {
base.response (Meta.CloseDialogResponse.FORCE_CLOSE);
} else {
base.response (Meta.CloseDialogResponse.WAIT);
}
}
}
}