Line |
Branch |
Exec |
Source |
1 |
|
|
/* cc-applications-panel.c |
2 |
|
|
* |
3 |
|
|
* Copyright 2018 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> |
4 |
|
|
* |
5 |
|
|
* This program is free software: you can redistribute it and/or modify |
6 |
|
|
* it under the terms of the GNU General Public License as published by |
7 |
|
|
* the Free Software Foundation, either version 3 of the License, or |
8 |
|
|
* (at your option) any later version. |
9 |
|
|
* |
10 |
|
|
* This program is distributed in the hope that it will be useful, |
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
* GNU General Public License for more details. |
14 |
|
|
* |
15 |
|
|
* You should have received a copy of the GNU General Public License |
16 |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 |
|
|
* |
18 |
|
|
* SPDX-License-Identifier: GPL-3.0-or-later |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
#undef G_LOG_DOMAIN |
22 |
|
|
#define G_LOG_DOMAIN "cc-applications-panel" |
23 |
|
|
|
24 |
|
|
#include <config.h> |
25 |
|
|
#include <glib/gi18n.h> |
26 |
|
|
#ifdef HAVE_MALCONTENT |
27 |
|
|
#include <libmalcontent/malcontent.h> |
28 |
|
|
#endif |
29 |
|
|
|
30 |
|
|
#include <gio/gdesktopappinfo.h> |
31 |
|
|
|
32 |
|
|
#include "cc-applications-panel.h" |
33 |
|
|
#include "cc-applications-row.h" |
34 |
|
|
#include "cc-info-row.h" |
35 |
|
|
#include "cc-list-row.h" |
36 |
|
|
#include "cc-default-apps-page.h" |
37 |
|
|
#include "cc-removable-media-settings.h" |
38 |
|
|
#include "cc-applications-resources.h" |
39 |
|
|
#ifdef HAVE_SNAP |
40 |
|
|
#include "cc-snapd-client.h" |
41 |
|
|
#include "cc-snap-row.h" |
42 |
|
|
#endif |
43 |
|
|
#include "cc-util.h" |
44 |
|
|
#include "globs.h" |
45 |
|
|
#include "search.h" |
46 |
|
|
#include "utils.h" |
47 |
|
|
|
48 |
|
|
#define MASTER_SCHEMA "org.gnome.desktop.notifications" |
49 |
|
|
#define APP_SCHEMA MASTER_SCHEMA ".application" |
50 |
|
|
#define APP_PREFIX "/org/gnome/desktop/notifications/application/" |
51 |
|
|
|
52 |
|
|
#define PORTAL_SNAP_PREFIX "snap." |
53 |
|
|
|
54 |
|
|
struct _CcApplicationsPanel |
55 |
|
|
{ |
56 |
|
|
CcPanel parent; |
57 |
|
|
|
58 |
|
|
CcDefaultAppsPage *default_apps_page; |
59 |
|
|
AdwSwitchRow *autorun_never_row; |
60 |
|
|
CcRemovableMediaSettings *removable_media_settings; |
61 |
|
|
|
62 |
|
|
AdwNavigationView *navigation_view; |
63 |
|
|
AdwNavigationPage *app_settings_page; |
64 |
|
|
GtkListBox *app_listbox; |
65 |
|
|
GtkEntry *app_search_entry; |
66 |
|
|
GtkWidget *no_apps_page; |
67 |
|
|
GtkStack *app_listbox_stack; |
68 |
|
|
GAppInfoMonitor *monitor; |
69 |
|
|
gulong monitor_id; |
70 |
|
|
GListModel *app_model; |
71 |
|
|
GListModel *filter_model; |
72 |
|
|
GtkFilter *filter; |
73 |
|
|
#ifdef HAVE_MALCONTENT |
74 |
|
|
GCancellable *cancellable; |
75 |
|
|
|
76 |
|
|
MctAppFilter *app_filter; |
77 |
|
|
MctManager *manager; |
78 |
|
|
guint app_filter_id; |
79 |
|
|
#endif |
80 |
|
|
|
81 |
|
|
gchar *current_app_id; |
82 |
|
|
GAppInfo *current_app_info; |
83 |
|
|
gchar *current_portal_app_id; |
84 |
|
|
|
85 |
|
|
GHashTable *globs; |
86 |
|
|
GHashTable *search_providers; |
87 |
|
|
|
88 |
|
|
GtkImage *app_icon_image; |
89 |
|
|
GtkLabel *app_name_label; |
90 |
|
|
GtkButton *launch_button; |
91 |
|
|
GtkButton *view_details_button; |
92 |
|
|
AdwBanner *sandbox_banner; |
93 |
|
|
GtkWidget *sandbox_info_button; |
94 |
|
|
|
95 |
|
|
GDBusProxy *perm_store; |
96 |
|
|
GSettings *media_handling_settings; |
97 |
|
|
GtkListBoxRow *perm_store_pending_row; |
98 |
|
|
GSettings *notification_settings; |
99 |
|
|
GSettings *location_settings; |
100 |
|
|
GSettings *privacy_settings; |
101 |
|
|
GSettings *search_settings; |
102 |
|
|
|
103 |
|
|
GtkButton *install_button; |
104 |
|
|
|
105 |
|
|
AdwPreferencesGroup *integration_section; |
106 |
|
|
AdwSwitchRow *notification; |
107 |
|
|
AdwSwitchRow *background; |
108 |
|
|
AdwSwitchRow *wallpaper; |
109 |
|
|
AdwSwitchRow *screenshot; |
110 |
|
|
AdwSwitchRow *sound; |
111 |
|
|
CcInfoRow *no_sound; |
112 |
|
|
AdwSwitchRow *search; |
113 |
|
|
CcInfoRow *no_search; |
114 |
|
|
AdwSwitchRow *camera; |
115 |
|
|
CcInfoRow *no_camera; |
116 |
|
|
AdwSwitchRow *location; |
117 |
|
|
CcInfoRow *no_location; |
118 |
|
|
AdwSwitchRow *shortcuts; |
119 |
|
|
AdwSwitchRow *microphone; |
120 |
|
|
CcInfoRow *no_microphone; |
121 |
|
|
AdwPreferencesGroup *other_permissions_section; |
122 |
|
|
CcListRow *builtin; |
123 |
|
|
AdwDialog *builtin_dialog; |
124 |
|
|
AdwPreferencesPage *builtin_page; |
125 |
|
|
GtkListBox *builtin_list; |
126 |
|
|
GList *snap_permission_rows; |
127 |
|
|
|
128 |
|
|
GtkButton *handler_reset; |
129 |
|
|
AdwDialog *handler_dialog; |
130 |
|
|
AdwPreferencesPage *handler_page; |
131 |
|
|
CcListRow *handler_row; |
132 |
|
|
AdwPreferencesGroup *handler_file_group; |
133 |
|
|
AdwPreferencesGroup *handler_link_group; |
134 |
|
|
GList *file_handler_rows; |
135 |
|
|
GList *link_handler_rows; |
136 |
|
|
|
137 |
|
|
GtkWidget *usage_section; |
138 |
|
|
CcListRow *storage; |
139 |
|
|
AdwDialog *storage_dialog; |
140 |
|
|
CcInfoRow *app; |
141 |
|
|
CcInfoRow *data; |
142 |
|
|
CcInfoRow *cache; |
143 |
|
|
CcInfoRow *total; |
144 |
|
|
GtkButton *clear_cache_button; |
145 |
|
|
|
146 |
|
|
guint64 app_size; |
147 |
|
|
guint64 cache_size; |
148 |
|
|
guint64 data_size; |
149 |
|
|
}; |
150 |
|
|
|
151 |
|
|
static void select_app (CcApplicationsPanel *self, |
152 |
|
|
const gchar *app_id, |
153 |
|
|
gboolean emit_activate); |
154 |
|
|
|
155 |
|
|
static void update_handler_dialog (CcApplicationsPanel *self, GAppInfo *info); |
156 |
|
|
|
157 |
|
✗ |
G_DEFINE_TYPE (CcApplicationsPanel, cc_applications_panel, CC_TYPE_PANEL) |
158 |
|
|
|
159 |
|
|
enum |
160 |
|
|
{ |
161 |
|
|
PROP_0, |
162 |
|
|
PROP_PARAMETERS |
163 |
|
|
}; |
164 |
|
|
|
165 |
|
|
static gboolean |
166 |
|
✗ |
gnome_software_is_installed (void) |
167 |
|
|
{ |
168 |
|
✗ |
g_autofree gchar *path = g_find_program_in_path ("gnome-software"); |
169 |
|
✗ |
return path != NULL; |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
/* Callbacks */ |
173 |
|
|
|
174 |
|
|
static gboolean |
175 |
|
✗ |
privacy_link_cb (CcApplicationsPanel *self) |
176 |
|
|
{ |
177 |
|
✗ |
CcShell *shell = cc_panel_get_shell (CC_PANEL (self)); |
178 |
|
✗ |
g_autoptr(GError) error = NULL; |
179 |
|
|
|
180 |
|
✗ |
if (!cc_shell_set_active_panel_from_id (shell, "location", NULL, &error)) |
181 |
|
✗ |
g_warning ("Failed to switch to privacy panel: %s", error->message); |
182 |
|
|
|
183 |
|
✗ |
return TRUE; |
184 |
|
|
} |
185 |
|
|
|
186 |
|
|
static void |
187 |
|
✗ |
open_software_cb (CcApplicationsPanel *self) |
188 |
|
|
{ |
189 |
|
✗ |
const gchar *argv[] = { "gnome-software", "--details", "appid", NULL }; |
190 |
|
|
|
191 |
|
✗ |
if (self->current_app_id == NULL) |
192 |
|
✗ |
argv[1] = NULL; |
193 |
|
|
else |
194 |
|
✗ |
argv[2] = self->current_app_id; |
195 |
|
|
|
196 |
|
✗ |
g_spawn_async (NULL, (char **)argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); |
197 |
|
✗ |
} |
198 |
|
|
|
199 |
|
|
/* --- portal permissions and utilities --- */ |
200 |
|
|
|
201 |
|
|
static gchar ** |
202 |
|
✗ |
get_portal_permissions (CcApplicationsPanel *self, |
203 |
|
|
const gchar *table, |
204 |
|
|
const gchar *id, |
205 |
|
|
const gchar *app_id) |
206 |
|
|
{ |
207 |
|
✗ |
g_autoptr(GVariant) ret = NULL; |
208 |
|
✗ |
g_autoptr(GVariantIter) iter = NULL; |
209 |
|
✗ |
const gchar *key = NULL; |
210 |
|
|
GStrv val; |
211 |
|
✗ |
GStrv result = NULL; |
212 |
|
|
|
213 |
|
✗ |
ret = g_dbus_proxy_call_sync (self->perm_store, |
214 |
|
|
"Lookup", |
215 |
|
|
g_variant_new ("(ss)", table, id), |
216 |
|
|
0, G_MAXINT, NULL, NULL); |
217 |
|
✗ |
if (ret == NULL) |
218 |
|
✗ |
return NULL; |
219 |
|
|
|
220 |
|
✗ |
g_variant_get (ret, "(a{sas}v)", &iter, NULL); |
221 |
|
|
|
222 |
|
✗ |
while (g_variant_iter_loop (iter, "{&s^a&s}", &key, &val)) |
223 |
|
|
{ |
224 |
|
✗ |
if (strcmp (key, app_id) == 0 && result == NULL) |
225 |
|
✗ |
result = g_strdupv (val); |
226 |
|
|
} |
227 |
|
|
|
228 |
|
✗ |
return result; |
229 |
|
|
} |
230 |
|
|
|
231 |
|
|
static void |
232 |
|
✗ |
set_portal_permissions (CcApplicationsPanel *self, |
233 |
|
|
const gchar *table, |
234 |
|
|
const gchar *id, |
235 |
|
|
const gchar *app_id, |
236 |
|
|
const gchar * const *permissions) |
237 |
|
|
{ |
238 |
|
✗ |
g_autoptr(GError) error = NULL; |
239 |
|
|
|
240 |
|
✗ |
g_dbus_proxy_call_sync (self->perm_store, |
241 |
|
|
"SetPermission", |
242 |
|
|
g_variant_new ("(sbss^as)", table, TRUE, id, app_id, permissions), |
243 |
|
|
0, |
244 |
|
|
G_MAXINT, |
245 |
|
|
NULL, |
246 |
|
|
&error); |
247 |
|
✗ |
if (error) |
248 |
|
✗ |
g_warning ("Error setting portal permissions: %s", error->message); |
249 |
|
✗ |
} |
250 |
|
|
|
251 |
|
|
static gchar * |
252 |
|
✗ |
get_portal_app_id (GAppInfo *info) |
253 |
|
|
{ |
254 |
|
✗ |
if (G_IS_DESKTOP_APP_INFO (info)) |
255 |
|
|
{ |
256 |
|
✗ |
g_autofree gchar *snap_name = NULL; |
257 |
|
|
gchar *flatpak_id; |
258 |
|
|
|
259 |
|
✗ |
flatpak_id = g_desktop_app_info_get_string (G_DESKTOP_APP_INFO (info), "X-Flatpak"); |
260 |
|
✗ |
if (flatpak_id != NULL) |
261 |
|
✗ |
return flatpak_id; |
262 |
|
|
|
263 |
|
✗ |
snap_name = g_desktop_app_info_get_string (G_DESKTOP_APP_INFO (info), "X-SnapInstanceName"); |
264 |
|
✗ |
if (snap_name != NULL) |
265 |
|
✗ |
return g_strdup_printf ("%s%s", PORTAL_SNAP_PREFIX, snap_name); |
266 |
|
|
} |
267 |
|
|
|
268 |
|
✗ |
return NULL; |
269 |
|
|
} |
270 |
|
|
|
271 |
|
|
static GFile * |
272 |
|
✗ |
get_flatpak_app_dir (const gchar *app_id, |
273 |
|
|
const gchar *subdir) |
274 |
|
|
{ |
275 |
|
✗ |
g_autofree gchar *path = NULL; |
276 |
|
✗ |
g_autoptr(GFile) appdir = NULL; |
277 |
|
|
|
278 |
|
✗ |
path = g_build_filename (g_get_home_dir (), ".var", "app", app_id, NULL); |
279 |
|
✗ |
appdir = g_file_new_for_path (path); |
280 |
|
|
|
281 |
|
✗ |
return g_file_get_child (appdir, subdir); |
282 |
|
|
} |
283 |
|
|
|
284 |
|
|
/* --- search settings --- */ |
285 |
|
|
|
286 |
|
|
static void |
287 |
|
✗ |
set_search_enabled (CcApplicationsPanel *self, |
288 |
|
|
const gchar *app_id, |
289 |
|
|
gboolean enabled) |
290 |
|
|
{ |
291 |
|
✗ |
g_autoptr(GPtrArray) new_apps = NULL; |
292 |
|
✗ |
g_autofree gchar *desktop_id = NULL; |
293 |
|
✗ |
g_auto(GStrv) apps = NULL; |
294 |
|
|
gpointer key, value; |
295 |
|
|
gboolean default_disabled; |
296 |
|
|
gint i; |
297 |
|
|
|
298 |
|
✗ |
desktop_id = g_strconcat (app_id, ".desktop", NULL); |
299 |
|
|
|
300 |
|
✗ |
if (!g_hash_table_lookup_extended (self->search_providers, app_id, &key, &value)) |
301 |
|
|
{ |
302 |
|
✗ |
g_warning ("Trying to configure search for a provider-less app - this shouldn't happen"); |
303 |
|
✗ |
return; |
304 |
|
|
} |
305 |
|
|
|
306 |
|
✗ |
default_disabled = GPOINTER_TO_INT (value); |
307 |
|
|
|
308 |
|
✗ |
new_apps = g_ptr_array_new_with_free_func (g_free); |
309 |
|
✗ |
if (default_disabled) |
310 |
|
|
{ |
311 |
|
✗ |
apps = g_settings_get_strv (self->search_settings, "enabled"); |
312 |
|
✗ |
for (i = 0; apps[i]; i++) |
313 |
|
|
{ |
314 |
|
✗ |
if (strcmp (apps[i], desktop_id) != 0) |
315 |
|
✗ |
g_ptr_array_add (new_apps, g_strdup (apps[i])); |
316 |
|
|
} |
317 |
|
✗ |
if (enabled) |
318 |
|
✗ |
g_ptr_array_add (new_apps, g_strdup (desktop_id)); |
319 |
|
✗ |
g_ptr_array_add (new_apps, NULL); |
320 |
|
✗ |
g_settings_set_strv (self->search_settings, "enabled", (const gchar * const *)new_apps->pdata); |
321 |
|
|
} |
322 |
|
|
else |
323 |
|
|
{ |
324 |
|
✗ |
apps = g_settings_get_strv (self->search_settings, "disabled"); |
325 |
|
✗ |
for (i = 0; apps[i]; i++) |
326 |
|
|
{ |
327 |
|
✗ |
if (strcmp (apps[i], desktop_id) != 0) |
328 |
|
✗ |
g_ptr_array_add (new_apps, g_strdup (apps[i])); |
329 |
|
|
} |
330 |
|
✗ |
if (!enabled) |
331 |
|
✗ |
g_ptr_array_add (new_apps, g_strdup (desktop_id)); |
332 |
|
✗ |
g_ptr_array_add (new_apps, NULL); |
333 |
|
✗ |
g_settings_set_strv (self->search_settings, "disabled", (const gchar * const *)new_apps->pdata); |
334 |
|
|
} |
335 |
|
|
} |
336 |
|
|
|
337 |
|
|
static gboolean |
338 |
|
✗ |
search_contains_string_for_app (CcApplicationsPanel *self, |
339 |
|
|
const gchar *app_id, |
340 |
|
|
const gchar *setting) |
341 |
|
|
{ |
342 |
|
✗ |
g_autofree gchar *desktop_id = NULL; |
343 |
|
✗ |
g_auto(GStrv) apps = NULL; |
344 |
|
|
|
345 |
|
✗ |
desktop_id = g_strconcat (app_id, ".desktop", NULL); |
346 |
|
✗ |
apps = g_settings_get_strv (self->search_settings, setting); |
347 |
|
|
|
348 |
|
✗ |
return g_strv_contains ((const gchar * const *)apps, desktop_id); |
349 |
|
|
} |
350 |
|
|
|
351 |
|
|
static gboolean |
352 |
|
✗ |
search_enabled_for_app (CcApplicationsPanel *self, |
353 |
|
|
const gchar *app_id) |
354 |
|
|
{ |
355 |
|
✗ |
return search_contains_string_for_app (self, app_id, "enabled"); |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
static gboolean |
359 |
|
✗ |
search_disabled_for_app (CcApplicationsPanel *self, |
360 |
|
|
const gchar *app_id) |
361 |
|
|
{ |
362 |
|
✗ |
return search_contains_string_for_app (self, app_id, "disabled"); |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
static void |
366 |
|
✗ |
get_search_enabled (CcApplicationsPanel *self, |
367 |
|
|
const gchar *app_id, |
368 |
|
|
gboolean *set, |
369 |
|
|
gboolean *enabled) |
370 |
|
|
{ |
371 |
|
|
gpointer key, value; |
372 |
|
|
|
373 |
|
✗ |
*enabled = FALSE; |
374 |
|
✗ |
*set = g_hash_table_lookup_extended (self->search_providers, app_id, &key, &value); |
375 |
|
✗ |
if (!*set) |
376 |
|
✗ |
return; |
377 |
|
|
|
378 |
|
✗ |
if (search_enabled_for_app (self, app_id)) |
379 |
|
✗ |
*enabled = TRUE; |
380 |
|
✗ |
else if (search_disabled_for_app (self, app_id)) |
381 |
|
✗ |
*enabled = FALSE; |
382 |
|
|
else |
383 |
|
✗ |
*enabled = !GPOINTER_TO_INT (value); |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
static void |
387 |
|
✗ |
search_cb (CcApplicationsPanel *self) |
388 |
|
|
{ |
389 |
|
✗ |
if (self->current_app_id) |
390 |
|
✗ |
set_search_enabled (self, |
391 |
|
✗ |
self->current_app_id, |
392 |
|
|
adw_switch_row_get_active (self->search)); |
393 |
|
✗ |
} |
394 |
|
|
|
395 |
|
|
/* --- notification permissions (flatpaks and non-flatpak) --- */ |
396 |
|
|
|
397 |
|
|
static void |
398 |
|
✗ |
get_notification_allowed (CcApplicationsPanel *self, |
399 |
|
|
const gchar *app_id, |
400 |
|
|
gboolean *set, |
401 |
|
|
gboolean *allowed) |
402 |
|
|
{ |
403 |
|
✗ |
if (self->notification_settings) |
404 |
|
|
{ |
405 |
|
|
/* FIXME */ |
406 |
|
✗ |
*set = TRUE; |
407 |
|
✗ |
*allowed = g_settings_get_boolean (self->notification_settings, "enable"); |
408 |
|
|
} |
409 |
|
|
else |
410 |
|
|
{ |
411 |
|
✗ |
g_auto(GStrv) perms = get_portal_permissions (self, "notifications", "notification", app_id); |
412 |
|
✗ |
*set = perms != NULL; |
413 |
|
|
/* FIXME: needs unreleased xdg-desktop-portals to write permissions on use */ |
414 |
|
✗ |
*set = TRUE; |
415 |
|
✗ |
*allowed = perms == NULL || strcmp (perms[0], "no") != 0; |
416 |
|
|
} |
417 |
|
✗ |
} |
418 |
|
|
|
419 |
|
|
static void |
420 |
|
✗ |
set_notification_allowed (CcApplicationsPanel *self, |
421 |
|
|
gboolean allowed) |
422 |
|
|
{ |
423 |
|
✗ |
if (self->notification_settings) |
424 |
|
|
{ |
425 |
|
✗ |
g_settings_set_boolean (self->notification_settings, "enable", allowed); |
426 |
|
|
} |
427 |
|
|
else |
428 |
|
|
{ |
429 |
|
✗ |
const gchar *perms[2] = { NULL, NULL }; |
430 |
|
|
|
431 |
|
✗ |
perms[0] = allowed ? "yes" : "no"; |
432 |
|
✗ |
set_portal_permissions (self, "notifications", "notification", self->current_portal_app_id, perms); |
433 |
|
|
} |
434 |
|
✗ |
} |
435 |
|
|
|
436 |
|
|
static void |
437 |
|
✗ |
notification_cb (CcApplicationsPanel *self) |
438 |
|
|
{ |
439 |
|
✗ |
if (self->current_app_id) |
440 |
|
✗ |
set_notification_allowed (self, adw_switch_row_get_active (self->notification)); |
441 |
|
✗ |
} |
442 |
|
|
|
443 |
|
|
static gchar * |
444 |
|
✗ |
munge_app_id (const gchar *app_id) |
445 |
|
|
{ |
446 |
|
✗ |
gchar *id = g_strdup (app_id); |
447 |
|
|
gint i; |
448 |
|
|
|
449 |
|
✗ |
g_strcanon (id, |
450 |
|
|
"0123456789" |
451 |
|
|
"abcdefghijklmnopqrstuvwxyz" |
452 |
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
453 |
|
|
"-", |
454 |
|
|
'-'); |
455 |
|
✗ |
for (i = 0; id[i] != '\0'; i++) |
456 |
|
✗ |
id[i] = g_ascii_tolower (id[i]); |
457 |
|
|
|
458 |
|
✗ |
return id; |
459 |
|
|
} |
460 |
|
|
|
461 |
|
|
static GSettings * |
462 |
|
✗ |
get_notification_settings (const gchar *app_id) |
463 |
|
|
{ |
464 |
|
✗ |
g_autofree gchar *munged_app_id = munge_app_id (app_id); |
465 |
|
✗ |
g_autofree gchar *path = g_strconcat (APP_PREFIX, munged_app_id, "/", NULL); |
466 |
|
✗ |
return g_settings_new_with_path (APP_SCHEMA, path); |
467 |
|
|
} |
468 |
|
|
|
469 |
|
|
|
470 |
|
|
/* --- background --- */ |
471 |
|
|
|
472 |
|
|
static void |
473 |
|
✗ |
get_background_allowed (CcApplicationsPanel *self, |
474 |
|
|
const gchar *app_id, |
475 |
|
|
gboolean *set, |
476 |
|
|
gboolean *allowed) |
477 |
|
|
{ |
478 |
|
✗ |
g_auto(GStrv) perms = get_portal_permissions (self, "background", "background", app_id); |
479 |
|
✗ |
*set = TRUE; |
480 |
|
✗ |
*allowed = perms == NULL || strcmp (perms[0], "no") != 0; |
481 |
|
✗ |
} |
482 |
|
|
|
483 |
|
|
static void |
484 |
|
✗ |
set_background_allowed (CcApplicationsPanel *self, |
485 |
|
|
gboolean allowed) |
486 |
|
|
{ |
487 |
|
✗ |
const gchar *perms[2] = { NULL, NULL }; |
488 |
|
|
|
489 |
|
✗ |
perms[0] = allowed ? "yes" : "no"; |
490 |
|
✗ |
set_portal_permissions (self, "background", "background", self->current_portal_app_id, perms); |
491 |
|
✗ |
} |
492 |
|
|
|
493 |
|
|
static void |
494 |
|
✗ |
background_cb (CcApplicationsPanel *self) |
495 |
|
|
{ |
496 |
|
✗ |
if (self->current_app_id) |
497 |
|
✗ |
set_background_allowed (self, adw_switch_row_get_active (self->background)); |
498 |
|
✗ |
} |
499 |
|
|
|
500 |
|
|
/* --- wallpaper --- */ |
501 |
|
|
|
502 |
|
|
static void |
503 |
|
✗ |
get_wallpaper_allowed (CcApplicationsPanel *self, |
504 |
|
|
const gchar *app_id, |
505 |
|
|
gboolean *set, |
506 |
|
|
gboolean *allowed) |
507 |
|
|
{ |
508 |
|
✗ |
g_auto(GStrv) perms = get_portal_permissions (self, "wallpaper", "wallpaper", app_id); |
509 |
|
|
|
510 |
|
✗ |
*set = perms != NULL; |
511 |
|
✗ |
*allowed = perms == NULL || strcmp (perms[0], "no") != 0; |
512 |
|
✗ |
} |
513 |
|
|
|
514 |
|
|
static void |
515 |
|
✗ |
set_wallpaper_allowed (CcApplicationsPanel *self, |
516 |
|
|
gboolean allowed) |
517 |
|
|
{ |
518 |
|
✗ |
const gchar *perms[2] = { NULL, NULL }; |
519 |
|
|
|
520 |
|
✗ |
perms[0] = allowed ? "yes" : "no"; |
521 |
|
✗ |
set_portal_permissions (self, "wallpaper", "wallpaper", self->current_app_id, perms); |
522 |
|
✗ |
} |
523 |
|
|
|
524 |
|
|
static void |
525 |
|
✗ |
wallpaper_cb (CcApplicationsPanel *self) |
526 |
|
|
{ |
527 |
|
✗ |
if (self->current_app_id) |
528 |
|
✗ |
set_wallpaper_allowed (self, adw_switch_row_get_active (self->wallpaper)); |
529 |
|
✗ |
} |
530 |
|
|
|
531 |
|
|
/* --- screenshot --- */ |
532 |
|
|
|
533 |
|
|
static void |
534 |
|
✗ |
get_screenshot_allowed (CcApplicationsPanel *self, |
535 |
|
|
const gchar *app_id, |
536 |
|
|
gboolean *set, |
537 |
|
|
gboolean *allowed) |
538 |
|
|
{ |
539 |
|
✗ |
g_auto(GStrv) perms = get_portal_permissions (self, "screenshot", "screenshot", app_id); |
540 |
|
|
|
541 |
|
✗ |
*set = perms != NULL; |
542 |
|
✗ |
*allowed = perms == NULL || strcmp (perms[0], "no") != 0; |
543 |
|
✗ |
} |
544 |
|
|
|
545 |
|
|
static void |
546 |
|
✗ |
set_screenshot_allowed (CcApplicationsPanel *self, |
547 |
|
|
gboolean allowed) |
548 |
|
|
{ |
549 |
|
✗ |
const gchar *perms[2] = { NULL, NULL }; |
550 |
|
|
|
551 |
|
✗ |
perms[0] = allowed ? "yes" : "no"; |
552 |
|
✗ |
set_portal_permissions (self, "screenshot", "screenshot", self->current_app_id, perms); |
553 |
|
✗ |
} |
554 |
|
|
|
555 |
|
|
static void |
556 |
|
✗ |
screenshot_cb (CcApplicationsPanel *self) |
557 |
|
|
{ |
558 |
|
✗ |
if (self->current_app_id) |
559 |
|
✗ |
set_screenshot_allowed (self, adw_switch_row_get_active (self->screenshot)); |
560 |
|
✗ |
} |
561 |
|
|
|
562 |
|
|
/* --- shortcuts permissions (flatpak) --- */ |
563 |
|
|
|
564 |
|
|
static void |
565 |
|
✗ |
get_shortcuts_allowed (CcApplicationsPanel *self, |
566 |
|
|
const gchar *app_id, |
567 |
|
|
gboolean *set, |
568 |
|
|
gboolean *granted) |
569 |
|
|
{ |
570 |
|
✗ |
g_auto(GStrv) perms = NULL; |
571 |
|
|
|
572 |
|
✗ |
perms = get_portal_permissions (self, "gnome", "shortcuts-inhibitor", app_id); |
573 |
|
|
|
574 |
|
|
/* GNOME Shell's "inhibit shortcut dialog" sets the permission to "GRANTED" if |
575 |
|
|
* the user allowed for the keyboard shortcuts to be inhibited, check for that |
576 |
|
|
* string value here. |
577 |
|
|
*/ |
578 |
|
✗ |
*set = perms != NULL; |
579 |
|
✗ |
*granted = (perms != NULL) && g_ascii_strcasecmp (perms[0], "GRANTED") == 0; |
580 |
|
✗ |
} |
581 |
|
|
|
582 |
|
|
static void |
583 |
|
✗ |
set_shortcuts_allowed (CcApplicationsPanel *self, |
584 |
|
|
gboolean granted) |
585 |
|
|
{ |
586 |
|
|
const gchar *perms[2]; |
587 |
|
✗ |
g_autofree gchar *desktop_id = g_strconcat (self->current_app_id, ".desktop", NULL); |
588 |
|
|
|
589 |
|
|
/* "GRANTED" and "DENIED" here match the values set by the "inhibit shortcut |
590 |
|
|
* dialog" is GNOME Shell: |
591 |
|
|
* https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/inhibitShortcutsDialog.js |
592 |
|
|
*/ |
593 |
|
✗ |
perms[0] = granted ? "GRANTED" : "DENIED"; |
594 |
|
✗ |
perms[1] = NULL; |
595 |
|
|
|
596 |
|
✗ |
set_portal_permissions (self, "gnome", "shortcuts-inhibitor", desktop_id, perms); |
597 |
|
✗ |
} |
598 |
|
|
|
599 |
|
|
static void |
600 |
|
✗ |
shortcuts_cb (CcApplicationsPanel *self) |
601 |
|
|
{ |
602 |
|
✗ |
if (self->current_app_id) |
603 |
|
✗ |
set_shortcuts_allowed (self, adw_switch_row_get_active (self->shortcuts)); |
604 |
|
✗ |
} |
605 |
|
|
|
606 |
|
|
/* --- device (microphone, camera, speaker) permissions (flatpak) --- */ |
607 |
|
|
|
608 |
|
|
static void |
609 |
|
✗ |
get_device_allowed (CcApplicationsPanel *self, |
610 |
|
|
const gchar *device, |
611 |
|
|
const gchar *app_id, |
612 |
|
|
gboolean *set, |
613 |
|
|
gboolean *allowed) |
614 |
|
|
{ |
615 |
|
✗ |
g_auto(GStrv) perms = NULL; |
616 |
|
|
|
617 |
|
✗ |
perms = get_portal_permissions (self, "devices", device, app_id); |
618 |
|
|
|
619 |
|
✗ |
*set = perms != NULL; |
620 |
|
✗ |
*allowed = perms == NULL || strcmp (perms[0], "no") != 0; |
621 |
|
✗ |
} |
622 |
|
|
|
623 |
|
|
static void |
624 |
|
✗ |
set_device_allowed (CcApplicationsPanel *self, |
625 |
|
|
const gchar *device, |
626 |
|
|
gboolean allowed) |
627 |
|
|
{ |
628 |
|
|
const gchar *perms[2]; |
629 |
|
|
|
630 |
|
✗ |
perms[0] = allowed ? "yes" : "no"; |
631 |
|
✗ |
perms[1] = NULL; |
632 |
|
|
|
633 |
|
✗ |
set_portal_permissions (self, "devices", device, self->current_portal_app_id, perms); |
634 |
|
✗ |
} |
635 |
|
|
|
636 |
|
|
static void |
637 |
|
✗ |
microphone_cb (CcApplicationsPanel *self) |
638 |
|
|
{ |
639 |
|
✗ |
if (self->current_portal_app_id) |
640 |
|
✗ |
set_device_allowed (self, "microphone", adw_switch_row_get_active (self->microphone)); |
641 |
|
✗ |
} |
642 |
|
|
|
643 |
|
|
static void |
644 |
|
✗ |
sound_cb (CcApplicationsPanel *self) |
645 |
|
|
{ |
646 |
|
✗ |
if (self->current_portal_app_id) |
647 |
|
✗ |
set_device_allowed (self, "speakers", adw_switch_row_get_active (self->sound)); |
648 |
|
✗ |
} |
649 |
|
|
|
650 |
|
|
static void |
651 |
|
✗ |
camera_cb (CcApplicationsPanel *self) |
652 |
|
|
{ |
653 |
|
✗ |
if (self->current_portal_app_id) |
654 |
|
✗ |
set_device_allowed (self, "camera", adw_switch_row_get_active (self->camera)); |
655 |
|
✗ |
} |
656 |
|
|
|
657 |
|
|
/* --- location permissions (flatpak) --- */ |
658 |
|
|
|
659 |
|
|
static void |
660 |
|
✗ |
get_location_allowed (CcApplicationsPanel *self, |
661 |
|
|
const gchar *app_id, |
662 |
|
|
gboolean *set, |
663 |
|
|
gboolean *allowed) |
664 |
|
|
{ |
665 |
|
✗ |
g_auto(GStrv) perms = NULL; |
666 |
|
|
|
667 |
|
✗ |
perms = get_portal_permissions (self, "location", "location", app_id); |
668 |
|
|
|
669 |
|
✗ |
*set = perms != NULL; |
670 |
|
✗ |
*allowed = perms == NULL || strcmp (perms[0], "NONE") != 0; |
671 |
|
✗ |
} |
672 |
|
|
|
673 |
|
|
static void |
674 |
|
✗ |
set_location_allowed (CcApplicationsPanel *self, |
675 |
|
|
gboolean allowed) |
676 |
|
|
{ |
677 |
|
|
const gchar *perms[3]; |
678 |
|
|
|
679 |
|
|
/* FIXME allow setting accuracy */ |
680 |
|
✗ |
perms[0] = allowed ? "EXACT" : "NONE"; |
681 |
|
✗ |
perms[1] = "0"; |
682 |
|
✗ |
perms[2] = NULL; |
683 |
|
|
|
684 |
|
✗ |
set_portal_permissions (self, "location", "location", self->current_portal_app_id, perms); |
685 |
|
✗ |
} |
686 |
|
|
|
687 |
|
|
static void |
688 |
|
✗ |
location_cb (CcApplicationsPanel *self) |
689 |
|
|
{ |
690 |
|
✗ |
if (self->current_portal_app_id) |
691 |
|
✗ |
set_location_allowed (self, adw_switch_row_get_active (self->location)); |
692 |
|
✗ |
} |
693 |
|
|
|
694 |
|
|
/* --- permissions section --- */ |
695 |
|
|
|
696 |
|
|
#ifdef HAVE_SNAP |
697 |
|
|
static void |
698 |
|
✗ |
remove_snap_permissions (CcApplicationsPanel *self) |
699 |
|
|
{ |
700 |
|
|
GList *l; |
701 |
|
|
|
702 |
|
✗ |
for (l = self->snap_permission_rows; l; l = l->next) |
703 |
|
✗ |
adw_preferences_group_remove (self->integration_section, l->data); |
704 |
|
✗ |
g_clear_pointer (&self->snap_permission_rows, g_list_free); |
705 |
|
✗ |
} |
706 |
|
|
|
707 |
|
|
static gboolean |
708 |
|
✗ |
add_snap_permissions (CcApplicationsPanel *self, |
709 |
|
|
GAppInfo *info, |
710 |
|
|
const gchar *app_id) |
711 |
|
|
{ |
712 |
|
|
const gchar *snap_name; |
713 |
|
✗ |
g_autoptr(CcSnapdClient) client = NULL; |
714 |
|
✗ |
g_autoptr(JsonArray) plugs = NULL; |
715 |
|
✗ |
g_autoptr(JsonArray) slots = NULL; |
716 |
|
✗ |
gint added = 0; |
717 |
|
✗ |
g_autoptr(GError) error = NULL; |
718 |
|
✗ |
g_autoptr(GError) interfaces_error = NULL; |
719 |
|
|
|
720 |
|
✗ |
if (!g_str_has_prefix (app_id, PORTAL_SNAP_PREFIX)) |
721 |
|
✗ |
return FALSE; |
722 |
|
✗ |
snap_name = app_id + strlen (PORTAL_SNAP_PREFIX); |
723 |
|
|
|
724 |
|
✗ |
client = cc_snapd_client_new (); |
725 |
|
|
|
726 |
|
✗ |
if (!cc_snapd_client_get_all_connections_sync (client, &plugs, &slots, cc_panel_get_cancellable (CC_PANEL (self)), &error)) |
727 |
|
|
{ |
728 |
|
✗ |
g_warning ("Failed to get snap connections: %s", error->message); |
729 |
|
✗ |
return FALSE; |
730 |
|
|
} |
731 |
|
|
|
732 |
|
✗ |
for (guint i = 0; i < json_array_get_length (plugs); i++) |
733 |
|
|
{ |
734 |
|
✗ |
JsonObject *plug = json_array_get_object_element (plugs, i); |
735 |
|
|
const gchar *plug_interface; |
736 |
|
|
CcSnapRow *row; |
737 |
|
✗ |
g_autoptr(JsonArray) available_slots = NULL; |
738 |
|
✗ |
const gchar * const hidden_interfaces[] = { "content", |
739 |
|
|
"desktop", "desktop-legacy", |
740 |
|
|
"mir", |
741 |
|
|
"unity7", "unity8", |
742 |
|
|
"wayland", |
743 |
|
|
"x11", |
744 |
|
|
NULL }; |
745 |
|
|
|
746 |
|
|
/* Skip if not relating to this snap */ |
747 |
|
✗ |
if (g_strcmp0 (json_object_get_string_member (plug, "snap"), snap_name) != 0) |
748 |
|
✗ |
continue; |
749 |
|
|
|
750 |
|
|
/* Ignore interfaces that are too low level to make sense to show or disable */ |
751 |
|
✗ |
plug_interface = json_object_get_string_member (plug, "interface"); |
752 |
|
✗ |
if (g_strv_contains (hidden_interfaces, plug_interface)) |
753 |
|
✗ |
continue; |
754 |
|
|
|
755 |
|
✗ |
available_slots = json_array_new (); |
756 |
|
✗ |
for (guint j = 0; j < json_array_get_length (slots); j++) |
757 |
|
|
{ |
758 |
|
✗ |
JsonObject *slot = json_array_get_object_element (slots, j); |
759 |
|
✗ |
if (g_strcmp0 (plug_interface, json_object_get_string_member (slot, "interface")) != 0) |
760 |
|
✗ |
continue; |
761 |
|
|
|
762 |
|
✗ |
json_array_add_object_element (available_slots, slot); |
763 |
|
|
} |
764 |
|
|
|
765 |
|
✗ |
row = cc_snap_row_new (cc_panel_get_cancellable (CC_PANEL (self)), plug, available_slots); |
766 |
|
✗ |
adw_preferences_group_add (self->integration_section, GTK_WIDGET (row)); |
767 |
|
✗ |
self->snap_permission_rows = g_list_prepend (self->snap_permission_rows, row); |
768 |
|
✗ |
added++; |
769 |
|
|
} |
770 |
|
|
|
771 |
|
✗ |
return added > 0; |
772 |
|
|
} |
773 |
|
|
#endif |
774 |
|
|
|
775 |
|
|
static void |
776 |
|
✗ |
update_sandbox_banner (CcApplicationsPanel *self, |
777 |
|
|
gboolean is_sandboxed) |
778 |
|
|
{ |
779 |
|
|
|
780 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->sandbox_banner), !is_sandboxed); |
781 |
|
✗ |
if (is_sandboxed) |
782 |
|
✗ |
return; |
783 |
|
|
|
784 |
|
✗ |
adw_banner_set_title (self->sandbox_banner, _("App is not sandboxed")); |
785 |
|
|
} |
786 |
|
|
|
787 |
|
|
static gint |
788 |
|
✗ |
add_static_permission_row (CcApplicationsPanel *self, |
789 |
|
|
const gchar *title, |
790 |
|
|
const gchar *subtitle) |
791 |
|
|
{ |
792 |
|
|
GtkWidget *row; |
793 |
|
|
|
794 |
|
✗ |
row = adw_action_row_new (); |
795 |
|
✗ |
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), title); |
796 |
|
✗ |
adw_action_row_set_subtitle (ADW_ACTION_ROW (row), subtitle); |
797 |
|
✗ |
gtk_widget_add_css_class (row, "property"); |
798 |
|
✗ |
gtk_list_box_append (self->builtin_list, row); |
799 |
|
|
|
800 |
|
✗ |
return 1; |
801 |
|
|
} |
802 |
|
|
|
803 |
|
|
static gboolean |
804 |
|
✗ |
add_static_permissions (CcApplicationsPanel *self, |
805 |
|
|
GAppInfo *info, |
806 |
|
|
const gchar *app_id) |
807 |
|
|
{ |
808 |
|
✗ |
g_autoptr(GKeyFile) keyfile = NULL; |
809 |
|
✗ |
g_auto(GStrv) sockets = NULL; |
810 |
|
✗ |
g_auto(GStrv) devices = NULL; |
811 |
|
✗ |
g_auto(GStrv) shared = NULL; |
812 |
|
✗ |
g_auto(GStrv) filesystems = NULL; |
813 |
|
✗ |
g_autofree gchar *str = NULL; |
814 |
|
✗ |
gint added = 0; |
815 |
|
✗ |
g_autofree gchar *text = NULL; |
816 |
|
✗ |
g_autofree gchar *static_permissions_number = NULL; |
817 |
|
✗ |
gboolean is_sandboxed, is_snap = FALSE; |
818 |
|
|
|
819 |
|
✗ |
is_snap = app_id && g_str_has_prefix (app_id, PORTAL_SNAP_PREFIX); |
820 |
|
✗ |
if (app_id && !is_snap) |
821 |
|
✗ |
keyfile = get_flatpak_metadata (app_id); |
822 |
|
|
|
823 |
|
✗ |
is_sandboxed = (keyfile != NULL) || is_snap; |
824 |
|
✗ |
update_sandbox_banner (self, is_sandboxed); |
825 |
|
✗ |
if (keyfile == NULL) |
826 |
|
✗ |
return FALSE; |
827 |
|
|
|
828 |
|
✗ |
sockets = g_key_file_get_string_list (keyfile, "Context", "sockets", NULL, NULL); |
829 |
|
✗ |
if (sockets && g_strv_contains ((const gchar * const*)sockets, "system-bus")) |
830 |
|
✗ |
added += add_static_permission_row (self, _("System Bus"), _("Full access")); |
831 |
|
✗ |
if (sockets && g_strv_contains ((const gchar * const*)sockets, "session-bus")) |
832 |
|
✗ |
added += add_static_permission_row (self, _("Session Bus"), _("Full access")); |
833 |
|
|
|
834 |
|
✗ |
devices = g_key_file_get_string_list (keyfile, "Context", "devices", NULL, NULL); |
835 |
|
✗ |
if (devices && g_strv_contains ((const gchar * const*)devices, "all")) |
836 |
|
✗ |
added += add_static_permission_row (self, _("Devices"), _("Full access to /dev")); |
837 |
|
|
|
838 |
|
✗ |
shared = g_key_file_get_string_list (keyfile, "Context", "shared", NULL, NULL); |
839 |
|
✗ |
if (shared && g_strv_contains ((const gchar * const*)shared, "network")) |
840 |
|
✗ |
added += add_static_permission_row (self, _("Network"), _("Has network access")); |
841 |
|
|
|
842 |
|
✗ |
filesystems = g_key_file_get_string_list (keyfile, "Context", "filesystems", NULL, NULL); |
843 |
|
✗ |
if (filesystems && (g_strv_contains ((const gchar * const *)filesystems, "home") || |
844 |
|
✗ |
g_strv_contains ((const gchar * const *)filesystems, "home:rw"))) |
845 |
|
✗ |
added += add_static_permission_row (self, _("Home"), _("Full access")); |
846 |
|
✗ |
else if (filesystems && g_strv_contains ((const gchar * const *)filesystems, "home:ro")) |
847 |
|
✗ |
added += add_static_permission_row (self, _("Home"), _("Read-only")); |
848 |
|
✗ |
if (filesystems && (g_strv_contains ((const gchar * const *)filesystems, "host") || |
849 |
|
✗ |
g_strv_contains ((const gchar * const *)filesystems, "host:rw"))) |
850 |
|
✗ |
added += add_static_permission_row (self, _("File System"), _("Full access")); |
851 |
|
✗ |
else if (filesystems && g_strv_contains ((const gchar * const *)filesystems, "host:ro")) |
852 |
|
✗ |
added += add_static_permission_row (self, _("File System"), _("Read-only")); |
853 |
|
|
|
854 |
|
✗ |
str = g_key_file_get_string (keyfile, "Session Bus Policy", "ca.desrt.dconf", NULL); |
855 |
|
✗ |
if (str && g_str_equal (str, "talk")) |
856 |
|
✗ |
added += add_static_permission_row (self, _("Settings"), _("Can change settings")); |
857 |
|
|
|
858 |
|
✗ |
text = g_strdup_printf (_("<b>%s</b> requires access to the following system resources. To stop this access, the app must be removed."), g_app_info_get_display_name (info)); |
859 |
|
✗ |
adw_preferences_page_set_description (self->builtin_page, text); |
860 |
|
|
|
861 |
|
✗ |
static_permissions_number = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, |
862 |
|
|
"%u permission", |
863 |
|
|
"%u permissions", |
864 |
|
|
added), |
865 |
|
|
added); |
866 |
|
✗ |
cc_list_row_set_secondary_label (self->builtin, static_permissions_number); |
867 |
|
|
|
868 |
|
✗ |
return added > 0; |
869 |
|
|
} |
870 |
|
|
|
871 |
|
|
static void |
872 |
|
✗ |
remove_static_permissions (CcApplicationsPanel *self) |
873 |
|
|
{ |
874 |
|
✗ |
gtk_list_box_remove_all (self->builtin_list); |
875 |
|
✗ |
} |
876 |
|
|
|
877 |
|
|
/* --- header section --- */ |
878 |
|
|
|
879 |
|
|
static void |
880 |
|
✗ |
update_header_section (CcApplicationsPanel *self, |
881 |
|
|
GAppInfo *info) |
882 |
|
|
{ |
883 |
|
|
GIcon *icon; |
884 |
|
|
|
885 |
|
✗ |
icon = g_app_info_get_icon (info); |
886 |
|
✗ |
gtk_image_set_from_gicon (self->app_icon_image, icon); |
887 |
|
|
|
888 |
|
✗ |
gtk_label_set_label (self->app_name_label, |
889 |
|
|
g_app_info_get_display_name (info)); |
890 |
|
✗ |
} |
891 |
|
|
|
892 |
|
|
|
893 |
|
|
/* --- gintegration section --- */ |
894 |
|
|
|
895 |
|
|
static void |
896 |
|
✗ |
update_integration_section (CcApplicationsPanel *self, |
897 |
|
|
GAppInfo *info) |
898 |
|
|
{ |
899 |
|
✗ |
g_autofree gchar *app_id = get_app_id (info); |
900 |
|
✗ |
g_autofree gchar *portal_app_id = get_portal_app_id (info); |
901 |
|
|
gboolean set, allowed, disabled; |
902 |
|
✗ |
gboolean has_any = FALSE; |
903 |
|
|
|
904 |
|
✗ |
disabled = g_settings_get_boolean (self->search_settings, "disable-external"); |
905 |
|
✗ |
get_search_enabled (self, app_id, &set, &allowed); |
906 |
|
✗ |
adw_switch_row_set_active (self->search, allowed); |
907 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->search), set && !disabled); |
908 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_search), set && disabled); |
909 |
|
|
|
910 |
|
✗ |
if (app_id != NULL) |
911 |
|
|
{ |
912 |
|
✗ |
g_autofree gchar *desktop_id = g_strconcat (app_id, ".desktop", NULL); |
913 |
|
✗ |
get_shortcuts_allowed (self, desktop_id, &set, &allowed); |
914 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->shortcuts), set); |
915 |
|
✗ |
adw_switch_row_set_active (self->shortcuts, allowed); |
916 |
|
|
} |
917 |
|
|
else |
918 |
|
|
{ |
919 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->shortcuts), FALSE); |
920 |
|
|
} |
921 |
|
|
|
922 |
|
|
#ifdef HAVE_SNAP |
923 |
|
✗ |
remove_snap_permissions (self); |
924 |
|
|
#endif |
925 |
|
|
|
926 |
|
✗ |
if (portal_app_id != NULL) |
927 |
|
|
{ |
928 |
|
✗ |
g_clear_object (&self->notification_settings); |
929 |
|
✗ |
get_notification_allowed (self, portal_app_id, &set, &allowed); |
930 |
|
✗ |
adw_switch_row_set_active (self->notification, allowed); |
931 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->notification), set); |
932 |
|
✗ |
has_any |= set; |
933 |
|
|
|
934 |
|
✗ |
get_background_allowed (self, portal_app_id, &set, &allowed); |
935 |
|
✗ |
adw_switch_row_set_active (self->background, allowed); |
936 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->background), set); |
937 |
|
✗ |
has_any |= set; |
938 |
|
|
|
939 |
|
✗ |
get_wallpaper_allowed (self, portal_app_id, &set, &allowed); |
940 |
|
✗ |
adw_switch_row_set_active (self->wallpaper, allowed); |
941 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->wallpaper), set); |
942 |
|
✗ |
has_any |= set; |
943 |
|
|
|
944 |
|
✗ |
get_screenshot_allowed (self, portal_app_id, &set, &allowed); |
945 |
|
✗ |
adw_switch_row_set_active (self->screenshot, allowed); |
946 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->screenshot), set); |
947 |
|
✗ |
has_any |= set; |
948 |
|
|
|
949 |
|
✗ |
disabled = g_settings_get_boolean (self->privacy_settings, "disable-sound-output"); |
950 |
|
✗ |
get_device_allowed (self, "speakers", portal_app_id, &set, &allowed); |
951 |
|
✗ |
adw_switch_row_set_active (self->sound, allowed); |
952 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->sound), set && !disabled); |
953 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_sound), set && disabled); |
954 |
|
|
|
955 |
|
✗ |
disabled = g_settings_get_boolean (self->privacy_settings, "disable-camera"); |
956 |
|
✗ |
get_device_allowed (self, "camera", portal_app_id, &set, &allowed); |
957 |
|
✗ |
adw_switch_row_set_active (self->camera, allowed); |
958 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->camera), set && !disabled); |
959 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_camera), set && disabled); |
960 |
|
✗ |
has_any |= set; |
961 |
|
|
|
962 |
|
✗ |
disabled = g_settings_get_boolean (self->privacy_settings, "disable-microphone"); |
963 |
|
✗ |
get_device_allowed (self, "microphone", portal_app_id, &set, &allowed); |
964 |
|
✗ |
adw_switch_row_set_active (self->microphone, allowed); |
965 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->microphone), set && !disabled); |
966 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_microphone), set && disabled); |
967 |
|
✗ |
has_any |= set; |
968 |
|
|
|
969 |
|
✗ |
disabled = !g_settings_get_boolean (self->location_settings, "enabled"); |
970 |
|
✗ |
get_location_allowed (self, portal_app_id, &set, &allowed); |
971 |
|
✗ |
adw_switch_row_set_active (self->location, allowed); |
972 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->location), set && !disabled); |
973 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_location), set && disabled); |
974 |
|
✗ |
has_any |= set; |
975 |
|
|
|
976 |
|
|
#ifdef HAVE_SNAP |
977 |
|
✗ |
has_any |= add_snap_permissions (self, info, portal_app_id); |
978 |
|
|
#endif |
979 |
|
|
} |
980 |
|
|
else |
981 |
|
|
{ |
982 |
|
✗ |
g_set_object (&self->notification_settings, get_notification_settings (app_id)); |
983 |
|
✗ |
get_notification_allowed (self, app_id, &set, &allowed); |
984 |
|
✗ |
adw_switch_row_set_active (self->notification, allowed); |
985 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->notification), set); |
986 |
|
✗ |
has_any |= set; |
987 |
|
|
|
988 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->background), FALSE); |
989 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->wallpaper), FALSE); |
990 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->screenshot), FALSE); |
991 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->sound), FALSE); |
992 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_sound), FALSE); |
993 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->camera), FALSE); |
994 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_camera), FALSE); |
995 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->microphone), FALSE); |
996 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_microphone), FALSE); |
997 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->location), FALSE); |
998 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->no_location), FALSE); |
999 |
|
|
} |
1000 |
|
|
|
1001 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->integration_section), has_any); |
1002 |
|
✗ |
} |
1003 |
|
|
|
1004 |
|
|
/* --- handler section --- */ |
1005 |
|
|
|
1006 |
|
|
static void |
1007 |
|
✗ |
unset_cb (CcApplicationsPanel *self, |
1008 |
|
|
GtkButton *button) |
1009 |
|
|
{ |
1010 |
|
|
const gchar *type; |
1011 |
|
|
|
1012 |
|
✗ |
type = (const gchar *)g_object_get_data (G_OBJECT (button), "type"); |
1013 |
|
|
|
1014 |
|
✗ |
g_app_info_remove_supports_type (self->current_app_info, type, NULL); |
1015 |
|
✗ |
update_handler_dialog (self, self->current_app_info); |
1016 |
|
✗ |
} |
1017 |
|
|
|
1018 |
|
|
static void |
1019 |
|
✗ |
add_scheme (CcApplicationsPanel *self, |
1020 |
|
|
const gchar *type) |
1021 |
|
|
{ |
1022 |
|
✗ |
g_autofree gchar *title = NULL; |
1023 |
|
|
GtkWidget *button; |
1024 |
|
|
GtkWidget *row; |
1025 |
|
|
gchar *scheme; |
1026 |
|
|
|
1027 |
|
✗ |
scheme = strrchr (type, '/') + 1; |
1028 |
|
✗ |
title = g_strdup_printf ("%s://", scheme); |
1029 |
|
|
|
1030 |
|
✗ |
row = adw_action_row_new (); |
1031 |
|
✗ |
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), title); |
1032 |
|
|
|
1033 |
|
✗ |
button = gtk_button_new_from_icon_name ("edit-delete-symbolic"); |
1034 |
|
✗ |
gtk_widget_set_tooltip_text (button, _("Remove Link Type")); |
1035 |
|
✗ |
gtk_widget_set_valign (button, GTK_ALIGN_CENTER); |
1036 |
|
✗ |
gtk_widget_set_halign (button, GTK_ALIGN_END); |
1037 |
|
✗ |
gtk_widget_add_css_class (button, "flat"); |
1038 |
|
✗ |
gtk_widget_add_css_class (button, "circular"); |
1039 |
|
✗ |
adw_action_row_add_suffix (ADW_ACTION_ROW (row), button); |
1040 |
|
✗ |
g_object_set_data_full (G_OBJECT (button), "type", g_strdup (type), g_free); |
1041 |
|
✗ |
g_signal_connect_object (button, "clicked", G_CALLBACK (unset_cb), self, G_CONNECT_SWAPPED); |
1042 |
|
|
|
1043 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->handler_link_group), TRUE); |
1044 |
|
✗ |
adw_preferences_group_add (self->handler_link_group, GTK_WIDGET (row)); |
1045 |
|
|
|
1046 |
|
✗ |
self->link_handler_rows = g_list_prepend (self->link_handler_rows, row); |
1047 |
|
✗ |
} |
1048 |
|
|
|
1049 |
|
|
static void |
1050 |
|
✗ |
add_file_type (CcApplicationsPanel *self, |
1051 |
|
|
const gchar *type) |
1052 |
|
|
{ |
1053 |
|
✗ |
g_autofree gchar *desc = NULL; |
1054 |
|
|
const gchar *glob; |
1055 |
|
|
GtkWidget *button; |
1056 |
|
|
GtkWidget *row; |
1057 |
|
|
|
1058 |
|
✗ |
glob = g_hash_table_lookup (self->globs, type); |
1059 |
|
|
|
1060 |
|
✗ |
desc = g_content_type_get_description (type); |
1061 |
|
✗ |
row = adw_action_row_new (); |
1062 |
|
✗ |
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), desc); |
1063 |
|
✗ |
adw_action_row_set_subtitle (ADW_ACTION_ROW (row), glob ? glob : ""); |
1064 |
|
|
|
1065 |
|
✗ |
button = gtk_button_new_from_icon_name ("edit-delete-symbolic"); |
1066 |
|
✗ |
gtk_widget_set_tooltip_text (button, _("Remove File Type")); |
1067 |
|
✗ |
gtk_widget_set_valign (button, GTK_ALIGN_CENTER); |
1068 |
|
✗ |
gtk_widget_set_halign (button, GTK_ALIGN_END); |
1069 |
|
✗ |
gtk_widget_add_css_class (button, "flat"); |
1070 |
|
✗ |
gtk_widget_add_css_class (button, "circular"); |
1071 |
|
✗ |
adw_action_row_add_suffix (ADW_ACTION_ROW (row), button); |
1072 |
|
✗ |
g_object_set_data_full (G_OBJECT (button), "type", g_strdup (type), g_free); |
1073 |
|
✗ |
g_signal_connect_object (button, "clicked", G_CALLBACK (unset_cb), self, G_CONNECT_SWAPPED); |
1074 |
|
|
|
1075 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->handler_file_group), TRUE); |
1076 |
|
✗ |
adw_preferences_group_add (self->handler_file_group, GTK_WIDGET (row)); |
1077 |
|
|
|
1078 |
|
✗ |
self->file_handler_rows = g_list_prepend (self->file_handler_rows, row); |
1079 |
|
✗ |
} |
1080 |
|
|
|
1081 |
|
|
static void |
1082 |
|
✗ |
add_handler_row (CcApplicationsPanel *self, |
1083 |
|
|
const gchar *type) |
1084 |
|
|
{ |
1085 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->handler_row), TRUE); |
1086 |
|
|
|
1087 |
|
✗ |
if (g_content_type_is_a (type, "x-scheme-handler/*")) |
1088 |
|
✗ |
add_scheme (self, type); |
1089 |
|
|
else |
1090 |
|
✗ |
add_file_type (self, type); |
1091 |
|
✗ |
} |
1092 |
|
|
|
1093 |
|
|
static gboolean |
1094 |
|
✗ |
app_info_recommended_for (GAppInfo *info, |
1095 |
|
|
const gchar *type) |
1096 |
|
|
{ |
1097 |
|
|
/* this is horribly inefficient. I blame the mime system */ |
1098 |
|
✗ |
g_autolist(GObject) list = NULL; |
1099 |
|
|
GList *l; |
1100 |
|
✗ |
gboolean ret = FALSE; |
1101 |
|
|
|
1102 |
|
✗ |
list = g_app_info_get_recommended_for_type (type); |
1103 |
|
✗ |
for (l = list; l; l = l->next) |
1104 |
|
|
{ |
1105 |
|
✗ |
GAppInfo *ri = l->data; |
1106 |
|
|
|
1107 |
|
✗ |
if (g_app_info_equal (info, ri)) |
1108 |
|
|
{ |
1109 |
|
✗ |
ret = TRUE; |
1110 |
|
✗ |
break; |
1111 |
|
|
} |
1112 |
|
|
} |
1113 |
|
|
|
1114 |
|
✗ |
return ret; |
1115 |
|
|
} |
1116 |
|
|
|
1117 |
|
|
static void |
1118 |
|
✗ |
handler_reset_cb (CcApplicationsPanel *self) |
1119 |
|
|
{ |
1120 |
|
|
const gchar **types; |
1121 |
|
|
gint i; |
1122 |
|
|
|
1123 |
|
✗ |
types = g_app_info_get_supported_types (self->current_app_info); |
1124 |
|
✗ |
if (types == NULL || types[0] == NULL) |
1125 |
|
✗ |
return; |
1126 |
|
|
|
1127 |
|
✗ |
g_signal_handler_block (self->monitor, self->monitor_id); |
1128 |
|
✗ |
for (i = 0; types[i]; i++) |
1129 |
|
|
{ |
1130 |
|
✗ |
gchar *ctype = g_content_type_from_mime_type (types[i]); |
1131 |
|
✗ |
g_app_info_add_supports_type (self->current_app_info, ctype, NULL); |
1132 |
|
|
} |
1133 |
|
✗ |
g_signal_handler_unblock (self->monitor, self->monitor_id); |
1134 |
|
✗ |
g_signal_emit_by_name (self->monitor, "changed"); |
1135 |
|
✗ |
update_handler_dialog(self, self->current_app_info); |
1136 |
|
|
} |
1137 |
|
|
|
1138 |
|
|
static void |
1139 |
|
✗ |
remove_all_handler_rows (CcApplicationsPanel *self) |
1140 |
|
|
{ |
1141 |
|
|
GList *l; |
1142 |
|
|
|
1143 |
|
✗ |
for (l = self->file_handler_rows; l; l = l->next) |
1144 |
|
✗ |
adw_preferences_group_remove (self->handler_file_group, l->data); |
1145 |
|
✗ |
g_clear_pointer (&self->file_handler_rows, g_list_free); |
1146 |
|
|
|
1147 |
|
✗ |
for (l = self->link_handler_rows; l; l = l->next) |
1148 |
|
✗ |
adw_preferences_group_remove (self->handler_link_group, l->data); |
1149 |
|
✗ |
g_clear_pointer (&self->link_handler_rows, g_list_free); |
1150 |
|
✗ |
} |
1151 |
|
|
|
1152 |
|
|
static void |
1153 |
|
✗ |
update_handler_dialog (CcApplicationsPanel *self, |
1154 |
|
|
GAppInfo *info) |
1155 |
|
|
{ |
1156 |
|
✗ |
g_autofree gchar *header_title = NULL; |
1157 |
|
✗ |
g_autoptr(GHashTable) hash = NULL; |
1158 |
|
|
const gchar **types; |
1159 |
|
✗ |
guint n_associations = 0; |
1160 |
|
|
gint i; |
1161 |
|
|
|
1162 |
|
✗ |
remove_all_handler_rows (self); |
1163 |
|
|
|
1164 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->handler_row), FALSE); |
1165 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->handler_file_group), FALSE); |
1166 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->handler_link_group), FALSE); |
1167 |
|
|
|
1168 |
|
✗ |
types = g_app_info_get_supported_types (info); |
1169 |
|
✗ |
if (types == NULL || types[0] == NULL) |
1170 |
|
✗ |
return; |
1171 |
|
|
|
1172 |
|
✗ |
hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); |
1173 |
|
|
|
1174 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->handler_reset), FALSE); |
1175 |
|
✗ |
for (i = 0; types[i]; i++) |
1176 |
|
|
{ |
1177 |
|
✗ |
g_autofree gchar *ctype = g_content_type_from_mime_type (types[i]); |
1178 |
|
|
|
1179 |
|
✗ |
if (g_hash_table_contains (hash, ctype)) |
1180 |
|
✗ |
continue; |
1181 |
|
|
|
1182 |
|
✗ |
if (!app_info_recommended_for (info, ctype)) |
1183 |
|
|
{ |
1184 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->handler_reset), TRUE); |
1185 |
|
✗ |
continue; |
1186 |
|
|
} |
1187 |
|
|
|
1188 |
|
✗ |
add_handler_row (self, ctype); |
1189 |
|
✗ |
g_hash_table_add (hash, g_steal_pointer (&ctype)); |
1190 |
|
|
|
1191 |
|
✗ |
n_associations++; |
1192 |
|
|
} |
1193 |
|
|
|
1194 |
|
✗ |
if (n_associations > 0) |
1195 |
|
|
{ |
1196 |
|
✗ |
g_autofree gchar *types_number = NULL; |
1197 |
|
|
|
1198 |
|
✗ |
types_number = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, |
1199 |
|
|
"%u type", |
1200 |
|
|
"%u types", |
1201 |
|
|
n_associations), |
1202 |
|
|
n_associations); |
1203 |
|
✗ |
cc_list_row_set_secondary_label (self->handler_row, types_number); |
1204 |
|
|
} |
1205 |
|
|
|
1206 |
|
✗ |
header_title = g_strdup_printf (_("<b>%s</b> is used to open the following types of files and links."), |
1207 |
|
|
g_app_info_get_display_name (info)); |
1208 |
|
✗ |
adw_preferences_page_set_description (self->handler_page, header_title); |
1209 |
|
|
} |
1210 |
|
|
|
1211 |
|
|
/* --- usage section --- */ |
1212 |
|
|
|
1213 |
|
|
static void |
1214 |
|
✗ |
on_items_changed_cb (GListModel *list, |
1215 |
|
|
guint position, |
1216 |
|
|
guint removed, |
1217 |
|
|
guint added, |
1218 |
|
|
gpointer data) |
1219 |
|
|
{ |
1220 |
|
✗ |
CcApplicationsPanel *self = data; |
1221 |
|
|
|
1222 |
|
✗ |
if (g_list_model_get_n_items (list) == 0) |
1223 |
|
✗ |
gtk_stack_set_visible_child (self->app_listbox_stack, |
1224 |
|
|
self->no_apps_page); |
1225 |
|
|
else |
1226 |
|
✗ |
gtk_stack_set_visible_child (self->app_listbox_stack, |
1227 |
|
✗ |
GTK_WIDGET (self->app_listbox)); |
1228 |
|
✗ |
} |
1229 |
|
|
|
1230 |
|
|
static void |
1231 |
|
✗ |
update_total_size (CcApplicationsPanel *self) |
1232 |
|
|
{ |
1233 |
|
✗ |
g_autofree gchar *formatted_size = NULL; |
1234 |
|
|
guint64 total; |
1235 |
|
|
|
1236 |
|
✗ |
total = self->app_size + self->data_size + self->cache_size; |
1237 |
|
✗ |
formatted_size = g_format_size (total); |
1238 |
|
✗ |
g_object_set (self->total, "info", formatted_size, NULL); |
1239 |
|
|
|
1240 |
|
✗ |
cc_list_row_set_secondary_label (self->storage, formatted_size); |
1241 |
|
✗ |
} |
1242 |
|
|
|
1243 |
|
|
static void |
1244 |
|
✗ |
set_cache_size (GObject *source, |
1245 |
|
|
GAsyncResult *res, |
1246 |
|
|
gpointer data) |
1247 |
|
|
{ |
1248 |
|
✗ |
CcApplicationsPanel *self = data; |
1249 |
|
✗ |
g_autofree gchar *formatted_size = NULL; |
1250 |
|
|
guint64 size; |
1251 |
|
✗ |
g_autoptr(GError) error = NULL; |
1252 |
|
|
|
1253 |
|
✗ |
if (!file_size_finish (G_FILE (source), res, &size, &error)) |
1254 |
|
|
{ |
1255 |
|
✗ |
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
1256 |
|
✗ |
g_warning ("Failed to get flatpak cache size: %s", error->message); |
1257 |
|
✗ |
return; |
1258 |
|
|
} |
1259 |
|
✗ |
self->cache_size = size; |
1260 |
|
|
|
1261 |
|
✗ |
formatted_size = g_format_size (self->cache_size); |
1262 |
|
✗ |
g_object_set (self->cache, "info", formatted_size, NULL); |
1263 |
|
|
|
1264 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->clear_cache_button), self->cache_size > 0); |
1265 |
|
|
|
1266 |
|
✗ |
update_total_size (self); |
1267 |
|
|
} |
1268 |
|
|
|
1269 |
|
|
static void |
1270 |
|
✗ |
update_cache_row (CcApplicationsPanel *self, |
1271 |
|
|
const gchar *app_id) |
1272 |
|
|
{ |
1273 |
|
✗ |
g_autoptr(GFile) dir = get_flatpak_app_dir (app_id, "cache"); |
1274 |
|
✗ |
g_object_set (self->cache, "info", "...", NULL); |
1275 |
|
✗ |
file_size_async (dir, cc_panel_get_cancellable (CC_PANEL (self)), set_cache_size, self); |
1276 |
|
✗ |
} |
1277 |
|
|
|
1278 |
|
|
static void |
1279 |
|
✗ |
set_data_size (GObject *source, |
1280 |
|
|
GAsyncResult *res, |
1281 |
|
|
gpointer data) |
1282 |
|
|
{ |
1283 |
|
✗ |
CcApplicationsPanel *self = data; |
1284 |
|
✗ |
g_autofree gchar *formatted_size = NULL; |
1285 |
|
|
guint64 size; |
1286 |
|
✗ |
g_autoptr(GError) error = NULL; |
1287 |
|
|
|
1288 |
|
✗ |
if (!file_size_finish (G_FILE (source), res, &size, &error)) |
1289 |
|
|
{ |
1290 |
|
✗ |
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
1291 |
|
✗ |
g_warning ("Failed to get flatpak data size: %s", error->message); |
1292 |
|
✗ |
return; |
1293 |
|
|
} |
1294 |
|
✗ |
self->data_size = size; |
1295 |
|
|
|
1296 |
|
✗ |
formatted_size = g_format_size (self->data_size); |
1297 |
|
✗ |
g_object_set (self->data, "info", formatted_size, NULL); |
1298 |
|
|
|
1299 |
|
✗ |
update_total_size (self); |
1300 |
|
|
} |
1301 |
|
|
|
1302 |
|
|
static void |
1303 |
|
✗ |
update_data_row (CcApplicationsPanel *self, |
1304 |
|
|
const gchar *app_id) |
1305 |
|
|
{ |
1306 |
|
✗ |
g_autoptr(GFile) dir = get_flatpak_app_dir (app_id, "data"); |
1307 |
|
|
|
1308 |
|
✗ |
g_object_set (self->data, "info", "...", NULL); |
1309 |
|
✗ |
file_size_async (dir, cc_panel_get_cancellable (CC_PANEL (self)), set_data_size, self); |
1310 |
|
✗ |
} |
1311 |
|
|
|
1312 |
|
|
static void |
1313 |
|
✗ |
cache_cleared (GObject *source, |
1314 |
|
|
GAsyncResult *res, |
1315 |
|
|
gpointer data) |
1316 |
|
|
{ |
1317 |
|
✗ |
CcApplicationsPanel *self = data; |
1318 |
|
✗ |
g_autoptr(GError) error = NULL; |
1319 |
|
|
|
1320 |
|
✗ |
if (!file_remove_finish (G_FILE (source), res, &error)) |
1321 |
|
|
{ |
1322 |
|
✗ |
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
1323 |
|
✗ |
g_warning ("Failed to remove cache: %s", error->message); |
1324 |
|
✗ |
return; |
1325 |
|
|
} |
1326 |
|
|
|
1327 |
|
✗ |
update_cache_row (self, self->current_app_id); |
1328 |
|
|
} |
1329 |
|
|
|
1330 |
|
|
static void |
1331 |
|
✗ |
clear_cache_cb (CcApplicationsPanel *self) |
1332 |
|
|
{ |
1333 |
|
✗ |
g_autoptr(GFile) dir = NULL; |
1334 |
|
|
|
1335 |
|
✗ |
if (self->current_app_id == NULL) |
1336 |
|
✗ |
return; |
1337 |
|
|
|
1338 |
|
✗ |
dir = get_flatpak_app_dir (self->current_app_id, "cache"); |
1339 |
|
✗ |
file_remove_async (dir, cc_panel_get_cancellable (CC_PANEL (self)), cache_cleared, self); |
1340 |
|
|
} |
1341 |
|
|
|
1342 |
|
|
static void |
1343 |
|
✗ |
update_app_row (CcApplicationsPanel *self, |
1344 |
|
|
const gchar *app_id) |
1345 |
|
|
{ |
1346 |
|
✗ |
g_autofree gchar *formatted_size = NULL; |
1347 |
|
|
|
1348 |
|
✗ |
if (g_str_has_prefix (app_id, PORTAL_SNAP_PREFIX)) |
1349 |
|
✗ |
self->app_size = get_snap_app_size (app_id + strlen (PORTAL_SNAP_PREFIX)); |
1350 |
|
|
else |
1351 |
|
✗ |
self->app_size = get_flatpak_app_size (app_id); |
1352 |
|
✗ |
formatted_size = g_format_size (self->app_size); |
1353 |
|
✗ |
g_object_set (self->app, "info", formatted_size, NULL); |
1354 |
|
✗ |
update_total_size (self); |
1355 |
|
✗ |
} |
1356 |
|
|
|
1357 |
|
|
static void |
1358 |
|
✗ |
update_app_sizes (CcApplicationsPanel *self, |
1359 |
|
|
const gchar *app_id) |
1360 |
|
|
{ |
1361 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->clear_cache_button), FALSE); |
1362 |
|
|
|
1363 |
|
✗ |
self->app_size = self->data_size = self->cache_size = 0; |
1364 |
|
|
|
1365 |
|
✗ |
update_app_row (self, app_id); |
1366 |
|
✗ |
update_cache_row (self, app_id); |
1367 |
|
✗ |
update_data_row (self, app_id); |
1368 |
|
✗ |
} |
1369 |
|
|
|
1370 |
|
|
static void |
1371 |
|
✗ |
update_usage_section (CcApplicationsPanel *self, |
1372 |
|
|
GAppInfo *info) |
1373 |
|
|
{ |
1374 |
|
✗ |
g_autofree gchar *portal_app_id = get_portal_app_id (info); |
1375 |
|
✗ |
gboolean has_builtin = FALSE; |
1376 |
|
|
|
1377 |
|
✗ |
if (portal_app_id != NULL) |
1378 |
|
✗ |
update_app_sizes (self, portal_app_id); |
1379 |
|
|
|
1380 |
|
✗ |
remove_static_permissions (self); |
1381 |
|
✗ |
has_builtin = add_static_permissions (self, info, portal_app_id); |
1382 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->other_permissions_section), has_builtin); |
1383 |
|
|
|
1384 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->usage_section), portal_app_id || has_builtin); |
1385 |
|
✗ |
} |
1386 |
|
|
|
1387 |
|
|
/* --- panel setup --- */ |
1388 |
|
|
|
1389 |
|
|
static void |
1390 |
|
✗ |
update_panel (CcApplicationsPanel *self, |
1391 |
|
|
GtkListBoxRow *row) |
1392 |
|
|
{ |
1393 |
|
|
GAppInfo *info; |
1394 |
|
|
|
1395 |
|
✗ |
if (self->perm_store == NULL) |
1396 |
|
|
{ |
1397 |
|
|
/* Async permission store not initialized, row will be re-activated in the callback */ |
1398 |
|
✗ |
self->perm_store_pending_row = row; |
1399 |
|
✗ |
return; |
1400 |
|
|
} |
1401 |
|
|
|
1402 |
|
✗ |
if (row == NULL) |
1403 |
|
|
{ |
1404 |
|
✗ |
g_message ("No app selected, try again"); |
1405 |
|
✗ |
return; |
1406 |
|
|
} |
1407 |
|
|
|
1408 |
|
✗ |
info = cc_applications_row_get_info (CC_APPLICATIONS_ROW (row)); |
1409 |
|
|
|
1410 |
|
✗ |
adw_navigation_page_set_title (self->app_settings_page, |
1411 |
|
|
g_app_info_get_display_name (info)); |
1412 |
|
✗ |
adw_navigation_view_push_by_tag(self->navigation_view, "settings-box"); |
1413 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->view_details_button), gnome_software_is_installed ()); |
1414 |
|
|
|
1415 |
|
✗ |
g_clear_pointer (&self->current_app_id, g_free); |
1416 |
|
✗ |
g_clear_pointer (&self->current_portal_app_id, g_free); |
1417 |
|
|
|
1418 |
|
✗ |
update_header_section (self, info); |
1419 |
|
✗ |
update_integration_section (self, info); |
1420 |
|
✗ |
update_handler_dialog (self, info); |
1421 |
|
✗ |
update_usage_section (self, info); |
1422 |
|
|
|
1423 |
|
✗ |
g_set_object (&self->current_app_info, info); |
1424 |
|
✗ |
self->current_app_id = get_app_id (info); |
1425 |
|
✗ |
self->current_portal_app_id = get_portal_app_id (info); |
1426 |
|
|
} |
1427 |
|
|
|
1428 |
|
|
|
1429 |
|
|
static gint |
1430 |
|
✗ |
compare_rows (gconstpointer a, |
1431 |
|
|
gconstpointer b, |
1432 |
|
|
gpointer data) |
1433 |
|
|
{ |
1434 |
|
✗ |
GAppInfo *item1 = (GAppInfo *) a; |
1435 |
|
✗ |
GAppInfo *item2 = (GAppInfo *) b; |
1436 |
|
|
|
1437 |
|
✗ |
g_autofree gchar *key1 = NULL; |
1438 |
|
✗ |
g_autofree gchar *key2 = NULL; |
1439 |
|
|
|
1440 |
|
✗ |
key1 = g_utf8_casefold (g_app_info_get_display_name (item1), -1); |
1441 |
|
✗ |
key2 = g_utf8_casefold (g_app_info_get_display_name (item2), -1); |
1442 |
|
|
|
1443 |
|
✗ |
const gchar *sort_key1 = g_utf8_collate_key (key1, -1); |
1444 |
|
✗ |
const gchar *sort_key2 = g_utf8_collate_key (key2, -1); |
1445 |
|
|
|
1446 |
|
✗ |
return strcmp (sort_key1, sort_key2); |
1447 |
|
|
} |
1448 |
|
|
|
1449 |
|
|
static void |
1450 |
|
✗ |
populate_applications (CcApplicationsPanel *self) |
1451 |
|
|
{ |
1452 |
|
✗ |
g_autolist(GObject) infos = NULL; |
1453 |
|
|
GList *l; |
1454 |
|
|
|
1455 |
|
✗ |
g_list_store_remove_all (G_LIST_STORE (self->app_model)); |
1456 |
|
|
#ifdef HAVE_MALCONTENT |
1457 |
|
|
g_signal_handler_block (self->manager, self->app_filter_id); |
1458 |
|
|
#endif |
1459 |
|
|
|
1460 |
|
✗ |
infos = g_app_info_get_all (); |
1461 |
|
|
|
1462 |
|
✗ |
if (!infos) |
1463 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->app_search_entry), 0); |
1464 |
|
|
else |
1465 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->app_search_entry), 1); |
1466 |
|
|
|
1467 |
|
✗ |
for (l = infos; l; l = l->next) |
1468 |
|
|
{ |
1469 |
|
✗ |
GAppInfo *info = l->data; |
1470 |
|
|
GtkWidget *row; |
1471 |
|
✗ |
g_autofree gchar *id = NULL; |
1472 |
|
|
|
1473 |
|
✗ |
if (!g_app_info_should_show (info)) |
1474 |
|
✗ |
continue; |
1475 |
|
|
|
1476 |
|
|
#ifdef HAVE_MALCONTENT |
1477 |
|
|
if (!mct_app_filter_is_appinfo_allowed (self->app_filter, info)) |
1478 |
|
|
continue; |
1479 |
|
|
#endif |
1480 |
|
|
|
1481 |
|
✗ |
row = GTK_WIDGET (cc_applications_row_new (info)); |
1482 |
|
✗ |
g_list_store_insert_sorted (G_LIST_STORE (self->app_model), info, compare_rows, NULL); |
1483 |
|
|
|
1484 |
|
✗ |
id = get_app_id (info); |
1485 |
|
✗ |
if (g_strcmp0 (id, self->current_app_id) == 0) |
1486 |
|
✗ |
gtk_list_box_select_row (self->app_listbox, GTK_LIST_BOX_ROW (row)); |
1487 |
|
|
} |
1488 |
|
|
#ifdef HAVE_MALCONTENT |
1489 |
|
|
g_signal_handler_unblock (self->manager, self->app_filter_id); |
1490 |
|
|
#endif |
1491 |
|
✗ |
} |
1492 |
|
|
|
1493 |
|
|
static gboolean |
1494 |
|
✗ |
filter_app_rows (GObject *item, |
1495 |
|
|
gpointer data) |
1496 |
|
|
{ |
1497 |
|
✗ |
CcApplicationsPanel *self = CC_APPLICATIONS_PANEL (data); |
1498 |
|
✗ |
g_autofree gchar *app_name = NULL; |
1499 |
|
✗ |
g_autofree gchar *search_text = NULL; |
1500 |
|
|
const gchar *text; |
1501 |
|
✗ |
GAppInfo *info = G_APP_INFO (item); |
1502 |
|
|
|
1503 |
|
✗ |
text = gtk_editable_get_text (GTK_EDITABLE (self->app_search_entry)); |
1504 |
|
|
|
1505 |
|
|
/* Only filter after the second character */ |
1506 |
|
✗ |
if (g_utf8_strlen (text, -1) < 2) |
1507 |
|
✗ |
return TRUE; |
1508 |
|
|
|
1509 |
|
✗ |
app_name = cc_util_normalize_casefold_and_unaccent (g_app_info_get_name (info)); |
1510 |
|
✗ |
search_text = cc_util_normalize_casefold_and_unaccent (text); |
1511 |
|
|
|
1512 |
|
✗ |
return g_strstr_len (app_name, -1, search_text) != NULL; |
1513 |
|
|
} |
1514 |
|
|
|
1515 |
|
|
#ifdef HAVE_MALCONTENT |
1516 |
|
|
static void |
1517 |
|
|
app_filter_changed_cb (MctAppFilter *app_filter, |
1518 |
|
|
uid_t uid, |
1519 |
|
|
CcApplicationsPanel *self) |
1520 |
|
|
{ |
1521 |
|
|
populate_applications (self); |
1522 |
|
|
} |
1523 |
|
|
#endif |
1524 |
|
|
|
1525 |
|
|
static void |
1526 |
|
✗ |
apps_changed (CcApplicationsPanel *self) |
1527 |
|
|
{ |
1528 |
|
✗ |
populate_applications (self); |
1529 |
|
✗ |
} |
1530 |
|
|
|
1531 |
|
|
static void |
1532 |
|
✗ |
row_activated_cb (CcApplicationsPanel *self, |
1533 |
|
|
GtkListBoxRow *row) |
1534 |
|
|
{ |
1535 |
|
✗ |
update_panel (self, row); |
1536 |
|
✗ |
} |
1537 |
|
|
|
1538 |
|
|
static void |
1539 |
|
✗ |
on_perm_store_ready (GObject *source_object, |
1540 |
|
|
GAsyncResult *res, |
1541 |
|
|
gpointer data) |
1542 |
|
|
{ |
1543 |
|
✗ |
CcApplicationsPanel *self = data; |
1544 |
|
|
GDBusProxy *proxy; |
1545 |
|
✗ |
g_autoptr(GError) error = NULL; |
1546 |
|
|
|
1547 |
|
✗ |
proxy = g_dbus_proxy_new_for_bus_finish (res, &error); |
1548 |
|
✗ |
if (proxy == NULL) |
1549 |
|
|
{ |
1550 |
|
✗ |
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
1551 |
|
✗ |
g_warning ("Failed to connect to portal permission store: %s", |
1552 |
|
|
error->message); |
1553 |
|
✗ |
return; |
1554 |
|
|
} |
1555 |
|
|
|
1556 |
|
✗ |
self->perm_store = proxy; |
1557 |
|
|
|
1558 |
|
✗ |
if (self->perm_store_pending_row) |
1559 |
|
✗ |
g_signal_emit_by_name (self->perm_store_pending_row, "activate"); |
1560 |
|
|
|
1561 |
|
✗ |
self->perm_store_pending_row = NULL; |
1562 |
|
|
} |
1563 |
|
|
|
1564 |
|
|
static void |
1565 |
|
✗ |
select_app (CcApplicationsPanel *self, |
1566 |
|
|
const gchar *app_id, |
1567 |
|
|
gboolean emit_activate) |
1568 |
|
|
{ |
1569 |
|
|
GtkWidget *child; |
1570 |
|
|
|
1571 |
|
✗ |
for (child = gtk_widget_get_first_child (GTK_WIDGET (self->app_listbox)); |
1572 |
|
✗ |
child; |
1573 |
|
✗ |
child = gtk_widget_get_next_sibling (child)) |
1574 |
|
|
{ |
1575 |
|
✗ |
CcApplicationsRow *row = CC_APPLICATIONS_ROW (child); |
1576 |
|
✗ |
GAppInfo *info = cc_applications_row_get_info (row); |
1577 |
|
✗ |
if (g_str_has_prefix (g_app_info_get_id (info), app_id)) |
1578 |
|
|
{ |
1579 |
|
✗ |
gtk_list_box_select_row (self->app_listbox, GTK_LIST_BOX_ROW (row)); |
1580 |
|
✗ |
if (emit_activate) |
1581 |
|
✗ |
g_signal_emit_by_name (row, "activate"); |
1582 |
|
✗ |
break; |
1583 |
|
|
} |
1584 |
|
|
} |
1585 |
|
✗ |
} |
1586 |
|
|
|
1587 |
|
|
static void |
1588 |
|
✗ |
on_launch_button_clicked_cb (CcApplicationsPanel *self) |
1589 |
|
|
{ |
1590 |
|
✗ |
g_autoptr(GdkAppLaunchContext) context = NULL; |
1591 |
|
✗ |
g_autoptr(GError) error = NULL; |
1592 |
|
|
GdkDisplay *display; |
1593 |
|
|
|
1594 |
|
✗ |
if (!self->current_app_info) |
1595 |
|
✗ |
return; |
1596 |
|
|
|
1597 |
|
✗ |
display = gtk_widget_get_display (GTK_WIDGET (self)); |
1598 |
|
✗ |
context = gdk_display_get_app_launch_context (display); |
1599 |
|
|
|
1600 |
|
✗ |
g_app_info_launch (self->current_app_info, |
1601 |
|
|
NULL, |
1602 |
|
✗ |
G_APP_LAUNCH_CONTEXT (context), |
1603 |
|
|
&error); |
1604 |
|
|
|
1605 |
|
✗ |
if (error) |
1606 |
|
✗ |
g_warning ("Error launching app: %s", error->message); |
1607 |
|
|
} |
1608 |
|
|
|
1609 |
|
|
static void |
1610 |
|
✗ |
on_app_search_entry_activated_cb (CcApplicationsPanel *self) |
1611 |
|
|
{ |
1612 |
|
|
GtkListBoxRow *row; |
1613 |
|
|
|
1614 |
|
✗ |
row = gtk_list_box_get_row_at_y (self->app_listbox, 0); |
1615 |
|
|
|
1616 |
|
✗ |
if (!row) |
1617 |
|
✗ |
return; |
1618 |
|
|
|
1619 |
|
|
/* Show the app */ |
1620 |
|
✗ |
gtk_list_box_select_row (self->app_listbox, row); |
1621 |
|
✗ |
g_signal_emit_by_name (row, "activate"); |
1622 |
|
|
|
1623 |
|
|
/* Cleanup the entry */ |
1624 |
|
✗ |
gtk_editable_set_text (GTK_EDITABLE (self->app_search_entry), ""); |
1625 |
|
✗ |
gtk_widget_grab_focus (GTK_WIDGET (self->app_search_entry)); |
1626 |
|
|
} |
1627 |
|
|
|
1628 |
|
|
static void |
1629 |
|
✗ |
on_app_search_entry_search_changed_cb (CcApplicationsPanel *self) |
1630 |
|
|
{ |
1631 |
|
✗ |
gtk_filter_changed (self->filter, GTK_FILTER_CHANGE_DIFFERENT); |
1632 |
|
✗ |
} |
1633 |
|
|
|
1634 |
|
|
static void |
1635 |
|
✗ |
on_app_search_entry_search_stopped_cb (CcApplicationsPanel *self) |
1636 |
|
|
{ |
1637 |
|
✗ |
gtk_editable_set_text (GTK_EDITABLE (self->app_search_entry), ""); |
1638 |
|
✗ |
} |
1639 |
|
|
|
1640 |
|
|
static void |
1641 |
|
✗ |
cc_applications_panel_dispose (GObject *object) |
1642 |
|
|
{ |
1643 |
|
✗ |
CcApplicationsPanel *self = CC_APPLICATIONS_PANEL (object); |
1644 |
|
|
|
1645 |
|
✗ |
g_clear_pointer (&self->sandbox_info_button, gtk_widget_unparent); |
1646 |
|
|
|
1647 |
|
✗ |
remove_all_handler_rows (self); |
1648 |
|
|
#ifdef HAVE_SNAP |
1649 |
|
✗ |
remove_snap_permissions (self); |
1650 |
|
|
#endif |
1651 |
|
✗ |
g_clear_object (&self->monitor); |
1652 |
|
✗ |
g_clear_object (&self->perm_store); |
1653 |
|
|
|
1654 |
|
✗ |
G_OBJECT_CLASS (cc_applications_panel_parent_class)->dispose (object); |
1655 |
|
✗ |
} |
1656 |
|
|
|
1657 |
|
|
static void |
1658 |
|
✗ |
cc_applications_panel_finalize (GObject *object) |
1659 |
|
|
{ |
1660 |
|
✗ |
CcApplicationsPanel *self = CC_APPLICATIONS_PANEL (object); |
1661 |
|
|
#ifdef HAVE_MALCONTENT |
1662 |
|
|
if (self->app_filter != NULL && self->app_filter_id != 0) |
1663 |
|
|
{ |
1664 |
|
|
g_signal_handler_disconnect (self->manager, self->app_filter_id); |
1665 |
|
|
self->app_filter_id = 0; |
1666 |
|
|
} |
1667 |
|
|
g_clear_pointer (&self->app_filter, mct_app_filter_unref); |
1668 |
|
|
|
1669 |
|
|
g_clear_object (&self->manager); |
1670 |
|
|
#endif |
1671 |
|
✗ |
g_clear_object (&self->media_handling_settings); |
1672 |
|
✗ |
g_clear_object (&self->notification_settings); |
1673 |
|
✗ |
g_clear_object (&self->location_settings); |
1674 |
|
✗ |
g_clear_object (&self->privacy_settings); |
1675 |
|
✗ |
g_clear_object (&self->search_settings); |
1676 |
|
|
|
1677 |
|
✗ |
g_clear_object (&self->current_app_info); |
1678 |
|
✗ |
g_clear_pointer (&self->current_app_id, g_free); |
1679 |
|
✗ |
g_clear_pointer (&self->current_portal_app_id, g_free); |
1680 |
|
✗ |
g_clear_pointer (&self->globs, g_hash_table_unref); |
1681 |
|
✗ |
g_clear_pointer (&self->search_providers, g_hash_table_unref); |
1682 |
|
|
|
1683 |
|
✗ |
G_OBJECT_CLASS (cc_applications_panel_parent_class)->finalize (object); |
1684 |
|
✗ |
} |
1685 |
|
|
|
1686 |
|
|
static void |
1687 |
|
✗ |
cc_applications_panel_set_property (GObject *object, |
1688 |
|
|
guint property_id, |
1689 |
|
|
const GValue *value, |
1690 |
|
|
GParamSpec *pspec) |
1691 |
|
|
{ |
1692 |
|
✗ |
switch (property_id) |
1693 |
|
|
{ |
1694 |
|
✗ |
case PROP_PARAMETERS: |
1695 |
|
|
{ |
1696 |
|
|
GVariant *parameters, *v; |
1697 |
|
✗ |
const gchar *first_arg = NULL; |
1698 |
|
|
|
1699 |
|
✗ |
parameters = g_value_get_variant (value); |
1700 |
|
✗ |
if (parameters == NULL) |
1701 |
|
✗ |
return; |
1702 |
|
|
|
1703 |
|
✗ |
if (g_variant_n_children (parameters) > 0) |
1704 |
|
|
{ |
1705 |
|
✗ |
g_variant_get_child (parameters, 0, "v", &v); |
1706 |
|
✗ |
if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)) |
1707 |
|
✗ |
first_arg = g_variant_get_string (v, NULL); |
1708 |
|
|
else |
1709 |
|
✗ |
g_warning ("Wrong type for the second argument GVariant, expected 's' but got '%s'", |
1710 |
|
|
(gchar *)g_variant_get_type (v)); |
1711 |
|
✗ |
g_variant_unref (v); |
1712 |
|
|
|
1713 |
|
✗ |
select_app (CC_APPLICATIONS_PANEL (object), first_arg, TRUE); |
1714 |
|
|
} |
1715 |
|
|
|
1716 |
|
✗ |
return; |
1717 |
|
|
} |
1718 |
|
|
} |
1719 |
|
|
|
1720 |
|
✗ |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
1721 |
|
|
} |
1722 |
|
|
|
1723 |
|
|
static void |
1724 |
|
✗ |
cc_applications_panel_constructed (GObject *object) |
1725 |
|
|
{ |
1726 |
|
✗ |
G_OBJECT_CLASS (cc_applications_panel_parent_class)->constructed (object); |
1727 |
|
✗ |
} |
1728 |
|
|
|
1729 |
|
|
static void |
1730 |
|
✗ |
cc_applications_panel_class_init (CcApplicationsPanelClass *klass) |
1731 |
|
|
{ |
1732 |
|
✗ |
GObjectClass *object_class = G_OBJECT_CLASS (klass); |
1733 |
|
✗ |
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
1734 |
|
|
|
1735 |
|
✗ |
g_type_ensure (CC_TYPE_DEFAULT_APPS_PAGE); |
1736 |
|
✗ |
g_type_ensure (CC_TYPE_REMOVABLE_MEDIA_SETTINGS); |
1737 |
|
|
|
1738 |
|
✗ |
object_class->dispose = cc_applications_panel_dispose; |
1739 |
|
✗ |
object_class->finalize = cc_applications_panel_finalize; |
1740 |
|
✗ |
object_class->constructed = cc_applications_panel_constructed; |
1741 |
|
✗ |
object_class->set_property = cc_applications_panel_set_property; |
1742 |
|
|
|
1743 |
|
✗ |
g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters"); |
1744 |
|
|
|
1745 |
|
✗ |
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-applications-panel.ui"); |
1746 |
|
|
|
1747 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, app); |
1748 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, app_icon_image); |
1749 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, app_listbox); |
1750 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, app_name_label); |
1751 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, app_search_entry); |
1752 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, app_settings_page); |
1753 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, other_permissions_section); |
1754 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, autorun_never_row); |
1755 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, builtin); |
1756 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, builtin_dialog); |
1757 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, builtin_page); |
1758 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, builtin_list); |
1759 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, cache); |
1760 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, camera); |
1761 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, clear_cache_button); |
1762 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, data); |
1763 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, default_apps_page); |
1764 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_apps_page); |
1765 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, app_listbox_stack); |
1766 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, handler_dialog); |
1767 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, handler_page); |
1768 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, handler_file_group); |
1769 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, handler_link_group); |
1770 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, handler_row); |
1771 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, handler_reset); |
1772 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, install_button); |
1773 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, integration_section); |
1774 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, launch_button); |
1775 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, location); |
1776 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, microphone); |
1777 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, navigation_view); |
1778 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_camera); |
1779 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_location); |
1780 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_microphone); |
1781 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_search); |
1782 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_sound); |
1783 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, notification); |
1784 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, background); |
1785 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, wallpaper); |
1786 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, removable_media_settings); |
1787 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, sandbox_banner); |
1788 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, sandbox_info_button); |
1789 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, screenshot); |
1790 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, shortcuts); |
1791 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, search); |
1792 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, sound); |
1793 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, storage); |
1794 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, storage_dialog); |
1795 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, total); |
1796 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, usage_section); |
1797 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, view_details_button); |
1798 |
|
|
|
1799 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, camera_cb); |
1800 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, location_cb); |
1801 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, microphone_cb); |
1802 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, search_cb); |
1803 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, notification_cb); |
1804 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, background_cb); |
1805 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, wallpaper_cb); |
1806 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, screenshot_cb); |
1807 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, shortcuts_cb); |
1808 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, privacy_link_cb); |
1809 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, sound_cb); |
1810 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, clear_cache_cb); |
1811 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, open_software_cb); |
1812 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, handler_reset_cb); |
1813 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_launch_button_clicked_cb); |
1814 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_app_search_entry_activated_cb); |
1815 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_app_search_entry_search_changed_cb); |
1816 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_app_search_entry_search_stopped_cb); |
1817 |
|
✗ |
} |
1818 |
|
|
|
1819 |
|
|
static GtkWidget * |
1820 |
|
✗ |
app_row_new (gpointer item, |
1821 |
|
|
gpointer user_data) |
1822 |
|
|
{ |
1823 |
|
✗ |
GAppInfo *info = item; |
1824 |
|
|
|
1825 |
|
✗ |
return GTK_WIDGET (cc_applications_row_new (info)); |
1826 |
|
|
} |
1827 |
|
|
|
1828 |
|
|
static void |
1829 |
|
✗ |
cc_applications_panel_init (CcApplicationsPanel *self) |
1830 |
|
|
{ |
1831 |
|
|
#ifdef HAVE_MALCONTENT |
1832 |
|
|
g_autoptr(GDBusConnection) system_bus = NULL; |
1833 |
|
|
g_autoptr(GError) error = NULL; |
1834 |
|
|
#endif |
1835 |
|
|
|
1836 |
|
✗ |
g_resources_register (cc_applications_get_resource ()); |
1837 |
|
|
|
1838 |
|
✗ |
g_type_ensure (CC_TYPE_INFO_ROW); |
1839 |
|
✗ |
g_type_ensure (CC_TYPE_LIST_ROW); |
1840 |
|
|
|
1841 |
|
✗ |
gtk_widget_init_template (GTK_WIDGET (self)); |
1842 |
|
|
|
1843 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->install_button), gnome_software_is_installed ()); |
1844 |
|
|
|
1845 |
|
✗ |
g_signal_connect_object (self->app_listbox, "row-activated", |
1846 |
|
|
G_CALLBACK (row_activated_cb), self, G_CONNECT_SWAPPED); |
1847 |
|
|
|
1848 |
|
✗ |
g_signal_connect_object (self->view_details_button, |
1849 |
|
|
"clicked", |
1850 |
|
|
G_CALLBACK (open_software_cb), |
1851 |
|
|
self, |
1852 |
|
|
G_CONNECT_SWAPPED); |
1853 |
|
|
|
1854 |
|
✗ |
self->filter = GTK_FILTER (gtk_custom_filter_new ((GtkCustomFilterFunc) filter_app_rows, |
1855 |
|
|
self, NULL)); |
1856 |
|
|
|
1857 |
|
✗ |
self->app_model = G_LIST_MODEL (g_list_store_new (G_TYPE_APP_INFO)); |
1858 |
|
✗ |
self->filter_model = G_LIST_MODEL (gtk_filter_list_model_new (self->app_model, |
1859 |
|
✗ |
GTK_FILTER (self->filter))); |
1860 |
|
✗ |
g_signal_connect (self->filter_model, "items-changed", |
1861 |
|
|
G_CALLBACK (on_items_changed_cb), self); |
1862 |
|
|
|
1863 |
|
✗ |
gtk_list_box_bind_model (self->app_listbox, |
1864 |
|
|
self->filter_model, |
1865 |
|
|
app_row_new, |
1866 |
|
|
NULL, |
1867 |
|
|
NULL); |
1868 |
|
|
|
1869 |
|
✗ |
self->location_settings = g_settings_new ("org.gnome.system.location"); |
1870 |
|
✗ |
self->privacy_settings = g_settings_new ("org.gnome.desktop.privacy"); |
1871 |
|
✗ |
self->search_settings = g_settings_new ("org.gnome.desktop.search-providers"); |
1872 |
|
✗ |
self->media_handling_settings = g_settings_new ("org.gnome.desktop.media-handling"); |
1873 |
|
|
|
1874 |
|
✗ |
g_settings_bind (self->media_handling_settings, |
1875 |
|
|
"autorun-never", |
1876 |
|
✗ |
self->autorun_never_row, |
1877 |
|
|
"active", |
1878 |
|
|
G_SETTINGS_BIND_INVERT_BOOLEAN); |
1879 |
|
|
|
1880 |
|
|
#ifdef HAVE_MALCONTENT |
1881 |
|
|
/* FIXME: should become asynchronous */ |
1882 |
|
|
system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, self->cancellable, &error); |
1883 |
|
|
if (system_bus == NULL) |
1884 |
|
|
{ |
1885 |
|
|
g_warning ("Error getting system bus while setting up app permissions: %s", error->message); |
1886 |
|
|
return; |
1887 |
|
|
} |
1888 |
|
|
|
1889 |
|
|
/* Load the user’s parental controls settings too, so we can filter the list. */ |
1890 |
|
|
self->manager = mct_manager_new (system_bus); |
1891 |
|
|
self->app_filter = mct_manager_get_app_filter (self->manager, |
1892 |
|
|
getuid (), |
1893 |
|
|
MCT_MANAGER_GET_VALUE_FLAGS_NONE, |
1894 |
|
|
self->cancellable, |
1895 |
|
|
&error); |
1896 |
|
|
if (error) |
1897 |
|
|
{ |
1898 |
|
|
g_warning ("Error retrieving app filter: %s", error->message); |
1899 |
|
|
return; |
1900 |
|
|
} |
1901 |
|
|
|
1902 |
|
|
self->app_filter_id = g_signal_connect (self->manager, "app-filter-changed", |
1903 |
|
|
G_CALLBACK (app_filter_changed_cb), self); |
1904 |
|
|
#endif |
1905 |
|
✗ |
populate_applications (self); |
1906 |
|
|
|
1907 |
|
✗ |
self->monitor = g_app_info_monitor_get (); |
1908 |
|
✗ |
self->monitor_id = g_signal_connect_object (self->monitor, "changed", G_CALLBACK (apps_changed), self, G_CONNECT_SWAPPED); |
1909 |
|
|
|
1910 |
|
✗ |
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, |
1911 |
|
|
G_DBUS_PROXY_FLAGS_NONE, |
1912 |
|
|
NULL, |
1913 |
|
|
"org.freedesktop.impl.portal.PermissionStore", |
1914 |
|
|
"/org/freedesktop/impl/portal/PermissionStore", |
1915 |
|
|
"org.freedesktop.impl.portal.PermissionStore", |
1916 |
|
|
cc_panel_get_cancellable (CC_PANEL (self)), |
1917 |
|
|
on_perm_store_ready, |
1918 |
|
|
self); |
1919 |
|
|
|
1920 |
|
✗ |
self->globs = parse_globs (); |
1921 |
|
✗ |
self->search_providers = parse_search_providers (); |
1922 |
|
✗ |
} |
1923 |
|
|
|