Warnings: missing initializer for value_tables and function type cast (GObject)
[pspp] / src / ui / gui / psppire-conf.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2009, 2010  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 /*
18    This module provides an interface for simple user preference config
19    parameters.
20 */
21
22 #include <config.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <sys/stat.h>
26
27 #include <glib.h>
28
29 #include "psppire-conf.h"
30
31 G_DEFINE_TYPE (PsppireConf, psppire_conf, G_TYPE_OBJECT)
32
33 static void psppire_conf_finalize        (GObject   *object);
34 static void psppire_conf_dispose        (GObject   *object);
35
36 static GObjectClass *parent_class = NULL;
37
38 static void
39 conf_read (PsppireConf *conf)
40 {
41   g_key_file_load_from_file (conf->keyfile,
42                              conf->filename,
43                              G_KEY_FILE_KEEP_COMMENTS,
44                              NULL);
45 }
46
47 static gboolean
48 flush_conf (PsppireConf *conf)
49 {
50   gsize length = 0;
51
52   gchar *kf = g_key_file_to_data  (conf->keyfile, &length, NULL);
53
54   if (! g_file_set_contents (conf->filename, kf, length, NULL))
55     {
56       char *msg = strerror (errno);
57       g_warning ("Cannot open %s for writing: %s", conf->filename, msg);
58     }
59
60   g_free (kf);
61   conf->idle = 0;
62   return FALSE;
63 }
64
65 static void
66 conf_write (PsppireConf *conf)
67 {
68   if (conf->idle == 0)
69     conf->idle = g_idle_add_full (G_PRIORITY_LOW,
70                                   (GSourceFunc) flush_conf, conf, NULL);
71 }
72
73
74 static void
75 psppire_conf_dispose  (GObject *object)
76 {
77 }
78
79 static void
80 psppire_conf_finalize (GObject *object)
81 {
82   PsppireConf *conf = PSPPIRE_CONF (object);
83   g_key_file_free (conf->keyfile);
84   g_free (conf->filename);
85 }
86
87
88 static PsppireConf *the_instance = NULL;
89
90 static GObject*
91 psppire_conf_construct   (GType                  type,
92                                      guint                  n_construct_params,
93                                      GObjectConstructParam *construct_params)
94 {
95   GObject *object;
96
97   if (!the_instance)
98     {
99       object = G_OBJECT_CLASS (parent_class)->constructor (type,
100                                                            n_construct_params,
101                                                            construct_params);
102       the_instance = PSPPIRE_CONF (object);
103     }
104   else
105     object = g_object_ref (G_OBJECT (the_instance));
106
107   return object;
108 }
109
110 static void
111 psppire_conf_class_init (PsppireConfClass *class)
112 {
113   GObjectClass *object_class;
114
115   parent_class = g_type_class_peek_parent (class);
116   object_class = (GObjectClass*) class;
117
118   object_class->finalize = psppire_conf_finalize;
119   object_class->dispose = psppire_conf_dispose;
120   object_class->constructor = psppire_conf_construct;
121 }
122
123
124 static void
125 psppire_conf_init (PsppireConf *conf)
126 {
127   const gchar *dirname;
128   struct stat s;
129
130   /* Get the name of the directory for user configuration files, then, if it
131      doesn't already exist, create it, since we might be the first program
132      to want to put files there. */
133   dirname = g_get_user_config_dir ();
134   if (stat (dirname, &s) == -1 && errno == ENOENT)
135     mkdir (dirname, 0700);
136
137   conf->filename = g_strdup_printf ("%s/%s", dirname, "psppirerc");
138
139   conf->keyfile = g_key_file_new ();
140
141   conf->idle = 0;
142 }
143
144
145 PsppireConf *
146 psppire_conf_new (void)
147 {
148   return g_object_new (psppire_conf_get_type (), NULL);
149 }
150
151
152
153 gboolean
154 psppire_conf_get_int (PsppireConf *conf, const gchar *base,
155                       const gchar *name, gint *value)
156 {
157   gboolean ok;
158   GError *err = NULL;
159   conf_read (conf);
160   *value = g_key_file_get_integer (conf->keyfile,
161                                    base,
162                                    name, &err);
163
164   ok = (err == NULL);
165   if (err != NULL)
166     g_error_free (err);
167
168   return ok;
169 }
170
171 gboolean
172 psppire_conf_get_boolean (PsppireConf *conf, const gchar *base,
173                           const gchar *name, gboolean *value)
174 {
175   gboolean ok;
176   gboolean b;
177   GError *err = NULL;
178   conf_read (conf);
179   b = g_key_file_get_boolean (conf->keyfile,
180                               base,
181                               name, &err);
182
183   ok = (err == NULL);
184   if (err != NULL)
185     g_error_free (err);
186
187   if (ok)
188     *value = b;
189
190   return ok;
191 }
192
193
194
195 gboolean
196 psppire_conf_get_string (PsppireConf *conf, const gchar *base,
197                          const gchar *name, gchar **value)
198 {
199   gboolean ok;
200   gchar *b;
201   GError *err = NULL;
202   conf_read (conf);
203   b = g_key_file_get_string (conf->keyfile,
204                              base,
205                              name, &err);
206
207   ok = (err == NULL);
208   if (err != NULL)
209     g_error_free (err);
210
211   if (ok)
212     *value = b;
213
214   return ok;
215 }
216
217
218
219
220 gboolean
221 psppire_conf_get_variant (PsppireConf *conf, const gchar *base,
222                           const gchar *name, GVariant **v)
223 {
224   gboolean ok;
225   gchar *b;
226   GError *err = NULL;
227   conf_read (conf);
228   b = g_key_file_get_string (conf->keyfile,
229                              base,
230                              name, &err);
231
232   ok = (err == NULL);
233   if (err != NULL)
234     g_error_free (err);
235
236   if (ok)
237     {
238       *v = g_variant_parse (NULL, b, NULL, NULL, NULL);
239       g_free (b);
240     }
241
242   return ok;
243 }
244
245 gboolean
246 psppire_conf_get_enum (PsppireConf *conf, const gchar *base,
247                        const gchar *name,
248                        GType t,
249                        int *v)
250 {
251   gboolean ok;
252   gchar *b;
253   GError *err = NULL;
254   conf_read (conf);
255   b = g_key_file_get_string (conf->keyfile,
256                              base,
257                              name, &err);
258
259   ok = (err == NULL);
260   if (err != NULL)
261     g_error_free (err);
262
263   if (ok)
264     {
265       GEnumClass *ec = g_type_class_ref (t);
266       GEnumValue *ev = g_enum_get_value_by_nick (ec, b);
267       *v = ev->value;
268       g_type_class_unref (ec);
269       g_free (b);
270     }
271
272   return ok;
273 }
274
275 void
276 psppire_conf_set_int (PsppireConf *conf,
277                       const gchar *base, const gchar *name,
278                       gint value)
279 {
280   g_key_file_set_integer (conf->keyfile, base, name, value);
281   conf_write (conf);
282 }
283
284 void
285 psppire_conf_set_boolean (PsppireConf *conf,
286                           const gchar *base, const gchar *name,
287                           gboolean value)
288 {
289   g_key_file_set_boolean (conf->keyfile, base, name, value);
290   conf_write (conf);
291 }
292
293
294 void
295 psppire_conf_set_string (PsppireConf *conf,
296                          const gchar *base, const gchar *name,
297                          const gchar *value)
298 {
299   g_key_file_set_string (conf->keyfile, base, name, value);
300   conf_write (conf);
301 }
302
303 void
304 psppire_conf_set_variant (PsppireConf *conf,
305                                const gchar *base, const gchar *name,
306                                GVariant *value)
307 {
308   gchar *v = g_variant_print (value, FALSE);
309   g_key_file_set_string (conf->keyfile, base, name, v);
310   conf_write (conf);
311   g_free (v);
312 }
313
314 void
315 psppire_conf_set_enum (PsppireConf *conf,
316                        const gchar *base, const gchar *name,
317                        GType enum_type,
318                        int value)
319 {
320   GEnumClass *ec = g_type_class_ref (enum_type);
321   GEnumValue *ev = g_enum_get_value (ec, value);
322
323   g_key_file_set_string (conf->keyfile, base, name,
324                          ev->value_nick);
325
326   g_type_class_unref (ec);
327
328   conf_write (conf);
329 }
330
331
332
333 /*
334   A convenience function to set the geometry of a
335   window from from a saved config
336 */
337 void
338 psppire_conf_set_window_geometry (PsppireConf *conf,
339                                   const gchar *base,
340                                   GtkWindow *window)
341 {
342   gint height, width;
343   gint x, y;
344   gboolean maximize;
345
346   if (psppire_conf_get_int (conf, base, "height", &height)
347       &&
348       psppire_conf_get_int (conf, base, "width", &width))
349     {
350       gtk_window_set_default_size (window, width, height);
351     }
352
353   if (psppire_conf_get_int (conf, base, "x", &x)
354        &&
355        psppire_conf_get_int (conf, base, "y", &y))
356     {
357       gtk_window_move (window, x, y);
358     }
359
360   if (psppire_conf_get_boolean (conf, base, "maximize", &maximize))
361     {
362       if (maximize)
363         gtk_window_maximize (window);
364       else
365         gtk_window_unmaximize (window);
366     }
367 }
368
369
370 /*
371    A convenience function to save the window geometry.
372    This should typically be called from a window's
373    "configure-event" and "window-state-event" signal handlers
374  */
375 void
376 psppire_conf_save_window_geometry (PsppireConf *conf,
377                                    const gchar *base,
378                                    GtkWindow *gtk_window)
379 {
380   gboolean maximized;
381   GdkWindow *w;
382
383   w = gtk_widget_get_window (GTK_WIDGET (gtk_window));
384   if (w == NULL)
385     return;
386
387   maximized = (gdk_window_get_state (w) & GDK_WINDOW_STATE_MAXIMIZED) != 0;
388   psppire_conf_set_boolean (conf, base, "maximize", maximized);
389
390   if (!maximized)
391     {
392       gint x, y;
393
394       gint width = gdk_window_get_width (w);
395       gint height= gdk_window_get_height (w);
396
397       gdk_window_get_position (w, &x, &y);
398
399       psppire_conf_set_int (conf, base, "height", height);
400       psppire_conf_set_int (conf, base, "width", width);
401       psppire_conf_set_int (conf, base, "x", x);
402       psppire_conf_set_int (conf, base, "y", y);
403     }
404 }