1 /* Copyright (C) 2005-2006 Fabio Marzocca <thesaltydog@gmail.com>
2 * Copyright (C) 2012-2021 MATE Developers
3 *
4 * This file is part of MATE Utils.
5 *
6 * MATE Utils is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MATE Utils is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 #include <glib/gstdio.h>
29 #include <glibtop/mountlist.h>
30 #include <glibtop/fsusage.h>
31 #include "baobab.h"
32 #include "baobab-utils.h"
33 #include "baobab-prefs.h"
34
35 #define BAOBAB_PREFERENCES_UI_RESOURCE "/org/mate/disk-usage-analyzer/baobab-dialog-scan-props.ui"
36 #define GET_WIDGET(x) (GTK_WIDGET (gtk_builder_get_object (builder, (x))))
37
38 enum
39 {
40 COL_CHECK,
41 COL_DEVICE,
42 COL_MOUNT_D,
43 COL_MOUNT,
44 COL_TYPE,
45 COL_FS_SIZE,
46 COL_FS_AVAIL,
47 TOT_COLUMNS
48 };
49
50 static gboolean
add_excluded_item(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,GPtrArray * uris)51 add_excluded_item (GtkTreeModel *model,
52 GtkTreePath *path,
53 GtkTreeIter *iter,
54 GPtrArray *uris)
55 {
56 gchar *mount;
57 gboolean check;
58
59 gtk_tree_model_get (model,
60 iter,
61 COL_MOUNT, &mount,
62 COL_CHECK, &check,
63 -1);
64
65 if (!check) {
66 g_ptr_array_add (uris, mount);
67 }
68 else {
69 g_free (mount);
70 }
71
72 return FALSE;
73 }
74
75 static gchar **
get_excluded_locations(GtkTreeModel * model)76 get_excluded_locations (GtkTreeModel *model)
77 {
78 GPtrArray *uris;
79
80 uris = g_ptr_array_new ();
81
82 gtk_tree_model_foreach (model,
83 (GtkTreeModelForeachFunc) add_excluded_item,
84 uris);
85
86 g_ptr_array_add (uris, NULL);
87
88 return (gchar **) g_ptr_array_free (uris, FALSE);
89 }
90
91 static void
save_excluded_uris(GtkTreeModel * model)92 save_excluded_uris (GtkTreeModel *model)
93 {
94 gchar **uris;
95
96 uris = get_excluded_locations (model);
97
98 g_settings_set_strv (baobab.prefs_settings,
99 BAOBAB_SETTINGS_EXCLUDED_URIS,
100 (const gchar * const *) uris);
101
102 g_strfreev (uris);
103 }
104
105 static void
filechooser_response_cb(GtkDialog * dialog,gint response_id,GtkTreeModel * model)106 filechooser_response_cb (GtkDialog *dialog,
107 gint response_id,
108 GtkTreeModel *model)
109 {
110 switch (response_id) {
111 case GTK_RESPONSE_HELP:
112 baobab_help_display (GTK_WINDOW (baobab.window),
113 "mate-disk-usage-analyzer", "baobab-preferences");
114 break;
115 case GTK_RESPONSE_DELETE_EVENT:
116 case GTK_RESPONSE_CLOSE:
117 save_excluded_uris (model);
118 default:
119 gtk_widget_destroy (GTK_WIDGET (dialog));
120 break;
121 }
122 }
123
124 static void
check_toggled(GtkCellRendererToggle * cell,gchar * path_str,GtkTreeModel * model)125 check_toggled (GtkCellRendererToggle *cell,
126 gchar *path_str,
127 GtkTreeModel *model)
128 {
129 GtkTreeIter iter;
130 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
131 gboolean toggle;
132 gchar *mountpoint;
133
134 /* get toggled iter */
135 gtk_tree_model_get_iter (model, &iter, path);
136 gtk_tree_model_get (model,
137 &iter,
138 COL_CHECK, &toggle,
139 COL_MOUNT_D, &mountpoint,
140 -1);
141
142 /* check if root dir */
143 if (strcmp ("/", mountpoint) == 0)
144 goto clean_up;
145
146 /* set new value */
147 gtk_list_store_set (GTK_LIST_STORE (model),
148 &iter,
149 COL_CHECK, !toggle,
150 -1);
151
152 clean_up:
153 g_free (mountpoint);
154 gtk_tree_path_free (path);
155 }
156
157 static void
create_tree_props(GtkBuilder * builder,GtkTreeModel * model)158 create_tree_props (GtkBuilder *builder, GtkTreeModel *model)
159 {
160 GtkCellRenderer *cell;
161 GtkTreeViewColumn *col;
162 GtkWidget *tvw;
163
164 tvw = GET_WIDGET ("tree_view_props");
165
166 /* checkbox column */
167 cell = gtk_cell_renderer_toggle_new ();
168 g_signal_connect (cell, "toggled",
169 G_CALLBACK (check_toggled), model);
170
171 col = gtk_tree_view_column_new_with_attributes (_("Scan"), cell,
172 "active", COL_CHECK,
173 NULL);
174 gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);
175
176 /* First text column */
177 cell = gtk_cell_renderer_text_new ();
178 col = gtk_tree_view_column_new_with_attributes (_("Device"), cell,
179 "markup", COL_DEVICE,
180 "text", COL_DEVICE,
181 NULL);
182 gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);
183
184 /* second text column */
185 cell = gtk_cell_renderer_text_new ();
186 col = gtk_tree_view_column_new_with_attributes (_("Mount Point"),
187 cell, "markup",
188 COL_MOUNT_D, "text",
189 COL_MOUNT_D, NULL);
190 gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);
191
192 /* third text column */
193 cell = gtk_cell_renderer_text_new ();
194 col = gtk_tree_view_column_new_with_attributes (_("Filesystem Type"),
195 cell, "markup",
196 COL_TYPE, "text",
197 COL_TYPE, NULL);
198 gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);
199
200 /* fourth text column */
201 cell = gtk_cell_renderer_text_new ();
202 col = gtk_tree_view_column_new_with_attributes (_("Total Size"),
203 cell, "markup",
204 COL_FS_SIZE, "text",
205 COL_FS_SIZE, NULL);
206 g_object_set (G_OBJECT (cell), "xalign", (gfloat) 1.0, NULL);
207 gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);
208
209 /* fifth text column */
210 cell = gtk_cell_renderer_text_new ();
211 col = gtk_tree_view_column_new_with_attributes (_("Available"),
212 cell, "markup",
213 COL_FS_AVAIL, "text",
214 COL_FS_AVAIL, NULL);
215 g_object_set (G_OBJECT (cell), "xalign", (gfloat) 1.0, NULL);
216 gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);
217
218 gtk_tree_view_set_model (GTK_TREE_VIEW (tvw), model);
219 g_object_unref (model);
220 }
221
222 static void
fill_props_model(GtkListStore * store)223 fill_props_model (GtkListStore *store)
224 {
225 GtkTreeIter iter;
226 guint lo;
227 glibtop_mountlist mountlist;
228 glibtop_mountentry *mountentry, *mountentry_tofree;
229 guint64 fstotal, fsavail;
230
231 mountentry_tofree = glibtop_get_mountlist (&mountlist, 0);
232
233 for (lo = 0, mountentry = mountentry_tofree;
234 lo < mountlist.number;
235 lo++, mountentry++) {
236 glibtop_fsusage fsusage;
237 gchar * total, *avail;
238 GFile *file;
239 gchar *uri;
240 gboolean excluded;
241
242 struct stat buf;
243 if (g_stat (mountentry->devname,&buf) == -1)
244 continue;
245
246 glibtop_get_fsusage (&fsusage, mountentry->mountdir);
247 fstotal = fsusage.blocks * fsusage.block_size;
248 fsavail = fsusage.bfree * fsusage.block_size;
249
250 total = g_format_size(fstotal);
251 avail = g_format_size(fsavail);
252
253 file = g_file_new_for_path (mountentry->mountdir);
254 uri = g_file_get_uri (file);
255 excluded = baobab_is_excluded_location (file);
256
257 gtk_list_store_append (store, &iter);
258 gtk_list_store_set (store, &iter,
259 COL_CHECK, !excluded,
260 COL_DEVICE, mountentry->devname,
261 COL_MOUNT_D, mountentry->mountdir,
262 COL_MOUNT, uri,
263 COL_TYPE, mountentry->type,
264 COL_FS_SIZE, total,
265 COL_FS_AVAIL, avail,
266 -1);
267 g_free(total);
268 g_free(avail);
269 g_free(uri);
270 g_object_unref(file);
271 }
272
273 g_free (mountentry_tofree);
274 }
275
276 void
baobab_prefs_dialog(void)277 baobab_prefs_dialog (void)
278 {
279 GtkBuilder *builder;
280 GtkWidget *dlg;
281 GtkWidget *check_enablehome;
282 GtkListStore *model;
283 GError *error = NULL;
284
285 builder = gtk_builder_new ();
286
287 if (gtk_builder_add_from_resource (builder, BAOBAB_PREFERENCES_UI_RESOURCE, &error) == 0) {
288 g_critical ("Can't load user interface resource for the scan properties dialog: %s",
289 error->message);
290 g_object_unref (builder);
291 g_error_free (error);
292
293 return;
294 }
295
296 dlg = GET_WIDGET ("dialog_scan_props");
297
298 gtk_window_set_transient_for (GTK_WINDOW (dlg),
299 GTK_WINDOW (baobab.window));
300
301 model = gtk_list_store_new (TOT_COLUMNS,
302 G_TYPE_BOOLEAN, /* checkbox */
303 G_TYPE_STRING, /* device */
304 G_TYPE_STRING, /*mount point display */
305 G_TYPE_STRING, /* mount point uri */
306 G_TYPE_STRING, /* fs type */
307 G_TYPE_STRING, /* fs size */
308 G_TYPE_STRING /* fs avail */
309 );
310
311 create_tree_props (builder, GTK_TREE_MODEL (model));
312 fill_props_model (model);
313
314 check_enablehome = GET_WIDGET ("check_enable_home");
315 g_settings_bind (baobab.prefs_settings,
316 BAOBAB_SETTINGS_MONITOR_HOME,
317 check_enablehome, "active",
318 G_SETTINGS_BIND_DEFAULT);
319
320 g_signal_connect (dlg, "response",
321 G_CALLBACK (filechooser_response_cb), model);
322
323 gtk_widget_show_all (dlg);
324 }
325
326