1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* Copyright (C) 1998 Cesar Miquel <miquel@df.uba.ar>
3 * Copyright (C) 2004 Vincent Noel
4 * Copyright (C) 2006 Emmanuele Bassi
5 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
6 * Copyright (C) 2012-2021 MATE Developers
7 *
8 * This file is part of MATE Utils.
9 *
10 * MATE Utils is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MATE Utils is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <gtk/gtk.h>
31
32 #include "logview-prefs.h"
33
34 #define LOGVIEW_DEFAULT_HEIGHT 400
35 #define LOGVIEW_DEFAULT_WIDTH 600
36
37 /* logview settings */
38 #define LOGVIEW_SCHEMA "org.mate.system-log"
39 #define PREF_WIDTH "width"
40 #define PREF_HEIGHT "height"
41 #define PREF_LOGFILE "logfile"
42 #define PREF_LOGFILES "logfiles"
43 #define PREF_FONTSIZE "fontsize"
44 #define PREF_FILTERS "filters"
45
46 /* desktop-wide settings */
47 #define MATE_MONOSPACE_FONT_NAME "monospace-font-name"
48 #define MATE_MENUS_HAVE_TEAROFF "menus-have-tearoff"
49
50 static LogviewPrefs *singleton = NULL;
51
52 enum {
53 SYSTEM_FONT_CHANGED,
54 HAVE_TEAROFF_CHANGED,
55 LAST_SIGNAL
56 };
57
58 enum {
59 FILTER_NAME,
60 FILTER_INVISIBLE,
61 FILTER_FOREGROUND,
62 FILTER_BACKGROUND,
63 FILTER_REGEX,
64 MAX_TOKENS
65 };
66
67 static guint signals[LAST_SIGNAL] = { 0 };
68
69 struct _LogviewPrefsPrivate {
70 GSettings *logview_prefs;
71 GSettings *interface_prefs;
72
73 GHashTable *filters;
74 };
75
76 G_DEFINE_TYPE_WITH_PRIVATE (LogviewPrefs, logview_prefs, G_TYPE_OBJECT);
77
78 static void
do_finalize(GObject * obj)79 do_finalize (GObject *obj)
80 {
81 LogviewPrefs *prefs = LOGVIEW_PREFS (obj);
82
83 g_hash_table_destroy (prefs->priv->filters);
84
85 g_object_unref (prefs->priv->logview_prefs);
86 g_object_unref (prefs->priv->interface_prefs);
87
88 G_OBJECT_CLASS (logview_prefs_parent_class)->finalize (obj);
89 }
90
91 static void
logview_prefs_class_init(LogviewPrefsClass * klass)92 logview_prefs_class_init (LogviewPrefsClass *klass)
93 {
94 GObjectClass *oclass = G_OBJECT_CLASS (klass);
95
96 oclass->finalize = do_finalize;
97
98 signals[SYSTEM_FONT_CHANGED] = g_signal_new ("system-font-changed",
99 G_OBJECT_CLASS_TYPE (oclass),
100 G_SIGNAL_RUN_LAST,
101 G_STRUCT_OFFSET (LogviewPrefsClass, system_font_changed),
102 NULL, NULL,
103 g_cclosure_marshal_VOID__STRING,
104 G_TYPE_NONE, 1,
105 G_TYPE_STRING);
106 signals[HAVE_TEAROFF_CHANGED] = g_signal_new ("have-tearoff-changed",
107 G_OBJECT_CLASS_TYPE (oclass),
108 G_SIGNAL_RUN_LAST,
109 G_STRUCT_OFFSET (LogviewPrefsClass, have_tearoff_changed),
110 NULL, NULL,
111 g_cclosure_marshal_VOID__BOOLEAN,
112 G_TYPE_NONE, 1,
113 G_TYPE_BOOLEAN);
114 }
115
116 static void
have_tearoff_changed_cb(GSettings * settings,gchar * key,gpointer data)117 have_tearoff_changed_cb (GSettings *settings,
118 gchar *key,
119 gpointer data)
120 {
121 LogviewPrefs *prefs = data;
122 gboolean add_tearoffs;
123
124 add_tearoffs = g_settings_get_boolean (settings, key);
125 g_signal_emit (prefs, signals[HAVE_TEAROFF_CHANGED], 0, add_tearoffs, NULL);
126 }
127
128 static void
monospace_font_changed_cb(GSettings * settings,gchar * key,gpointer data)129 monospace_font_changed_cb (GSettings *settings,
130 gchar *key,
131 gpointer data)
132 {
133 LogviewPrefs *prefs = data;
134 gchar *monospace_font_name;
135
136 monospace_font_name = g_settings_get_string (settings, key);
137 g_signal_emit (prefs, signals[SYSTEM_FONT_CHANGED], 0, monospace_font_name, NULL);
138
139 g_free (monospace_font_name);
140 }
141
142 #define DELIMITER ":"
143
144 static void
load_filters(LogviewPrefs * prefs)145 load_filters (LogviewPrefs *prefs)
146 {
147 gchar **filters;
148 gchar **tokens;
149 const gchar *str;
150 LogviewFilter *filter;
151 GtkTextTag *tag;
152 GdkRGBA color;
153 gint idx;
154
155 filters = g_settings_get_strv (prefs->priv->logview_prefs,
156 PREF_FILTERS);
157
158 prefs->priv->filters = g_hash_table_new_full (g_str_hash, g_str_equal,
159 g_free,
160 g_object_unref);
161
162 for (idx = 0; filters[idx] != NULL; idx++) {
163 str = filters[idx];
164 tokens = g_strsplit (str, DELIMITER, MAX_TOKENS);
165 filter = logview_filter_new (tokens[FILTER_NAME], tokens[FILTER_REGEX]);
166 tag = gtk_text_tag_new (tokens[FILTER_NAME]);
167
168 g_object_set (tag, "invisible",
169 g_str_equal (tokens[FILTER_INVISIBLE], "1"), NULL);
170
171 if (strlen (tokens[FILTER_FOREGROUND])) {
172 gdk_rgba_parse (&color, tokens[FILTER_FOREGROUND]);
173 g_object_set (tag, "foreground-rgba", &color,
174 "foreground-set", TRUE, NULL);
175 }
176
177 if (strlen (tokens[FILTER_BACKGROUND])) {
178 gdk_rgba_parse (&color, tokens[FILTER_BACKGROUND]);
179 g_object_set (tag, "paragraph-background-rgba", &color,
180 "paragraph-background-set", TRUE, NULL);
181 }
182
183 g_object_set (filter, "texttag", tag, NULL);
184 g_hash_table_insert (prefs->priv->filters,
185 g_strdup(tokens[FILTER_NAME]),
186 filter);
187
188 g_object_ref (filter);
189 g_object_unref (tag);
190 g_strfreev (tokens);
191 }
192
193 g_strfreev (filters);
194 }
195
196 static void
save_filter_foreach_func(gpointer key,gpointer value,gpointer user_data)197 save_filter_foreach_func (gpointer key, gpointer value, gpointer user_data)
198 {
199 GPtrArray *filters;
200 const gchar *name;
201 LogviewFilter *filter;
202 GdkRGBA *foreground;
203 gboolean foreground_set;
204 GdkRGBA *background;
205 gboolean background_set;
206 gchar *regex, *color;
207 gboolean invisible;
208 GtkTextTag *tag;
209 GString *prefs_string;
210
211 filters = user_data;
212 filter = LOGVIEW_FILTER (value);
213 name = key;
214 color = NULL;
215
216 prefs_string = g_string_new (name);
217 g_string_append (prefs_string, DELIMITER);
218
219 g_object_get (filter,
220 "regex", ®ex,
221 "texttag", &tag,
222 NULL);
223 g_object_get (tag,
224 "foreground-set", &foreground_set,
225 "foreground-rgba", &foreground,
226 "paragraph-background-set", &background_set,
227 "paragraph-background-rgba", &background,
228 "invisible", &invisible, NULL);
229
230 if (invisible) {
231 g_string_append (prefs_string, "1" DELIMITER);
232 } else {
233 g_string_append (prefs_string, "0" DELIMITER);
234 }
235
236 if (foreground_set) {
237 color = gdk_rgba_to_string (foreground);
238 g_string_append (prefs_string, color);
239 g_free (color);
240 }
241
242 if (foreground) {
243 gdk_rgba_free (foreground);
244 }
245
246 g_string_append (prefs_string, DELIMITER);
247
248 if (background_set) {
249 color = gdk_rgba_to_string (background);
250 g_string_append (prefs_string, color);
251 g_free (color);
252 }
253
254 if (background) {
255 gdk_rgba_free (background);
256 }
257
258 g_string_append (prefs_string, DELIMITER);
259 g_string_append (prefs_string, regex);
260
261 g_free (regex);
262 g_object_unref (tag);
263
264 g_ptr_array_add (filters, g_string_free (prefs_string, FALSE));
265 }
266
267 static void
save_filters(LogviewPrefs * prefs)268 save_filters (LogviewPrefs *prefs)
269 {
270 GPtrArray *filters;
271 gchar **filters_strv;
272
273 filters = g_ptr_array_new ();
274 g_hash_table_foreach (prefs->priv->filters,
275 save_filter_foreach_func,
276 filters);
277 g_ptr_array_add (filters, NULL);
278
279 filters_strv = (gchar **) g_ptr_array_free (filters, FALSE);
280 g_settings_set_strv (prefs->priv->logview_prefs,
281 PREF_FILTERS,
282 (const gchar **) filters_strv);
283
284 g_strfreev (filters_strv);
285 }
286
287 static void
get_filters_foreach(gpointer key,gpointer value,gpointer user_data)288 get_filters_foreach (gpointer key, gpointer value, gpointer user_data)
289 {
290 GList **list;
291 list = user_data;
292 *list = g_list_append (*list, value);
293 }
294
295 static void
logview_prefs_init(LogviewPrefs * self)296 logview_prefs_init (LogviewPrefs *self)
297 {
298 LogviewPrefsPrivate *priv;
299
300 priv = self->priv = logview_prefs_get_instance_private (self);
301
302 priv->logview_prefs = g_settings_new (LOGVIEW_SCHEMA);
303 priv->interface_prefs = g_settings_new ("org.mate.interface");
304
305 g_signal_connect (priv->interface_prefs, "changed::" MATE_MONOSPACE_FONT_NAME,
306 G_CALLBACK (monospace_font_changed_cb), self);
307 g_signal_connect (priv->interface_prefs, "changed::" MATE_MENUS_HAVE_TEAROFF,
308 G_CALLBACK (have_tearoff_changed_cb), self);
309
310 load_filters (self);
311 }
312
313 /* public methods */
314
315 LogviewPrefs *
logview_prefs_get()316 logview_prefs_get ()
317 {
318 if (!singleton)
319 singleton = g_object_new (LOGVIEW_TYPE_PREFS, NULL);
320
321 return singleton;
322 }
323
324 void
logview_prefs_store_window_size(LogviewPrefs * prefs,int width,int height)325 logview_prefs_store_window_size (LogviewPrefs *prefs,
326 int width, int height)
327 {
328 g_assert (LOGVIEW_IS_PREFS (prefs));
329
330 g_settings_set_int (prefs->priv->logview_prefs,
331 PREF_WIDTH, width);
332 g_settings_set_int (prefs->priv->logview_prefs,
333 PREF_HEIGHT, height);
334 }
335
336 void
logview_prefs_get_stored_window_size(LogviewPrefs * prefs,int * width,int * height)337 logview_prefs_get_stored_window_size (LogviewPrefs *prefs,
338 int *width, int *height)
339 {
340 g_assert (LOGVIEW_IS_PREFS (prefs));
341
342 *width = g_settings_get_int (prefs->priv->logview_prefs,
343 PREF_WIDTH);
344 *height = g_settings_get_int (prefs->priv->logview_prefs,
345 PREF_HEIGHT);
346
347 if ((*width == 0) ^ (*height == 0)) {
348 /* if one of the two failed, return default for both */
349 *width = LOGVIEW_DEFAULT_WIDTH;
350 *height = LOGVIEW_DEFAULT_HEIGHT;
351 }
352 }
353
354 char *
logview_prefs_get_monospace_font_name(LogviewPrefs * prefs)355 logview_prefs_get_monospace_font_name (LogviewPrefs *prefs)
356 {
357 g_assert (LOGVIEW_IS_PREFS (prefs));
358
359 return (g_settings_get_string (prefs->priv->interface_prefs, MATE_MONOSPACE_FONT_NAME));
360 }
361
362 gboolean
logview_prefs_get_have_tearoff(LogviewPrefs * prefs)363 logview_prefs_get_have_tearoff (LogviewPrefs *prefs)
364 {
365 g_assert (LOGVIEW_IS_PREFS (prefs));
366
367 return (g_settings_get_boolean (prefs->priv->interface_prefs, MATE_MENUS_HAVE_TEAROFF));
368 }
369
370 /* the elements should be freed with g_free () */
371
372 gchar **
logview_prefs_get_stored_logfiles(LogviewPrefs * prefs)373 logview_prefs_get_stored_logfiles (LogviewPrefs *prefs)
374 {
375 g_assert (LOGVIEW_IS_PREFS (prefs));
376
377 return g_settings_get_strv (prefs->priv->logview_prefs,
378 PREF_LOGFILES);
379 }
380
381 void
logview_prefs_store_log(LogviewPrefs * prefs,GFile * file)382 logview_prefs_store_log (LogviewPrefs *prefs, GFile *file)
383 {
384 gchar **stored_logs;
385 GFile *stored;
386 gboolean found = FALSE;
387 gint idx, old_size;
388
389 g_assert (LOGVIEW_IS_PREFS (prefs));
390 g_assert (G_IS_FILE (file));
391
392 stored_logs = logview_prefs_get_stored_logfiles (prefs);
393
394 for (idx = 0; stored_logs[idx] != NULL; idx++) {
395 stored = g_file_parse_name (stored_logs[idx]);
396 if (g_file_equal (file, stored)) {
397 found = TRUE;
398 }
399
400 g_object_unref (stored);
401
402 if (found) {
403 break;
404 }
405 }
406
407 if (!found) {
408 old_size = g_strv_length (stored_logs);
409 stored_logs = g_realloc (stored_logs, (old_size + 2) * sizeof (gchar *));
410 stored_logs[old_size] = g_file_get_parse_name (file);
411 stored_logs[old_size + 1] = NULL;
412
413 g_settings_set_strv (prefs->priv->logview_prefs,
414 PREF_LOGFILES,
415 (const gchar **) stored_logs);
416 }
417
418 g_strfreev (stored_logs);
419 }
420
421 void
logview_prefs_remove_stored_log(LogviewPrefs * prefs,GFile * target)422 logview_prefs_remove_stored_log (LogviewPrefs *prefs, GFile *target)
423 {
424 gchar **stored_logs;
425 GFile *stored;
426 GPtrArray *new_value;
427 gint idx;
428
429 g_assert (LOGVIEW_IS_PREFS (prefs));
430 g_assert (G_IS_FILE (target));
431
432 stored_logs = logview_prefs_get_stored_logfiles (prefs);
433 new_value = g_ptr_array_new ();
434
435 for (idx = 0; stored_logs[idx] != NULL; idx++) {
436 stored = g_file_parse_name (stored_logs[idx]);
437 if (!g_file_equal (stored, target)) {
438 g_ptr_array_add (new_value, g_strdup (stored_logs[idx]));
439 }
440
441 g_object_unref (stored);
442 }
443
444 g_ptr_array_add (new_value, NULL);
445 g_strfreev (stored_logs);
446 stored_logs = (gchar **) g_ptr_array_free (new_value, FALSE);
447
448 g_settings_set_strv (prefs->priv->logview_prefs,
449 PREF_LOGFILES,
450 (const gchar **) stored_logs);
451
452 g_strfreev (stored_logs);
453 }
454
455 void
logview_prefs_store_fontsize(LogviewPrefs * prefs,int fontsize)456 logview_prefs_store_fontsize (LogviewPrefs *prefs, int fontsize)
457 {
458 g_assert (LOGVIEW_IS_PREFS (prefs));
459 g_assert (fontsize > 0);
460
461 g_settings_set_int (prefs->priv->logview_prefs, PREF_FONTSIZE, fontsize);
462 }
463
464 int
logview_prefs_get_stored_fontsize(LogviewPrefs * prefs)465 logview_prefs_get_stored_fontsize (LogviewPrefs *prefs)
466 {
467 g_assert (LOGVIEW_IS_PREFS (prefs));
468
469 return g_settings_get_int (prefs->priv->logview_prefs, PREF_FONTSIZE);
470 }
471
472 void
logview_prefs_store_active_logfile(LogviewPrefs * prefs,const char * filename)473 logview_prefs_store_active_logfile (LogviewPrefs *prefs,
474 const char *filename)
475 {
476 g_assert (LOGVIEW_IS_PREFS (prefs));
477
478 g_settings_set_string (prefs->priv->logview_prefs,
479 PREF_LOGFILE, filename);
480 }
481
482 char *
logview_prefs_get_active_logfile(LogviewPrefs * prefs)483 logview_prefs_get_active_logfile (LogviewPrefs *prefs)
484 {
485 g_assert (LOGVIEW_IS_PREFS (prefs));
486
487 return g_settings_get_string (prefs->priv->logview_prefs,
488 PREF_LOGFILE);
489 }
490
491 GList *
logview_prefs_get_filters(LogviewPrefs * prefs)492 logview_prefs_get_filters (LogviewPrefs *prefs)
493 {
494 GList *filters = NULL;
495
496 g_assert (LOGVIEW_IS_PREFS (prefs));
497
498 g_hash_table_foreach (prefs->priv->filters,
499 get_filters_foreach,
500 &filters);
501
502 return filters;
503 }
504
505 void
logview_prefs_remove_filter(LogviewPrefs * prefs,const gchar * name)506 logview_prefs_remove_filter (LogviewPrefs *prefs,
507 const gchar *name)
508 {
509 g_assert (LOGVIEW_IS_PREFS (prefs));
510
511 g_hash_table_remove (prefs->priv->filters,
512 name);
513
514 save_filters (prefs);
515 }
516
517 void
logview_prefs_add_filter(LogviewPrefs * prefs,LogviewFilter * filter)518 logview_prefs_add_filter (LogviewPrefs *prefs,
519 LogviewFilter *filter)
520 {
521 gchar* name;
522
523 g_assert (LOGVIEW_IS_PREFS (prefs));
524 g_assert (LOGVIEW_IS_FILTER (filter));
525
526 g_object_get (filter, "name", &name, NULL);
527 g_hash_table_insert (prefs->priv->filters, name, g_object_ref (filter));
528
529 save_filters (prefs);
530 }
531
532 LogviewFilter *
logview_prefs_get_filter(LogviewPrefs * prefs,const gchar * name)533 logview_prefs_get_filter (LogviewPrefs *prefs,
534 const gchar *name)
535 {
536 g_assert (LOGVIEW_IS_PREFS (prefs));
537
538 return g_hash_table_lookup (prefs->priv->filters, name);
539 }
540
541