fixed font for trash
[claws.git] / src / prefs.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999,2000 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <gtk/gtk.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include "intl.h"
32 #include "main.h"
33 #include "prefs.h"
34 #include "utils.h"
35 #include "gtkutils.h"
36
37 typedef enum
38 {
39         DUMMY_PARAM
40 } DummyEnum;
41
42 #define PREFSBUFSIZE    1024
43
44 void prefs_read_config(PrefParam *param, const gchar *label,
45                        const gchar *rcfile)
46 {
47         FILE *fp;
48         gchar buf[PREFSBUFSIZE];
49         gchar *rcpath;
50         gchar *block_label;
51
52         g_return_if_fail(param != NULL);
53         g_return_if_fail(label != NULL);
54         g_return_if_fail(rcfile != NULL);
55
56         debug_print(_("Reading configuration...\n"));
57
58         prefs_set_default(param);
59
60         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
61         if ((fp = fopen(rcpath, "r")) == NULL) {
62                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
63                 g_free(rcpath);
64                 return;
65         }
66         g_free(rcpath);
67
68         block_label = g_strdup_printf("[%s]", label);
69
70         /* search aiming block */
71         while (fgets(buf, sizeof(buf), fp) != NULL) {
72                 gint val;
73
74                 val = strncmp(buf, block_label, strlen(block_label));
75                 if (val == 0) {
76                         debug_print(_("Found %s\n"), block_label);
77                         break;
78                 }
79         }
80         g_free(block_label);
81
82         while (fgets(buf, sizeof(buf), fp) != NULL) {
83                 strretchomp(buf);
84                 /* reached next block */
85                 if (buf[0] == '[') break;
86
87                 prefs_config_parse_one_line(param, buf);
88         }
89
90         debug_print(_("Finished reading configuration.\n"));
91         fclose(fp);
92 }
93
94 void prefs_config_parse_one_line(PrefParam *param, const gchar *buf)
95 {
96         gint i;
97         gint name_len;
98         const gchar *value;
99
100         for (i = 0; param[i].name != NULL; i++) {
101                 name_len = strlen(param[i].name);
102                 if (strncasecmp(buf, param[i].name, name_len))
103                         continue;
104                 if (buf[name_len] != '=')
105                         continue;
106                 value = buf + name_len + 1;
107                 debug_print("%s = %s\n", param[i].name, value);
108
109                 switch (param[i].type) {
110                 case P_STRING:
111                         g_free(*((gchar **)param[i].data));
112                         *((gchar **)param[i].data) =
113                                 *value ? g_strdup(value) : NULL;
114                         break;
115                 case P_INT:
116                         *((gint *)param[i].data) =
117                                 (gint)atoi(value);
118                         break;
119                 case P_BOOL:
120                         *((gboolean *)param[i].data) =
121                                 (*value == '0' || *value == '\0')
122                                         ? FALSE : TRUE;
123                         break;
124                 case P_ENUM:
125                         *((DummyEnum *)param[i].data) =
126                                 (DummyEnum)atoi(value);
127                         break;
128                 case P_USHORT:
129                         *((gushort *)param[i].data) =
130                                 (gushort)atoi(value);
131                         break;
132                 default:
133                         break;
134                 }
135         }
136 }
137
138 #define TRY(func) \
139 if (!(func)) \
140 { \
141         g_warning(_("failed to write configuration to file\n")); \
142         if (orig_fp) fclose(orig_fp); \
143         prefs_write_close_revert(pfile); \
144         g_free(rcpath); \
145         g_free(block_label); \
146         return; \
147 } \
148
149 void prefs_save_config(PrefParam *param, const gchar *label,
150                        const gchar *rcfile)
151 {
152         FILE *orig_fp;
153         PrefFile *pfile;
154         gchar *rcpath;
155         gchar buf[PREFSBUFSIZE];
156         gchar *block_label = NULL;
157         gboolean block_matched = FALSE;
158
159         g_return_if_fail(param != NULL);
160         g_return_if_fail(label != NULL);
161         g_return_if_fail(rcfile != NULL);
162
163         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
164         if ((orig_fp = fopen(rcpath, "r")) == NULL) {
165                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
166         }
167
168         if ((pfile = prefs_write_open(rcpath)) == NULL) {
169                 g_warning(_("failed to write configuration to file\n"));
170                 if (orig_fp) fclose(orig_fp);
171                 g_free(rcpath);
172                 return;
173         }
174
175         block_label = g_strdup_printf("[%s]", label);
176
177         /* search aiming block */
178         if (orig_fp) {
179                 while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
180                         gint val;
181
182                         val = strncmp(buf, block_label, strlen(block_label));
183                         if (val == 0) {
184                                 debug_print(_("Found %s\n"), block_label);
185                                 block_matched = TRUE;
186                                 break;
187                         } else
188                                 TRY(fputs(buf, pfile->fp) != EOF);
189                 }
190         }
191
192         TRY(fprintf(pfile->fp, "%s\n", block_label) > 0);
193         g_free(block_label);
194         block_label = NULL;
195
196         /* write all param data to file */
197         TRY(prefs_write_param(param, pfile->fp) == 0);
198
199         if (block_matched) {
200                 while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
201                         /* next block */
202                         if (buf[0] == '[') {
203                                 TRY(fputc('\n', pfile->fp) != EOF &&
204                                     fputs(buf, pfile->fp)  != EOF);
205                                 break;
206                         }
207                 }
208                 while (fgets(buf, sizeof(buf), orig_fp) != NULL)
209                         TRY(fputs(buf, pfile->fp) != EOF);
210         }
211
212         if (orig_fp) fclose(orig_fp);
213         if (prefs_write_close(pfile) < 0)
214                 g_warning(_("failed to write configuration to file\n"));
215         g_free(rcpath);
216
217         debug_print(_("Configuration is saved.\n"));
218 }
219
220 gint prefs_write_param(PrefParam *param, FILE *fp)
221 {
222         gint i;
223         gchar buf[PREFSBUFSIZE];
224
225         for (i = 0; param[i].name != NULL; i++) {
226                 switch (param[i].type) {
227                 case P_STRING:
228                         g_snprintf(buf, sizeof(buf), "%s=%s\n", param[i].name,
229                                    *((gchar **)param[i].data) ?
230                                    *((gchar **)param[i].data) : "");
231                         break;
232                 case P_INT:
233                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
234                                    *((gint *)param[i].data));
235                         break;
236                 case P_BOOL:
237                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
238                                    *((gboolean *)param[i].data));
239                         break;
240                 case P_ENUM:
241                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
242                                    *((DummyEnum *)param[i].data));
243                         break;
244                 case P_USHORT:
245                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
246                                    *((gushort *)param[i].data));
247                         break;
248                 default:
249                         buf[0] = '\0';
250                 }
251
252                 if (buf[0] != '\0') {
253                         if (fputs(buf, fp) == EOF) {
254                                 perror("fputs");
255                                 return -1;
256                         }
257                 }
258         }
259
260         return 0;
261 }
262
263 PrefFile *prefs_write_open(const gchar *path)
264 {
265         PrefFile *pfile;
266         gchar *tmppath;
267         FILE *fp;
268
269         g_return_val_if_fail(path != NULL, NULL);
270
271         if (prefs_is_readonly(path)) {
272                 g_warning(_("no permission - %s\n"), path);
273                 return NULL;
274         }
275
276         tmppath = g_strconcat(path, ".tmp", NULL);
277         if ((fp = fopen(tmppath, "w")) == NULL) {
278                 FILE_OP_ERROR(tmppath, "fopen");
279                 g_free(tmppath);
280                 return NULL;
281         }
282
283         if (change_file_mode_rw(fp, tmppath) < 0)
284                 FILE_OP_ERROR(tmppath, "chmod");
285
286         g_free(tmppath);
287
288         pfile = g_new(PrefFile, 1);
289         pfile->fp = fp;
290         pfile->path = g_strdup(path);
291
292         return pfile;
293 }
294
295 gint prefs_write_close(PrefFile *pfile)
296 {
297         FILE *fp;
298         gchar *path;
299         gchar *tmppath;
300         gchar *bakpath = NULL;
301
302         g_return_val_if_fail(pfile != NULL, -1);
303
304         fp = pfile->fp;
305         path = pfile->path;
306         g_free(pfile);
307
308         tmppath = g_strconcat(path, ".tmp", NULL);
309         if (fclose(fp) == EOF) {
310                 FILE_OP_ERROR(tmppath, "fclose");
311                 unlink(tmppath);
312                 g_free(path);
313                 g_free(tmppath);
314                 return -1;
315         }
316
317         if (is_file_exist(path)) {
318                 bakpath = g_strconcat(path, ".bak", NULL);
319                 if (rename(path, bakpath) < 0) {
320                         FILE_OP_ERROR(path, "rename");
321                         unlink(tmppath);
322                         g_free(path);
323                         g_free(tmppath);
324                         g_free(bakpath);
325                         return -1;
326                 }
327         }
328
329         if (rename(tmppath, path) < 0) {
330                 FILE_OP_ERROR(tmppath, "rename");
331                 unlink(tmppath);
332                 g_free(path);
333                 g_free(tmppath);
334                 g_free(bakpath);
335                 return -1;
336         }
337
338         g_free(path);
339         g_free(tmppath);
340         g_free(bakpath);
341         return 0;
342 }
343
344 gint prefs_write_close_revert(PrefFile *pfile)
345 {
346         gchar *tmppath;
347
348         g_return_val_if_fail(pfile != NULL, -1);
349
350         tmppath = g_strconcat(pfile->path, ".tmp", NULL);
351         fclose(pfile->fp);
352         if (unlink(tmppath) < 0) FILE_OP_ERROR(tmppath, "unlink");
353         g_free(tmppath);
354         g_free(pfile->path);
355         g_free(pfile);
356
357         return 0;
358 }
359
360 void prefs_set_default(PrefParam *param)
361 {
362         gint i;
363
364         g_return_if_fail(param != NULL);
365
366         for (i = 0; param[i].name != NULL; i++) {
367                 if (!param[i].data) continue;
368
369                 switch (param[i].type) {
370                 case P_STRING:
371                         if (param[i].defval != NULL) {
372                                 if (!strncasecmp(param[i].defval, "ENV_", 4))
373                                         *((gchar **)param[i].data) =
374                                                 g_strdup(g_getenv(param[i].defval + 4));
375                                 else if (param[i].defval[0] == '~')
376                                         *((gchar **)param[i].data) =
377                                                 g_strconcat(get_home_dir(),
378                                                             param[i].defval + 1,
379                                                             NULL);
380                                 else if (param[i].defval[0] != '\0')
381                                         *((gchar **)param[i].data) =
382                                                 g_strdup(param[i].defval);
383                                 else
384                                         *((gchar **)param[i].data) = NULL;
385                         } else
386                                 *((gchar **)param[i].data) = NULL;
387                         break;
388                 case P_INT:
389                         if (param[i].defval != NULL)
390                                 *((gint *)param[i].data) =
391                                         (gint)atoi(param[i].defval);
392                         else
393                                 *((gint *)param[i].data) = 0;
394                         break;
395                 case P_BOOL:
396                         if (param[i].defval != NULL) {
397                                 if (!strcasecmp(param[i].defval, "TRUE"))
398                                         *((gboolean *)param[i].data) = TRUE;
399                                 else
400                                         *((gboolean *)param[i].data) =
401                                                 atoi(param[i].defval) ? TRUE : FALSE;
402                         } else
403                                 *((gboolean *)param[i].data) = FALSE;
404                         break;
405                 case P_ENUM:
406                         if (param[i].defval != NULL)
407                                 *((DummyEnum*)param[i].data) =
408                                         (DummyEnum)atoi(param[i].defval);
409                         else
410                                 *((DummyEnum *)param[i].data) = 0;
411                         break;
412                 case P_USHORT:
413                         if (param[i].defval != NULL)
414                                 *((gushort *)param[i].data) =
415                                         (gushort)atoi(param[i].defval);
416                         else
417                                 *((gushort *)param[i].data) = 0;
418                         break;
419                 default:
420                         break;
421                 }
422         }
423 }
424
425 void prefs_free(PrefParam *param)
426 {
427         gint i;
428
429         g_return_if_fail(param != NULL);
430
431         for (i = 0; param[i].name != NULL; i++) {
432                 if (!param[i].data) continue;
433
434                 switch (param[i].type) {
435                 case P_STRING:
436                         g_free(*((gchar **)param[i].data));
437                         break;
438                 default:
439                         break;
440                 }
441         }
442 }
443
444 void prefs_dialog_create(PrefsDialog *dialog)
445 {
446         GtkWidget *window;
447         GtkWidget *vbox;
448         GtkWidget *notebook;
449
450         GtkWidget *confirm_area;
451         GtkWidget *ok_btn;
452         GtkWidget *cancel_btn;
453         GtkWidget *apply_btn;
454
455         g_return_if_fail(dialog != NULL);
456
457         window = gtk_window_new (GTK_WINDOW_DIALOG);
458         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
459         gtk_window_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
460         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
461         gtk_window_set_policy (GTK_WINDOW(window), FALSE, TRUE, FALSE);
462
463         vbox = gtk_vbox_new (FALSE, 6);
464         gtk_widget_show(vbox);
465         gtk_container_add (GTK_CONTAINER (window), vbox);
466
467         notebook = gtk_notebook_new ();
468         gtk_widget_show(notebook);
469         gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
470         gtk_container_set_border_width (GTK_CONTAINER (notebook), 2);
471         /* GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS); */
472         gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
473
474         gtkut_button_set_create(&confirm_area,
475                                 &ok_btn,        _("OK"),
476                                 &cancel_btn,    _("Cancel"),
477                                 &apply_btn,     _("Apply"));
478         gtk_widget_show(confirm_area);
479         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
480         gtk_widget_grab_default(ok_btn);
481
482         dialog->window     = window;
483         dialog->notebook   = notebook;
484         dialog->ok_btn     = ok_btn;
485         dialog->cancel_btn = cancel_btn;
486         dialog->apply_btn  = apply_btn;
487 }
488
489 void prefs_button_toggled(GtkToggleButton *toggle_btn, GtkWidget *widget)
490 {
491         gboolean is_active;
492
493         is_active = gtk_toggle_button_get_active(toggle_btn);
494         gtk_widget_set_sensitive(widget, is_active);
495 }
496
497 void prefs_set_dialog(PrefParam *param)
498 {
499         gint i;
500
501         for (i = 0; param[i].name != NULL; i++) {
502                 if (param[i].widget_set_func)
503                         param[i].widget_set_func(&param[i]);
504         }
505 }
506
507 void prefs_set_data_from_dialog(PrefParam *param)
508 {
509         gint i;
510
511         for (i = 0; param[i].name != NULL; i++) {
512                 if (param[i].data_set_func)
513                         param[i].data_set_func(&param[i]);
514         }
515 }
516
517 void prefs_set_dialog_to_default(PrefParam *param)
518 {
519         gint       i;
520         PrefParam  tmpparam;
521         gchar     *str_data = NULL;
522         gint       int_data;
523         gushort    ushort_data;
524         gboolean   bool_data;
525         DummyEnum  enum_data;
526
527         for (i = 0; param[i].name != NULL; i++) {
528                 if (!param[i].widget_set_func) continue;
529
530                 tmpparam = param[i];
531
532                 switch (tmpparam.type) {
533                 case P_STRING:
534                         if (tmpparam.defval) {
535                                 if (!strncasecmp(tmpparam.defval, "ENV_", 4)) {
536                                         str_data = g_strdup(g_getenv(param[i].defval + 4));
537                                         tmpparam.data = &str_data;
538                                         break;
539                                 } else if (tmpparam.defval[0] == '~') {
540                                         str_data =
541                                                 g_strconcat(get_home_dir(),
542                                                             param[i].defval + 1,
543                                                             NULL);
544                                         tmpparam.data = &str_data;
545                                         break;
546                                 }
547                         }
548                         tmpparam.data = &tmpparam.defval;
549                         break;
550                 case P_INT:
551                         if (tmpparam.defval)
552                                 int_data = atoi(tmpparam.defval);
553                         else
554                                 int_data = 0;
555                         tmpparam.data = &int_data;
556                         break;
557                 case P_USHORT:
558                         if (tmpparam.defval)
559                                 ushort_data = atoi(tmpparam.defval);
560                         else
561                                 ushort_data = 0;
562                         tmpparam.data = &ushort_data;
563                         break;
564                 case P_BOOL:
565                         if (tmpparam.defval) {
566                                 if (!strcasecmp(tmpparam.defval, "TRUE"))
567                                         bool_data = TRUE;
568                                 else
569                                         bool_data = atoi(tmpparam.defval)
570                                                 ? TRUE : FALSE;
571                         } else
572                                 bool_data = FALSE;
573                         tmpparam.data = &bool_data;
574                         break;
575                 case P_ENUM:
576                         if (tmpparam.defval)
577                                 enum_data = (DummyEnum)atoi(tmpparam.defval);
578                         else
579                                 enum_data = 0;
580                         tmpparam.data = &enum_data;
581                         break;
582                 case P_OTHER:
583                         break;
584                 }
585                 tmpparam.widget_set_func(&tmpparam);
586                 g_free(str_data);
587                 str_data = NULL;
588         }
589 }
590
591 void prefs_set_data_from_entry(PrefParam *pparam)
592 {
593         gchar **str, *entry_str;
594
595         g_return_if_fail(*pparam->widget != NULL);
596
597         entry_str = gtk_entry_get_text(GTK_ENTRY(*pparam->widget));
598
599         switch (pparam->type) {
600         case P_STRING:
601                 str = (gchar **)pparam->data;
602                 g_free(*str);
603                 *str = entry_str[0] ? g_strdup(entry_str) : NULL;
604                 break;
605         case P_USHORT:
606                 *((gushort *)pparam->data) = atoi(entry_str);
607                 break;
608         case P_INT:
609                 *((gint *)pparam->data) = atoi(entry_str);
610                 break;
611         default:
612                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
613                           pparam->type);
614         }
615 }
616
617 void prefs_set_entry(PrefParam *pparam)
618 {
619         gchar **str;
620
621         g_return_if_fail(*pparam->widget != NULL);
622
623         switch (pparam->type) {
624         case P_STRING:
625                 str = (gchar **)pparam->data;
626                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
627                                    *str ? *str : "");
628                 break;
629         case P_INT:
630                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
631                                    itos(*((gint *)pparam->data)));
632                 break;
633         case P_USHORT:
634                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
635                                    itos(*((gushort *)pparam->data)));
636                 break;
637         default:
638                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
639                           pparam->type);
640         }
641 }
642
643 void prefs_set_data_from_text(PrefParam *pparam)
644 {
645         gchar **str;
646         gchar *text, *tp;
647         gchar *tmp, *tmpp;
648
649         g_return_if_fail(*pparam->widget != NULL);
650
651         switch (pparam->type) {
652         case P_STRING:
653                 str = (gchar **)pparam->data;
654                 g_free(*str);
655                 tp = text = gtk_editable_get_chars
656                         (GTK_EDITABLE(*pparam->widget), 0, -1);
657                 if (text[0] == '\0') {
658                         *str = NULL;
659                         g_free(text);
660                         break;
661                 }
662
663                 Xalloca(tmpp = tmp, strlen(text) * 2 + 1,
664                         { *str = NULL; break; });
665                 while (*tp) {
666                         if (*tp == '\n') {
667                                 *tmpp++ = '\\';
668                                 *tmpp++ = 'n';
669                                 tp++;
670                         } else
671                                 *tmpp++ = *tp++;
672                 }
673                 *tmpp = '\0';
674                 *str = g_strdup(tmp);
675                 g_free(text);
676                 break;
677         default:
678                 g_warning("Invalid PrefType for GtkText widget: %d\n",
679                           pparam->type);
680         }
681 }
682
683 void prefs_set_text(PrefParam *pparam)
684 {
685         gchar *buf, *sp, *bufp;
686         gchar **str;
687         GtkText *text;
688
689         g_return_if_fail(*pparam->widget != NULL);
690
691         switch (pparam->type) {
692         case P_STRING:
693                 str = (gchar **)pparam->data;
694                 if (*str) {
695                         bufp = buf = alloca(strlen(*str) + 1);
696                         if (!buf) buf = "";
697                         else {
698                                 sp = *str;
699                                 while (*sp) {
700                                         if (*sp == '\\' && *(sp + 1) == 'n') {
701                                                 *bufp++ = '\n';
702                                                 sp += 2;
703                                         } else
704                                                 *bufp++ = *sp++;
705                                 }
706                                 *bufp = '\0';
707                         }
708                 } else
709                         buf = "";
710
711                 text = GTK_TEXT(*pparam->widget);
712                 gtk_text_set_point(text, 0);
713                 gtk_text_forward_delete(text, gtk_text_get_length(text));
714                 gtk_text_set_point(text, 0);
715                 gtk_text_insert(text, NULL, NULL, NULL, buf, -1);
716                 break;
717         default:
718                 g_warning("Invalid PrefType for GtkText widget: %d\n",
719                           pparam->type);
720         }
721 }
722
723 void prefs_set_data_from_toggle(PrefParam *pparam)
724 {
725         g_return_if_fail(pparam->type == P_BOOL);
726         g_return_if_fail(*pparam->widget != NULL);
727         
728         *((gboolean *)pparam->data) =
729                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(*pparam->widget));
730 }
731
732 void prefs_set_toggle(PrefParam *pparam)
733 {
734         g_return_if_fail(pparam->type == P_BOOL);
735         g_return_if_fail(*pparam->widget != NULL);
736
737         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(*pparam->widget),
738                                      *((gboolean *)pparam->data));
739 }
740
741 void prefs_set_data_from_spinbtn(PrefParam *pparam)
742 {
743         g_return_if_fail(*pparam->widget != NULL);
744
745         switch (pparam->type) {
746         case P_INT:
747                 *((gint *)pparam->data) =
748                         gtk_spin_button_get_value_as_int
749                         (GTK_SPIN_BUTTON(*pparam->widget));
750                 break;
751         case P_USHORT:
752                 *((gushort *)pparam->data) =
753                         (gushort)gtk_spin_button_get_value_as_int
754                         (GTK_SPIN_BUTTON(*pparam->widget));
755                 break;
756         default:
757                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
758                           pparam->type);
759         }
760 }
761
762 void prefs_set_spinbtn(PrefParam *pparam)
763 {
764         g_return_if_fail(*pparam->widget != NULL);
765
766         switch (pparam->type) {
767         case P_INT:
768                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
769                                           (gfloat)*((gint *)pparam->data));
770                 break;
771         case P_USHORT:
772                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
773                                           (gfloat)*((gushort *)pparam->data));
774                 break;
775         default:
776                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
777                           pparam->type);
778         }
779 }
780
781 gboolean prefs_is_readonly(const gchar * path)
782 {
783         if (path == NULL)
784                 return TRUE;
785
786         return (access(path, W_OK) != 0 && access(path, F_OK) == 0);
787 }
788
789 gboolean prefs_rc_is_readonly(const gchar * rcfile)
790 {
791         gboolean result;
792         gchar * rcpath;
793
794         if (rcfile == NULL)
795                 return TRUE;
796
797         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
798         result = prefs_is_readonly(rcpath);
799         g_free(rcpath);
800
801         return result;
802 }