Merge 'master' into 'gtk3'.
[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 static void psppire_conf_init            (PsppireConf      *conf);
32 static void psppire_conf_class_init      (PsppireConfClass *class);
33
34 static void psppire_conf_finalize        (GObject   *object);
35 static void psppire_conf_dispose        (GObject   *object);
36
37 static GObjectClass *parent_class = NULL;
38
39
40 GType
41 psppire_conf_get_type (void)
42 {
43   static GType conf_type = 0;
44
45   if (!conf_type)
46     {
47       static const GTypeInfo conf_info =
48       {
49         sizeof (PsppireConfClass),
50         NULL,           /* base_init */
51         NULL,           /* base_finalize */
52         (GClassInitFunc) psppire_conf_class_init,
53         NULL,           /* class_finalize */
54         NULL,           /* class_data */
55         sizeof (PsppireConf),
56         0,
57         (GInstanceInitFunc) psppire_conf_init,
58       };
59
60       conf_type = g_type_register_static (G_TYPE_OBJECT,
61                                                 "PsppireConf",
62                                                 &conf_info, 0);
63     }
64
65   return conf_type;
66 }
67
68
69 static void
70 conf_read (PsppireConf *conf)
71 {
72   g_key_file_load_from_file (conf->keyfile,
73                              conf->filename,
74                              G_KEY_FILE_KEEP_COMMENTS,
75                              NULL);
76 }
77
78 static gboolean
79 flush_conf (PsppireConf *conf)
80 {
81   gsize length = 0;
82
83   gchar *kf = g_key_file_to_data  (conf->keyfile, &length, NULL);
84
85   if ( ! g_file_set_contents (conf->filename, kf, length, NULL) )
86     {
87       g_warning ("Cannot open %s for writing", conf->filename);
88     }
89
90   g_free (kf);
91   conf->idle = 0;
92   return FALSE;
93 }
94
95 static void
96 conf_write (PsppireConf *conf)
97 {
98   if ( conf->idle == 0)
99     conf->idle = g_idle_add_full (G_PRIORITY_LOW, 
100                                   (GSourceFunc) flush_conf, conf, NULL);
101 }
102
103
104 static void
105 psppire_conf_dispose  (GObject *object)
106 {
107 }
108
109 static void
110 psppire_conf_finalize (GObject *object)
111 {
112   PsppireConf *conf = PSPPIRE_CONF (object);
113   g_key_file_free (conf->keyfile);
114   g_free (conf->filename);
115 }
116
117
118 static PsppireConf *the_instance = NULL;
119
120 static GObject*
121 psppire_conf_construct   (GType                  type,
122                                      guint                  n_construct_params,
123                                      GObjectConstructParam *construct_params)
124 {
125   GObject *object;
126
127   if (!the_instance)
128     {
129       object = G_OBJECT_CLASS (parent_class)->constructor (type,
130                                                            n_construct_params,
131                                                            construct_params);
132       the_instance = PSPPIRE_CONF (object);
133     }
134   else
135     object = g_object_ref (G_OBJECT (the_instance));
136
137   return object;
138 }
139
140 static void
141 psppire_conf_class_init (PsppireConfClass *class)
142 {
143   GObjectClass *object_class;
144
145   parent_class = g_type_class_peek_parent (class);
146   object_class = (GObjectClass*) class;
147
148   object_class->finalize = psppire_conf_finalize;
149   object_class->dispose = psppire_conf_dispose;
150   object_class->constructor = psppire_conf_construct;
151
152 }
153
154
155 static void
156 psppire_conf_init (PsppireConf *conf)
157 {
158   const gchar *dirname;
159   struct stat s;
160
161   /* Get the name of the directory for user configuration files, then, if it
162      doesn't already exist, create it, since we might be the first program
163      to want to put files there. */
164   dirname = g_get_user_config_dir ();
165   if (stat (dirname, &s) == -1 && errno == ENOENT)
166     mkdir (dirname, 0700);
167
168   conf->filename = g_strdup_printf ("%s/%s", dirname, "psppirerc");
169
170   conf->keyfile = g_key_file_new ();
171
172   conf->dispose_has_run = FALSE;
173   conf->idle = 0;
174 }
175
176
177 PsppireConf *
178 psppire_conf_new (void)
179 {
180   return g_object_new (psppire_conf_get_type (), NULL);
181 }
182
183
184
185 gboolean
186 psppire_conf_get_int (PsppireConf *conf, const gchar *base,
187                       const gchar *name, gint *value)
188 {
189   gboolean ok;
190   GError *err = NULL;
191   conf_read (conf);
192   *value = g_key_file_get_integer (conf->keyfile,
193                                    base,
194                                    name, &err);
195
196   ok = (err == NULL);
197   if ( err != NULL )
198     g_error_free (err);
199
200   return ok;
201 }
202
203 gboolean
204 psppire_conf_get_boolean (PsppireConf *conf, const gchar *base,
205                           const gchar *name, gboolean *value)
206 {
207   gboolean ok;
208   gboolean b;
209   GError *err = NULL;
210   conf_read (conf);
211   b = g_key_file_get_boolean (conf->keyfile,
212                               base,
213                               name, &err);
214
215   ok = (err == NULL);
216   if ( err != NULL )
217     g_error_free (err);
218
219   if (ok)
220     *value = b;
221
222   return ok;
223 }
224
225
226
227 gboolean
228 psppire_conf_get_string (PsppireConf *conf, const gchar *base,
229                          const gchar *name, gchar **value)
230 {
231   gboolean ok;
232   gchar *b;
233   GError *err = NULL;
234   conf_read (conf);
235   b = g_key_file_get_string (conf->keyfile,
236                              base,
237                              name, &err);
238
239   ok = (err == NULL);
240   if ( err != NULL )
241     g_error_free (err);
242
243   if (ok)
244     *value = b;
245
246   return ok;
247 }
248
249
250
251 void
252 psppire_conf_set_int (PsppireConf *conf,
253                       const gchar *base, const gchar *name,
254                       gint value)
255 {
256   g_key_file_set_integer (conf->keyfile, base, name, value);
257   conf_write (conf);
258 }
259
260 void
261 psppire_conf_set_boolean (PsppireConf *conf,
262                           const gchar *base, const gchar *name,
263                           gboolean value)
264 {
265   g_key_file_set_boolean (conf->keyfile, base, name, value);
266   conf_write (conf);
267 }
268
269
270 void
271 psppire_conf_set_string (PsppireConf *conf,
272                          const gchar *base, const gchar *name,
273                          const gchar *value)
274 {
275   g_key_file_set_string (conf->keyfile, base, name, value);
276   conf_write (conf);
277 }
278
279
280
281 /*
282   A convenience function to set the geometry of a
283   window from from a saved config
284 */
285 void
286 psppire_conf_set_window_geometry (PsppireConf *conf,
287                                   const gchar *base,
288                                   GtkWindow *window)
289 {
290   gint height, width;
291   gint x, y;
292   gboolean maximize;
293
294   if (psppire_conf_get_int (conf, base, "height", &height)
295       &&
296       psppire_conf_get_int (conf, base, "width", &width) )
297     {
298       gtk_window_set_default_size (window, width, height);
299     }
300
301   if ( psppire_conf_get_int (conf, base, "x", &x)
302        &&
303        psppire_conf_get_int (conf, base, "y", &y) )
304     {
305       gtk_window_move (window, x, y);
306     }
307
308   if ( psppire_conf_get_boolean (conf, base, "maximize", &maximize))
309     {
310       if (maximize)
311         gtk_window_maximize (window);
312       else
313         gtk_window_unmaximize (window);
314     }
315 }
316
317
318 /*
319    A convenience function to save the window geometry.
320    This should typically be called from a window's
321    "configure-event" and "window-state-event" signal handlers
322  */
323 void
324 psppire_conf_save_window_geometry (PsppireConf *conf,
325                                    const gchar *base,
326                                    GtkWindow *gtk_window)
327 {
328   gboolean maximized;
329   GdkWindow *w;
330
331   w = gtk_widget_get_window (GTK_WIDGET (gtk_window));
332   if (w == NULL)
333     return;
334
335   maximized = (gdk_window_get_state (w) & GDK_WINDOW_STATE_MAXIMIZED) != 0;
336   psppire_conf_set_boolean (conf, base, "maximize", maximized);
337
338   if (!maximized)
339     {
340       gint x, y;
341
342       gint width = gdk_window_get_width (w);
343       gint height= gdk_window_get_height (w);
344
345       gdk_window_get_position (w, &x, &y);
346
347       psppire_conf_set_int (conf, base, "height", height);
348       psppire_conf_set_int (conf, base, "width", width);
349       psppire_conf_set_int (conf, base, "x", x);
350       psppire_conf_set_int (conf, base, "y", y);
351     }
352 }