1 /*
2  * config.c - Part of the Geany Markdown plugin
3  *
4  * Copyright 2012 Matthew Brush <mbrush@codebrainz.ca>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  *
21  *
22  */
23 
24 #include "config.h"
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <geanyplugin.h>
28 #include "conf.h"
29 #include "markdown-gtk-compat.h"
30 
31 #define FONT_NAME_MAX  256
32 #define COLOR_CODE_MAX 8
33 #define DEFAULT_CONF \
34   "[general]\n" \
35   "template=\n" \
36   "\n" \
37   "[view]\n" \
38   "position=0\n" \
39   "font_name=Serif\n" \
40   "code_font_name=Mono\n" \
41   "font_point_size=12\n" \
42   "code_font_point_size=12\n" \
43   "bg_color=#fff\n" \
44   "fg_color=#000\n"
45 
46 #define MARKDOWN_HTML_TEMPLATE \
47   "<html>\n" \
48   "  <head>\n" \
49   "    <style type=\"text/css\">\n" \
50   "      body {\n" \
51   "        font-family: @@font_name@@;\n" \
52   "        font-size: @@font_point_size@@pt;\n" \
53   "        background-color: @@bg_color@@;\n" \
54   "        color: @@fg_color@@;\n" \
55   "      }\n" \
56   "      code {\n" \
57   "        font-family: @@code_font_name@@;\n" \
58   "        font-size: @@code_font_point_size@@pt;\n" \
59   "      }\n" \
60   "    </style>\n" \
61   "  </head>\n" \
62   "  <body>\n" \
63   "    @@markdown@@\n" \
64   "  </body>\n" \
65   "</html>\n"
66 
67 enum
68 {
69   PROP_0 = 0,
70   PROP_TEMPLATE_FILE,
71   PROP_FONT_NAME,
72   PROP_CODE_FONT_NAME,
73   PROP_FONT_POINT_SIZE,
74   PROP_CODE_FONT_POINT_SIZE,
75   PROP_BG_COLOR,
76   PROP_FG_COLOR,
77   PROP_VIEW_POS,
78   PROP_LAST
79 };
80 
81 static GParamSpec *md_props[PROP_LAST] = { NULL };
82 
83 struct _MarkdownConfigPrivate
84 {
85   gchar *filename;
86   GKeyFile *kf;
87   guint handle;
88   gulong dlg_handle;
89   gboolean initialized;
90   gchar *tmpl_text;
91   gsize tmpl_text_len;
92   struct {
93     GtkWidget *table;
94     GtkWidget *pos_sb_radio;
95     GtkWidget *pos_mw_radio;
96     GtkWidget *font_button;
97     GtkWidget *code_font_button;
98     GtkWidget *bg_color_button;
99     GtkWidget *fg_color_button;
100     GtkWidget *tmpl_file_button;
101   } widgets;
102 };
103 
104 static void markdown_config_finalize(GObject *object);
105 
G_DEFINE_TYPE(MarkdownConfig,markdown_config,G_TYPE_OBJECT)106 G_DEFINE_TYPE(MarkdownConfig, markdown_config, G_TYPE_OBJECT)
107 
108 static gboolean on_idle_timeout(MarkdownConfig *conf)
109 {
110   markdown_config_save(conf);
111   conf->priv->handle = 0;
112   return FALSE;
113 }
114 
115 static void
init_conf_file(MarkdownConfig * conf)116 init_conf_file(MarkdownConfig *conf)
117 {
118   GError *error = NULL;
119   gchar *def_tmpl, *dirn;
120 
121   dirn = g_path_get_dirname(conf->priv->filename);
122   if (!g_file_test(dirn, G_FILE_TEST_IS_DIR)) {
123     g_mkdir_with_parents(dirn, 0755);
124   }
125 
126   if (!g_file_test(conf->priv->filename, G_FILE_TEST_EXISTS)) {
127     if (!g_file_set_contents(conf->priv->filename, DEFAULT_CONF, -1, &error)) {
128       g_warning("Unable to write default configuration file: %s", error->message);
129       g_error_free(error); error = NULL;
130     }
131   }
132 
133   def_tmpl = g_build_filename(dirn, "template.html", NULL);
134 
135   if (!g_file_test(def_tmpl, G_FILE_TEST_EXISTS)) {
136     if (!g_file_set_contents(def_tmpl, MARKDOWN_HTML_TEMPLATE, -1, &error)) {
137       g_warning("Unable to write default template file: %s", error->message);
138       g_error_free(error); error = NULL;
139     }
140   }
141 
142   g_free(dirn);
143   g_free(def_tmpl);
144 }
145 
146 static void
markdown_config_load_template_text(MarkdownConfig * conf)147 markdown_config_load_template_text(MarkdownConfig *conf)
148 {
149   GError *error = NULL;
150   gchar *tmpl_file = NULL;
151 
152   g_object_get(conf, "template-file", &tmpl_file, NULL);
153 
154   g_free(conf->priv->tmpl_text);
155   conf->priv->tmpl_text = NULL;
156   conf->priv->tmpl_text_len = 0;
157 
158   if (!g_file_get_contents(tmpl_file, &(conf->priv->tmpl_text),
159       &(conf->priv->tmpl_text_len), &error))
160   {
161     g_warning("Error reading template file: %s", error->message);
162     g_error_free(error); error = NULL;
163   }
164 }
165 
166 static void
markdown_config_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)167 markdown_config_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec)
168 {
169   gboolean save_later = FALSE;
170   MarkdownConfig *conf = MARKDOWN_CONFIG(obj);
171 
172   /* FIXME: Prevent writing to keyfile until it's ready */
173   if (!conf->priv->initialized)
174     return;
175 
176   switch (prop_id) {
177     case PROP_TEMPLATE_FILE:
178       g_key_file_set_string(conf->priv->kf, "general", "template",
179         g_value_get_string(value));
180       /*markdown_config_load_template_text(conf);*/
181       save_later = TRUE;
182       break;
183     case PROP_FONT_NAME:
184       g_key_file_set_string(conf->priv->kf, "view", "font_name",
185         g_value_get_string(value));
186       save_later = TRUE;
187       break;
188     case PROP_CODE_FONT_NAME:
189       g_key_file_set_string(conf->priv->kf, "view", "code_font_name",
190         g_value_get_string(value));
191       save_later = TRUE;
192       break;
193     case PROP_FONT_POINT_SIZE:
194       g_key_file_set_integer(conf->priv->kf, "view", "font_point_size",
195         (gint) g_value_get_uint(value));
196       save_later = TRUE;
197       break;
198     case PROP_CODE_FONT_POINT_SIZE:
199       g_key_file_set_integer(conf->priv->kf, "view", "code_font_point_size",
200         (gint) g_value_get_uint(value));
201       save_later = TRUE;
202       break;
203     case PROP_BG_COLOR:
204       g_key_file_set_string(conf->priv->kf, "view", "bg_color",
205         g_value_get_string(value));
206       save_later = TRUE;
207       break;
208     case PROP_FG_COLOR:
209       g_key_file_set_string(conf->priv->kf, "view", "fg_color",
210         g_value_get_string(value));
211       save_later = TRUE;
212       break;
213     case PROP_VIEW_POS:
214       g_key_file_set_integer(conf->priv->kf, "view", "position",
215         (gint) g_value_get_uint(value));
216       save_later = TRUE;
217       break;
218     default:
219       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
220       break;
221   }
222 
223   if (save_later && conf->priv->handle == 0) {
224     conf->priv->handle = g_idle_add((GSourceFunc) on_idle_timeout, conf);
225   }
226 }
227 
228 static gchar *
markdown_config_get_string_key(MarkdownConfig * conf,const gchar * group,const gchar * key,const gchar * default_value)229 markdown_config_get_string_key(MarkdownConfig *conf, const gchar *group,
230   const gchar *key, const gchar *default_value)
231 {
232   gchar *out_str;
233   GError *error = NULL;
234 
235   out_str = g_key_file_get_string(conf->priv->kf, group, key, &error);
236   if (error) {
237     g_debug("Config read failed: %s", error->message);
238     g_error_free(error); error = NULL;
239     out_str = g_strdup(default_value);
240   }
241 
242   return out_str;
243 }
244 
245 static guint
markdown_config_get_uint_key(MarkdownConfig * conf,const gchar * group,const gchar * key,guint default_value)246 markdown_config_get_uint_key(MarkdownConfig *conf, const gchar *group,
247   const gchar *key, guint default_value)
248 {
249   guint out_uint;
250   GError *error = NULL;
251 
252   out_uint = (guint) g_key_file_get_integer(conf->priv->kf, group, key, &error);
253   if (error) {
254     g_debug("Config read failed: %s", error->message);
255     g_error_free(error); error = NULL;
256     out_uint = default_value;
257   }
258 
259   return out_uint;
260 }
261 
262 static void
markdown_config_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)263 markdown_config_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
264 {
265   MarkdownConfig *conf = MARKDOWN_CONFIG(obj);
266 
267   switch (prop_id) {
268     case PROP_TEMPLATE_FILE:
269     {
270       gchar *tmpl_file;
271       tmpl_file = markdown_config_get_string_key(conf, "general", "template", "");
272       /* If empty, use default template.html file. */
273       if (!tmpl_file || !tmpl_file[0]) {
274         gchar *dn;
275         g_free(tmpl_file);
276         dn = g_path_get_dirname(conf->priv->filename);
277         tmpl_file = g_build_filename(dn, "template.html", NULL);
278         g_free(dn);
279       }
280       g_value_set_string(value, tmpl_file);
281       g_free(tmpl_file);
282       break;
283     }
284     case PROP_FONT_NAME:
285     {
286       gchar *font_name;
287       font_name = markdown_config_get_string_key(conf, "view", "font_name", "Serif");
288       g_value_set_string(value, font_name);
289       g_free(font_name);
290       break;
291     }
292     case PROP_CODE_FONT_NAME:
293     {
294       gchar *font_name;
295       font_name = markdown_config_get_string_key(conf, "view", "code_font_name", "Monospace");
296       g_value_set_string(value, font_name);
297       g_free(font_name);
298       break;
299     }
300     case PROP_FONT_POINT_SIZE:
301     {
302       guint font_size;
303       font_size = markdown_config_get_uint_key(conf, "view", "font_point_size", 12);
304       g_value_set_uint(value, font_size);
305       break;
306     }
307     case PROP_CODE_FONT_POINT_SIZE:
308     {
309       guint font_size;
310       font_size = markdown_config_get_uint_key(conf, "view", "code_font_point_size", 12);
311       g_value_set_uint(value, font_size);
312       break;
313     }
314     case PROP_BG_COLOR:
315     {
316       gchar *bg_color;
317       bg_color = markdown_config_get_string_key(conf, "view", "bg_color", "#ffffff");
318       g_value_set_string(value, bg_color);
319       g_free(bg_color);
320       break;
321     }
322     case PROP_FG_COLOR:
323     {
324       gchar *fg_color;
325       fg_color = markdown_config_get_string_key(conf, "view", "fg_color", "#000000");
326       g_value_set_string(value, fg_color);
327       g_free(fg_color);
328       break;
329     }
330     case PROP_VIEW_POS:
331     {
332       guint view_pos;
333       view_pos = markdown_config_get_uint_key(conf, "view", "position", 0);
334       g_value_set_uint(value, view_pos);
335       break;
336     }
337     default:
338       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
339       break;
340   }
341 }
342 
343 static void
markdown_install_class_properties(GObjectClass * gclass,guint n_pspecs,GParamSpec ** pspecs)344 markdown_install_class_properties(GObjectClass *gclass, guint n_pspecs,
345   GParamSpec **pspecs)
346 {
347 #if GLIB_CHECK_VERSION(2, 26, 0)
348   g_object_class_install_properties(gclass, n_pspecs, pspecs);
349 #else
350   guint i;
351   for (i = 1; i < n_pspecs; i++)
352     g_object_class_install_property(gclass, i, pspecs[i]);
353 #endif
354 }
355 
356 static void
markdown_config_class_init(MarkdownConfigClass * klass)357 markdown_config_class_init(MarkdownConfigClass *klass)
358 {
359   GObjectClass *g_object_class;
360 
361   g_object_class = G_OBJECT_CLASS(klass);
362   g_object_class->finalize = markdown_config_finalize;
363   g_object_class->set_property = markdown_config_set_property;
364   g_object_class->get_property = markdown_config_get_property;
365   g_type_class_add_private((gpointer)klass, sizeof(MarkdownConfigPrivate));
366 
367   md_props[PROP_TEMPLATE_FILE] = g_param_spec_string("template-file", "TemplateFile",
368     "HTML template file for preview", "", G_PARAM_READWRITE);
369   md_props[PROP_FONT_NAME] = g_param_spec_string("font-name", "FontName",
370     "Font family name", "Serif", G_PARAM_READWRITE);
371   md_props[PROP_CODE_FONT_NAME] = g_param_spec_string("code-font-name", "CodeFontName",
372     "Font family for code blocks", "Monospace", G_PARAM_READWRITE);
373   md_props[PROP_FONT_POINT_SIZE] = g_param_spec_uint("font-point-size", "FontPointSize",
374     "Size in points of the font", 2, 100, 12, G_PARAM_READWRITE);
375   md_props[PROP_CODE_FONT_POINT_SIZE] = g_param_spec_uint("code-font-point-size",
376     "CodeFontPointSize", "Size in points of the font for code blocks", 2, 100, 12,
377     G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
378   md_props[PROP_BG_COLOR] = g_param_spec_string("bg-color", "BackgroundColor",
379     "Background colour of the page", "#ffffff", G_PARAM_READWRITE);
380   md_props[PROP_FG_COLOR] = g_param_spec_string("fg-color", "ForegroundColor",
381     "Foreground colour of the page", "#000000", G_PARAM_READWRITE);
382   md_props[PROP_VIEW_POS] = g_param_spec_uint("view-pos", "ViewPosition",
383     "Notebook where the view will be positioned", 0,
384     MARKDOWN_CONFIG_VIEW_POS_MAX-1, (guint) MARKDOWN_CONFIG_VIEW_POS_SIDEBAR,
385     G_PARAM_READWRITE);
386 
387   markdown_install_class_properties(g_object_class, PROP_LAST, md_props);
388 }
389 
390 
391 static void
markdown_config_finalize(GObject * object)392 markdown_config_finalize(GObject *object)
393 {
394   MarkdownConfig *self;
395 
396   g_return_if_fail(MARKDOWN_IS_CONFIG(object));
397 
398   self = MARKDOWN_CONFIG(object);
399 
400   if (self->priv->handle != 0) {
401     g_source_remove(self->priv->handle);
402     markdown_config_save(self);
403   }
404 
405   g_free(self->priv->filename);
406   g_key_file_free(self->priv->kf);
407 
408   G_OBJECT_CLASS(markdown_config_parent_class)->finalize (object);
409 }
410 
411 
412 static void
markdown_config_init(MarkdownConfig * self)413 markdown_config_init(MarkdownConfig *self)
414 {
415   self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, MARKDOWN_TYPE_CONFIG, MarkdownConfigPrivate);
416 }
417 
418 
419 MarkdownConfig *
markdown_config_new(const gchar * filename)420 markdown_config_new(const gchar *filename)
421 {
422   MarkdownConfig *conf = g_object_new(MARKDOWN_TYPE_CONFIG, NULL);
423   GError *error = NULL;
424 
425   g_return_val_if_fail(filename, conf);
426 
427   conf->priv->filename = g_strdup(filename);
428   init_conf_file(conf);
429   conf->priv->kf = g_key_file_new();
430   if (!g_key_file_load_from_file(conf->priv->kf, conf->priv->filename,
431     G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error))
432   {
433     g_warning("Error loading configuration file: %s", error->message);
434     g_error_free(error); error = NULL;
435   }
436 
437   conf->priv->initialized = TRUE;
438 
439   return conf;
440 }
441 
442 gboolean
markdown_config_save(MarkdownConfig * conf)443 markdown_config_save(MarkdownConfig *conf)
444 {
445   gchar *contents;
446   gsize len;
447   gboolean success = FALSE;
448   GError *error = NULL;
449 
450   contents = g_key_file_to_data(conf->priv->kf, &len, &error);
451 
452   /*g_debug("Saving: %s\n%s", conf->priv->filename, contents);*/
453 
454   if (error) {
455     g_warning("Error getting config data as string: %s", error->message);
456     g_error_free(error); error = NULL;
457     return success;
458   }
459 
460   success = g_file_set_contents(conf->priv->filename, contents, len, &error);
461   g_free(contents);
462 
463   if (!success) {
464     g_warning("Error writing config data to disk: %s", error->message);
465     g_error_free(error); error = NULL;
466   }
467 
468   return success;
469 }
470 
471 static gchar *
color_button_get_color(GtkColorButton * color_button)472 color_button_get_color(GtkColorButton *color_button)
473 {
474   MarkdownColor color;
475 
476   markdown_gtk_color_button_get_color(color_button, &color);
477 
478   return g_strdup_printf("#%02x%02x%02x", color.red, color.green, color.blue);
479 }
480 
481 static gboolean
get_font_info(const gchar * font_desc,gchar ** font_name,guint * font_size)482 get_font_info(const gchar *font_desc, gchar **font_name, guint *font_size)
483 {
484   gboolean success = FALSE;
485   PangoFontDescription *pfd;
486 
487   pfd = pango_font_description_from_string(font_desc);
488   if (pfd) {
489     *font_name = g_strdup(pango_font_description_get_family(pfd));
490     *font_size = (guint) (pango_font_description_get_size(pfd) / PANGO_SCALE);
491     success = TRUE;
492     pango_font_description_free(pfd);
493   }
494 
495   return success;
496 }
497 
498 static void
on_dialog_response(MarkdownConfig * conf,gint response_id,GtkDialog * dialog)499 on_dialog_response(MarkdownConfig *conf, gint response_id, GtkDialog *dialog)
500 {
501   if (response_id == GTK_RESPONSE_APPLY || response_id == GTK_RESPONSE_OK) {
502     GtkWidget *wid = conf->priv->widgets.pos_sb_radio;
503     gboolean pos_sidebar = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wid));
504     gchar *bg_color, *fg_color;
505     gchar *tmpl_file = NULL, *fnt = NULL, *code_fnt = NULL;
506     guint fnt_size = 0, code_fnt_size = 0;
507     const gchar *font_desc;
508     MarkdownConfigViewPos view_pos;
509 
510     view_pos = pos_sidebar ? MARKDOWN_CONFIG_VIEW_POS_SIDEBAR : MARKDOWN_CONFIG_VIEW_POS_MSGWIN;
511 
512     bg_color = color_button_get_color(GTK_COLOR_BUTTON(conf->priv->widgets.bg_color_button));
513     fg_color = color_button_get_color(GTK_COLOR_BUTTON(conf->priv->widgets.fg_color_button));
514 
515     font_desc = gtk_font_button_get_font_name(GTK_FONT_BUTTON(conf->priv->widgets.font_button));
516     get_font_info(font_desc, &fnt, &fnt_size);
517 
518     font_desc = gtk_font_button_get_font_name(GTK_FONT_BUTTON(conf->priv->widgets.code_font_button));
519     get_font_info(font_desc, &code_fnt, &code_fnt_size);
520 
521     tmpl_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(conf->priv->widgets.tmpl_file_button));
522 
523     g_object_set(conf,
524                  "font-name", fnt,
525                  "font-point-size", fnt_size,
526                  "code-font-name", code_fnt,
527                  "code-font-point-size", code_fnt_size,
528                  "view-pos", view_pos,
529                  "bg-color", bg_color,
530                  "fg-color", fg_color,
531                  "template-file", tmpl_file,
532                  NULL);
533 
534     g_free(fnt);
535     g_free(code_fnt);
536     g_free(bg_color);
537     g_free(fg_color);
538     g_free(tmpl_file);
539   }
540 }
541 
markdown_config_gui(MarkdownConfig * conf,GtkDialog * dialog)542 GtkWidget *markdown_config_gui(MarkdownConfig *conf, GtkDialog *dialog)
543 {
544   GSList *grp = NULL;
545   GtkWidget *table, *label, *hbox, *wid;
546   gchar *tmpl_file=NULL, *fnt=NULL, *code_fnt=NULL, *bg=NULL, *fg=NULL;
547   guint view_pos=0, fnt_sz=0, code_fnt_sz=0;
548 
549   g_object_get(conf,
550                "view-pos", &view_pos,
551                "font-name", &fnt,
552                "code-font-name", &code_fnt,
553                "font-point-size", &fnt_sz,
554                "code-font-point-size", &code_fnt_sz,
555                "bg-color", &bg,
556                "fg-color", &fg,
557                "template-file", &tmpl_file,
558                NULL);
559 
560   table = markdown_gtk_table_new(6, 2, FALSE);
561   markdown_gtk_table_set_col_spacing(MARKDOWN_GTK_TABLE(table), 6);
562   markdown_gtk_table_set_row_spacing(MARKDOWN_GTK_TABLE(table), 6);
563 
564   conf->priv->widgets.table = table;
565 
566   { /* POSITION OF VIEW */
567     label = gtk_label_new(_("Position:"));
568     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
569     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL);
570 
571     hbox = gtk_hbox_new(FALSE, 6);
572 
573     wid = gtk_radio_button_new_with_label(grp, _("Sidebar"));
574     grp = gtk_radio_button_get_group(GTK_RADIO_BUTTON(wid));
575     gtk_box_pack_start(GTK_BOX(hbox), wid, FALSE, TRUE, 0);
576     conf->priv->widgets.pos_sb_radio = wid;
577     if (((MarkdownConfigViewPos) view_pos) == MARKDOWN_CONFIG_VIEW_POS_SIDEBAR) {
578       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wid), TRUE);
579     }
580 
581     wid = gtk_radio_button_new_with_label(grp, _("Message Window"));
582     grp = gtk_radio_button_get_group(GTK_RADIO_BUTTON(wid));
583     gtk_box_pack_start(GTK_BOX(hbox), wid, FALSE, TRUE, 0);
584     conf->priv->widgets.pos_mw_radio = wid;
585     if (((MarkdownConfigViewPos) view_pos) == MARKDOWN_CONFIG_VIEW_POS_MSGWIN) {
586       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wid), TRUE);
587     }
588 
589     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), hbox, 1, 2, 0, 1, GTK_FILL, GTK_FILL);
590   }
591 
592   { /* FONT BUTTON */
593     gchar *font_desc;
594 
595     label = gtk_label_new(_("Font:"));
596     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
597     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL);
598 
599     font_desc = g_strdup_printf("%s %d", fnt, fnt_sz);
600     wid = gtk_font_button_new_with_font(font_desc);
601     conf->priv->widgets.font_button = wid;
602     g_free(font_desc);
603 
604     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), wid, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL);
605 
606     g_free(fnt);
607   }
608 
609   { /* CODE FONT BUTTON */
610     gchar *font_desc;
611 
612     label = gtk_label_new(_("Code Font:"));
613     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
614     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL);
615 
616     font_desc = g_strdup_printf("%s %d", code_fnt, code_fnt_sz);
617     wid = gtk_font_button_new_with_font(font_desc);
618     conf->priv->widgets.code_font_button = wid;
619     g_free(font_desc);
620 
621     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), wid, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL);
622 
623     g_free(code_fnt);
624   }
625 
626   { /* BG COLOR */
627     MarkdownColor bgclr;
628 
629     label = gtk_label_new(_("BG Color:"));
630     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
631     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL);
632 
633     markdown_color_parse(bg, &bgclr);
634 
635     wid = markdown_gtk_color_button_new_with_color(&bgclr);
636     conf->priv->widgets.bg_color_button = wid;
637     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), wid, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, GTK_FILL);
638 
639     g_free(bg);
640   }
641 
642   { /* FG COLOR */
643     MarkdownColor fgclr;
644 
645     label = gtk_label_new(_("FG Color:"));
646     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
647     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL);
648 
649     markdown_color_parse(fg, &fgclr);
650 
651     wid = markdown_gtk_color_button_new_with_color(&fgclr);
652     conf->priv->widgets.fg_color_button = wid;
653     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), wid, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND, GTK_FILL);
654 
655     g_free(fg);
656   }
657 
658   { /* TEMPLATE FILE */
659     label = gtk_label_new(_("Template:"));
660     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
661     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL, GTK_FILL);
662 
663     wid = gtk_file_chooser_button_new(_("Select Template File"),
664       GTK_FILE_CHOOSER_ACTION_OPEN);
665     conf->priv->widgets.tmpl_file_button = wid;
666     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(wid), g_get_home_dir());
667     if (tmpl_file && tmpl_file[0]) {
668       gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(wid), tmpl_file);
669     }
670     markdown_gtk_table_attach(MARKDOWN_GTK_TABLE(table), wid, 1, 2, 5, 6, GTK_FILL | GTK_EXPAND, GTK_FILL);
671 
672     g_free(tmpl_file);
673   }
674 
675   conf->priv->dlg_handle = g_signal_connect_swapped(dialog, "response",
676     G_CALLBACK(on_dialog_response), conf);
677 
678   gtk_widget_show_all(table);
679 
680   return table;
681 }
682 
683 const gchar *
markdown_config_get_template_text(MarkdownConfig * conf)684 markdown_config_get_template_text(MarkdownConfig *conf)
685 {
686   g_return_val_if_fail(conf, NULL);
687   if (!conf->priv->tmpl_text) {
688     markdown_config_load_template_text(conf);
689   }
690   return (const gchar *) conf->priv->tmpl_text;
691 }
692 
693 gchar *
markdown_config_get_dirname(MarkdownConfig * conf)694 markdown_config_get_dirname(MarkdownConfig *conf)
695 {
696   g_return_val_if_fail(conf, NULL);
697   return g_path_get_dirname(conf->priv->filename);
698 }
699 
markdown_config_get_view_pos(MarkdownConfig * conf)700 MarkdownConfigViewPos markdown_config_get_view_pos(MarkdownConfig *conf)
701 {
702   guint view_pos;
703   g_return_val_if_fail(MARKDOWN_IS_CONFIG(conf), MARKDOWN_CONFIG_VIEW_POS_SIDEBAR);
704   g_object_get(conf, "view-pos", &view_pos, NULL);
705   return (MarkdownConfigViewPos) view_pos;
706 }
707 
markdown_config_set_view_pos(MarkdownConfig * conf,MarkdownConfigViewPos view_pos)708 void markdown_config_set_view_pos(MarkdownConfig *conf, MarkdownConfigViewPos view_pos)
709 {
710   g_return_if_fail(MARKDOWN_IS_CONFIG(conf));
711   g_object_set(conf, "view-pos", view_pos, NULL);
712 }
713