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", &regex,
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