-
Notifications
You must be signed in to change notification settings - Fork 43
/
controlCenter.js
304 lines (269 loc) · 9.82 KB
/
controlCenter.js
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
// -*- mode: js; js-indent-level: 2; indent-tabs-mode: nil -*-
/* ------------------------------------------------------------------------- */
'use strict';
/* ------------------------------------------------------------------------- */
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
/* ------------------------------------------------------------------------- */
class GnomeControlCenterError extends Error {}
/* ------------------------------------------------------------------------- */
class SearchProviderConfiguration {
/* ....................................................................... */
constructor(desktopId, dbusName, dbusPath, providerApiVersion, autoStart) {
this.desktopId = desktopId;
this.dbusName = dbusName;
this.dbusPath = dbusPath;
this.providerApiVersion = providerApiVersion;
this.autoStart = autoStart;
}
}
let panelAppIDs = [];
// RemoteSearch doesn't export this anymore, so copied from there
const SearchProvider2Iface = `
<node>
<interface name="org.gnome.Shell.SearchProvider2">
<method name="GetInitialResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetSubsearchResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetResultMetas">
<arg type="as" direction="in" />
<arg type="aa{sv}" direction="out" />
</method>
<method name="ActivateResult">
<arg type="s" direction="in" />
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
<method name="LaunchSearch">
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
</interface>
</node>`;
const SearchProvider2ProxyInfo = Gio.DBusInterfaceInfo.new_for_xml(SearchProvider2Iface);
/* ------------------------------------------------------------------------- */
export var GnomeControlCenter = class GnomeControlCenter {
/* ....................................................................... */
// class constant for dbus time in milliseconds
/// (it's 2019 and ES does not support basic 'const', terrible)
get DBUS_PROXY_TIMEOUT() {
return 800;
}
/* ....................................................................... */
constructor() {
// "declare" instance variables ... so we know we what we use
this._providerConfiguration = null;
this._proxy = null;
// if successfull loaded search provider configuration then create proxy
try {
this._providerConfiguration = this._loadSearchProvider();
try {
this._proxy = this._createProxy();
} catch (error) {
this._proxy = null;
log(error.toString());
}
} catch (error) {
log(error.toString());
}
}
/* ....................................................................... */
get mainApplicationId() {
if (this._providerConfiguration !== null) {
return this._providerConfiguration.desktopId;
} else {
return '';
}
}
initPanelAppIDs() {
this._proxy && this._proxy.GetInitialResultSetRemote([], (results, error) => {
if (error) {
log('Switcher got an error getting settings panels', String(error));
return;
}
const panelIDs = results[0];
// get the panel metas with information about panels
this._proxy.GetResultMetasRemote(panelIDs, combine);
});
function combine(results, error) {
if (error) {
log(
'Switcher got an error getting settings panels details',
String(error)
);
return;
}
const panelMetas = results[0];
// get app id names from panel meta information
panelAppIDs = panelMetas.map((panelMeta) =>
panelMeta['id'].deep_unpack()
);
}
}
/* ....................................................................... */
getPanelAppIDs() {
return panelAppIDs;
}
/* ....................................................................... */
_getSearchProviderConigurationFilePath() {
let filePath;
let dataDirs;
let errorMessage;
// get list of data dirs (i.e. /usr/share)
dataDirs = GLib.get_system_data_dirs();
// prepent user director ~/.local/share
dataDirs.unshift(GLib.get_user_data_dir());
// go over all the data dirs, look for gnome search config file assign it's
// path to filePath if found. preseed filePath to null so we know later
// if no path has been found
filePath = null;
for (let i = 0; i < dataDirs.length; i++) {
// build file path for gnome-control search provider
let possibleFilePath = GLib.build_filenamev([
dataDirs[i],
'gnome-shell',
'search-providers',
'org.gnome.Settings.search-provider.ini'
]);
// check if the file exists and if so stop the search
if (GLib.file_test(possibleFilePath, GLib.FileTest.EXISTS) === true) {
filePath = possibleFilePath;
break;
}
}
if (filePath === null) {
errorMessage =
'' +
'Could not find Gnome Control center search provider configuration' +
' file in any system or user data directories: ' +
dataDirs.join(' ');
throw new GnomeControlCenterError(errorMessage);
}
return filePath;
}
/* ....................................................................... */
_loadSearchProvider() {
let configFilePath;
let keyFile;
let group;
let errorMessage;
let desktopId;
let dbusName;
let dbusPath;
let providerApiVersion;
let autoStart;
try {
// get the configuration file path
configFilePath = this._getSearchProviderConigurationFilePath();
try {
// load key-value-file from passed in configFilePath
keyFile = new GLib.KeyFile();
keyFile.load_from_file(configFilePath, 0);
// if keyfile has the search providers group section
group = 'Shell Search Provider';
if (keyFile.has_group(group) === true) {
try {
// get the desktop id for the gnome search provider
desktopId = keyFile.get_string(group, 'DesktopId');
// get search provider dbus bus name
dbusName = keyFile.get_string(group, 'BusName');
// get search provider dbus object path
dbusPath = keyFile.get_string(group, 'ObjectPath');
// get the version for the dbus interface used for search provider
providerApiVersion = keyFile.get_integer(group, 'Version');
// get the autostart setting for the dbus services
// it's possible gnome control center does not have it specified
// though so we fallback to autoStart set to true
try {
autoStart = keyFile.get_boolean(group, 'AutoStart');
} catch (error) {
autoStart = true;
}
} catch (error) {
errorMessage =
'' +
'Failed to retrive desktop id and DBus configuration from ' +
"search provider configuation file '%s': %s".format(
configFilePath,
error.toString()
);
throw new GnomeControlCenterError(errorMessage);
}
} else {
errorMessage =
'' +
"Loaded search provider configuration file '%s' does not " +
"contain '%s' configuration group".format(configFilePath, group);
throw new GnomeControlCenterError(errorMessage);
}
} catch (error) {
errorMessage =
'' +
"Failed to load search provider configuration file '%s':" +
' %s'.format(configFilePath);
throw new GnomeControlCenterError(error);
}
} catch (error) {
// re-throw error from _getSearchProviderConigurationFilePath
throw error;
}
return new SearchProviderConfiguration(
desktopId,
dbusName,
dbusPath,
providerApiVersion,
autoStart
);
}
/* ...................................................................... */
_createProxy() {
// TODO: need a lot more arror handling
let proxy;
let proxyInfo;
let g_flags;
let errorMessage;
// TODO: these were copied from remoteSearch.js, still need to comment
// as ti why we are doing this
g_flags = Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES;
if (this._providerConfiguration.autoStart === true) {
g_flags |= Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION;
} else {
g_flags |= Gio.DBusProxyFlags.DO_NOT_AUTO_START;
}
// load the dbus interface for the search provider
proxyInfo = SearchProvider2ProxyInfo;
// create dbus proxy
try {
proxy = new Gio.DBusProxy({
g_bus_type: Gio.BusType.SESSION,
g_name: this._providerConfiguration.dbusName,
g_object_path: this._providerConfiguration.dbusPath,
g_interface_info: proxyInfo,
g_interface_name: proxyInfo.name,
g_flags: g_flags
});
// initialize the proxy synchronously (basically blocking). this
// technically could be a problem if it blocks forever, though we expect
// the time out to handle it. Asynchronous initialization is conceptually
// more user friendly by being non-blocking however since switch other
// code is not currently async (desktop item scanning) this is necessary
// initialize dbus object with null for Cancelable, which means we can
// cancel it right now which should be fine since we do non-async calls
// to the dbus with timeout
proxy.init(null);
} catch (error) {
errorMessage =
'' +
'Failed to connect to Gnome Control Search Provider Dbus ' +
'service: %s'.format(error.toString());
throw new GnomeControlCenterError(errorMessage);
}
return proxy;
}
};