Use idle callback to write to the local config directory
[pspp-builds.git] / 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 void
227 psppire_conf_set_int (PsppireConf *conf,
228                       const gchar *base, const gchar *name,
229                       gint value)
230 {
231   g_key_file_set_integer (conf->keyfile, base, name, value);
232   conf_write (conf);
233 }
234
235 void
236 psppire_conf_set_boolean (PsppireConf *conf,
237                           const gchar *base, const gchar *name,
238                           gboolean value)
239 {
240   g_key_file_set_boolean (conf->keyfile, base, name, value);
241   conf_write (conf);
242 }
243
244 /*
245   A convenience function to set the geometry of a
246   window from from a saved config
247 */
248 void
249 psppire_conf_set_window_geometry (PsppireConf *conf,
250                                   const gchar *base,
251                                   GtkWindow *window)
252 {
253   gint height, width;
254   gint x, y;
255   gboolean maximize;
256
257   if (psppire_conf_get_int (conf, base, "height", &height)
258       &&
259       psppire_conf_get_int (conf, base, "width", &width) )
260     {
261       gtk_window_set_default_size (window, width, height);
262     }
263
264   if ( psppire_conf_get_int (conf, base, "x", &x)
265        &&
266        psppire_conf_get_int (conf, base, "y", &y) )
267     {
268       gtk_window_move (window, x, y);
269     }
270
271   if ( psppire_conf_get_boolean (conf, base, "maximize", &maximize))
272     {
273       if (maximize)
274         gtk_window_maximize (window);
275       else
276         gtk_window_unmaximize (window);
277     }
278 }
279
280
281 /*
282    A convenience function to save the window geometry.
283    This should typically be called from a window's
284    "configure-event" and "window-state-event" signal handlers
285  */
286 void
287 psppire_conf_save_window_geometry (PsppireConf *conf,
288                                    const gchar *base,
289                                    GtkWindow *gtk_window)
290 {
291   gboolean maximized;
292   GdkWindow *w;
293
294   w = gtk_widget_get_window (GTK_WIDGET (gtk_window));
295   if (w == NULL)
296     return;
297
298   maximized = (gdk_window_get_state (w) & GDK_WINDOW_STATE_MAXIMIZED) != 0;
299   psppire_conf_set_boolean (conf, base, "maximize", maximized);
300
301   if (!maximized)
302     {
303       gint width, height;
304       gint x, y;
305
306       gdk_drawable_get_size (w, &width, &height);
307       gdk_window_get_position (w, &x, &y);
308
309       psppire_conf_set_int (conf, base, "height", height);
310       psppire_conf_set_int (conf, base, "width", width);
311       psppire_conf_set_int (conf, base, "x", x);
312       psppire_conf_set_int (conf, base, "y", y);
313     }
314 }