1 /*
2  *  gretl -- Gnu Regression, Econometrics and Time-series Library
3  *  Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
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 3 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, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "gretl.h"
21 #include "version.h"
22 #include "filelists.h"
23 #include "gretl_www.h"
24 #include "dlgutils.h"
25 #include "fileselect.h"
26 #include "menustate.h"
27 #include "session.h"
28 #include "textbuf.h"
29 #include "ssheet.h"
30 #include "selector.h"
31 #include "gpt_control.h"
32 #include "tabwin.h"
33 #include "build.h"
34 #include "addons_utils.h"
35 
36 #ifdef HAVE_GTKSV_COMPLETION
37 # include "completions.h"
38 #endif
39 
40 #include "libset.h"
41 #include "texprint.h"
42 #include "uservar.h"
43 #include "gretl_foreign.h"
44 
45 #include <unistd.h>
46 #include <sys/types.h>
47 #include <dirent.h>
48 
49 #if GTK_MAJOR_VERSION == 3
50 # define HAVE_GTK_FONT_CHOOSER 1
51 #else
52 # define HAVE_GTK_FONT_CHOOSER 0
53 #endif
54 
55 #ifdef G_OS_WIN32
56 # include <windows.h>
57 # include "gretlwin32.h"
58 #endif
59 
60 #if HAVE_GTK_FONT_CHOOSER
61 # include "fontfilter.h"
62 #else
63 # include "gtkfontselhack.h"
64 #endif
65 
66 #if defined(OS_OSX) && defined(HAVE_MAC_THEMES)
67 # define MAC_THEMING
68 #endif
69 
70 static char rcfile[FILENAME_MAX];
71 static char http_proxy[128];
72 static int use_proxy;
73 
74 static ConfigPaths paths;
75 
76 static void make_prefs_tab (GtkWidget *notebook, int tab, int console);
77 static void apply_prefs_changes (GtkWidget *widget, GtkWidget *parent);
78 
79 #ifndef G_OS_WIN32
80 static int read_gretlrc (void);
81 #endif
82 
83 /* font handling */
84 
85 static int tmpfontscale;
86 static char system_appfont[64];
87 
88 #if defined(G_OS_WIN32)
89 static char fixedfontname[MAXLEN] = "Courier New 10";
90 static char default_fixedfont[64] = "Courier New 10";
91 #elif defined(OS_OSX)
92 static char fixedfontname[MAXLEN] = "Menlo 13";
93 static char default_fixedfont[64] = "Menlo 13";
94 #else
95 static char fixedfontname[MAXLEN] = "monospace 10";
96 static char default_fixedfont[64] = "monospace 10";
97 #endif
98 
99 #if defined(G_OS_WIN32)
100 static char appfontname[MAXLEN] = "";
101 #elif defined(OS_OSX)
102 static char appfontname[MAXLEN] = "Lucida Grande 13";
103 #else
104 static char appfontname[MAXLEN] = "sans 10";
105 #endif
106 
107 PangoFontDescription *fixed_font;
108 
109 /* end font handling */
110 
111 int swallow = 0;
112 
113 static int usecwd;
114 static int shellok;
115 static int manpref;
116 static int robust_z;
117 static int autoicon = 1;
118 static int session_prompt = 1;
119 static int keep_folder = 1;
120 static int tabbed_editor = 1;
121 static int tabbed_models = 0;
122 static int auto_collect = 0;
123 
124 static int script_output_policy;
125 static char datapage[24] = "Gretl";
126 static char scriptpage[24] = "Gretl";
127 static char author_mail[32];
128 static char sview_style[32] = "classic";
129 static char graph_theme[24] = "dark2";
130 static char gpcolors[18];
131 
132 static int hc_by_default;
133 static char langpref[32];
134 static char hc_xsect[5] = "HC1";
135 static char hc_tseri[5] = "HAC";
136 static char hc_panel[9] = "Arellano";
137 static char hc_garch[5] = "QML";
138 
139 #ifdef HAVE_MPI
140 # ifdef G_OS_WIN32
141 static char mpi_pref[8] = "MS-MPI";
142 # else
143 static char mpi_pref[8] = "OpenMPI";
144 # endif
145 #endif
146 
147 static int lcnumeric = 1;
148 static double graph_scale = 1.0;
149 static int icon_sizing = ICON_SIZE_AUTO;
150 
151 #if defined(MAC_THEMING)
152 static char themepref[12] = "Adwaita";
153 #elif defined(G_OS_WIN32)
154 static char themepref[12] = "Windows-10";
155 #endif
156 
157 /* model table display variables */
158 static int modtab_colheads;
159 static gboolean modtab_tstats;
160 static gboolean modtab_pvalues;
161 static gboolean modtab_asterisks = TRUE;
162 static int modtab_digits = 4;
163 static gboolean modtab_decimals;
164 
165 typedef enum {
166     USERSET  = 1 << 0,  /* user-level variable */
167     BOOLSET  = 1 << 1,  /* boolean value (user) */
168     INTSET   = 1 << 2,  /* integer value (user) */
169     FLOATSET = 1 << 3,  /* floating point value (user) */
170     LISTSET  = 1 << 4,  /* user selection from fixed menu */
171     RADIOSET = 1 << 5,  /* user int, from fixed menu */
172     INVISET  = 1 << 6,  /* not visible in preferences dialog */
173     FIXSET   = 1 << 7,  /* setting fixed by admin (Windows network use) */
174     MACHSET  = 1 << 8,  /* "local machine" setting */
175     BROWSER  = 1 << 9,  /* wants "Browse" button */
176     RESTART  = 1 << 10, /* needs program restart to take effect */
177     GOTSET   = 1 << 11, /* dynamic: already found a setting */
178     SKIPSET  = 1 << 12, /* for string value, skip empty value */
179     SPINSET  = 1 << 13  /* integer value: represented by spin-button */
180 } rcflags;
181 
182 typedef struct {
183     char *key;         /* config file variable name */
184     char *description; /* string shown in the preferences dialog */
185     char *link;        /* in case of radio button pair, alternate string */
186     void *var;         /* pointer to variable */
187     rcflags flags;     /* see above */
188     int len;           /* storage size for string variable (also see Note) */
189     short tab;         /* which tab (if any) does the item fall under? */
190     GtkWidget *widget;
191 } RCVAR;
192 
193 /* Note: actually "len" above is overloaded: if an rc_var is of
194    type BOOLSET and not part of a radio group, then a non-zero value
195    for len will link the var's toggle button with the sensitivity of
196    the preceding rc_var's entry field.  For example, the "use_proxy"
197    button controls the sensitivity of the "http_proxy" entry widget.
198 */
199 
200 RCVAR rc_vars[] = {
201     { "gretldir", N_("Main gretl directory"), NULL, paths.gretldir,
202       MACHSET | BROWSER, sizeof paths.gretldir, TAB_MAIN, NULL },
203     { "workdir", N_("User's gretl directory"), NULL, paths.workdir,
204       INVISET, sizeof paths.workdir, TAB_MAIN, NULL },
205 #ifndef G_OS_WIN32
206     { "winsize", N_("Remember main window size"), NULL, &winsize,
207       BOOLSET, 0, TAB_MAIN, NULL },
208 #endif
209 #ifdef ENABLE_NLS
210     { "lcnumeric", N_("Use locale setting for decimal point"), NULL, &lcnumeric,
211       BOOLSET | RESTART, 0, TAB_MAIN, NULL },
212 #endif
213 #if defined(MAC_THEMING) || defined(G_OS_WIN32)
214     { "themepref", N_("Theme preference"), NULL, themepref,
215       LISTSET | RESTART, 12, TAB_MAIN, NULL },
216 #endif
217 #if !defined(G_OS_WIN32) && !defined(OS_OSX)
218     { "browser", N_("Web browser"), NULL, Browser,
219       MACHSET | BROWSER, MAXSTR, TAB_PROGS, NULL },
220 #endif
221     { "shellok", N_("Allow shell commands"), NULL, &shellok,
222       BOOLSET, 0, TAB_MAIN, NULL },
223     { "autoicon", N_("Show icon view automatically"), NULL, &autoicon,
224       BOOLSET, 0, TAB_MAIN, NULL },
225     { "tabmodels", N_("Model viewer uses tabs"), NULL, &tabbed_models,
226       BOOLSET, 0, TAB_MAIN, NULL },
227     { "session_prompt", N_("Prompt to save session"), NULL, &session_prompt,
228       BOOLSET, 0, TAB_MAIN, NULL },
229     { "collect_plots", N_("Enable collecting plots"), NULL, &auto_collect,
230       BOOLSET, 0, TAB_MAIN, NULL },
231     { "swallow_console", N_("Main window includes console"), NULL, &swallow,
232       BOOLSET | RESTART, 0, TAB_MAIN, NULL },
233     { "icon_sizing", N_("Toolbar icon size"), NULL, &icon_sizing,
234       LISTSET | INTSET | RESTART, 0, TAB_MAIN, NULL },
235     { "usecwd", N_("Set working directory from shell"), NULL, &usecwd,
236       INVISET | BOOLSET | RESTART, 0, TAB_NONE, NULL },
237     { "keepfolder", N_("File selector remembers folder"), NULL, &keep_folder,
238       INVISET | BOOLSET, 0, TAB_NONE, NULL },
239 #ifdef ENABLE_NLS
240     { "langpref", N_("Language preference"), NULL, langpref,
241       LISTSET | RESTART, 32, TAB_MAIN, NULL },
242 #endif
243     { "graph_scale", N_("Default graph scale"), NULL, &graph_scale,
244       LISTSET | FLOATSET, 0, TAB_MAIN, NULL },
245     { "graph_theme", N_("Graph theme"), NULL, graph_theme,
246       LISTSET, sizeof graph_theme, TAB_MAIN, NULL },
247 #if !defined(G_OS_WIN32) || !defined(PKGBUILD)
248     { "gnuplot", N_("Command to launch gnuplot"), NULL, paths.gnuplot,
249       MACHSET | BROWSER, MAXLEN, TAB_PROGS, NULL },
250 #endif
251     { "Rcommand", N_("Command to launch GNU R"), NULL, Rcommand,
252       MACHSET | BROWSER, MAXSTR, TAB_PROGS, NULL },
253 #ifdef G_OS_WIN32
254     { "Rbin", N_("Path to R.exe"), NULL, paths.rbinpath,
255       MACHSET | BROWSER, MAXSTR, TAB_PROGS, NULL },
256 #endif
257     { "latex", N_("Command to compile TeX files"), NULL, latex,
258       MACHSET | BROWSER, MAXSTR, TAB_PROGS, NULL },
259 #if !defined(G_OS_WIN32) && !defined(OS_OSX)
260     { "viewps", N_("Command to view postscript files"), NULL, viewps,
261       MACHSET | BROWSER, MAXSTR, TAB_PROGS, NULL },
262     { "viewpdf", N_("Command to view PDF files"), NULL, viewpdf,
263       MACHSET | BROWSER, MAXSTR, TAB_PROGS, NULL },
264 #endif
265     { "calculator", N_("Calculator"), NULL, calculator,
266       USERSET | BROWSER, MAXSTR, TAB_PROGS, NULL },
267 #ifdef HAVE_X12A
268     { "x12a", N_("Path to x12arima (or x13)"), NULL, paths.x12a,
269       MACHSET | BROWSER, sizeof paths.x12a, TAB_PROGS, NULL },
270 #endif
271 #ifdef HAVE_TRAMO
272     { "tramo", N_("Path to tramo"), NULL, paths.tramo,
273       MACHSET | BROWSER, sizeof paths.tramo, TAB_PROGS, NULL},
274 #endif
275 #ifdef USE_RLIB
276     { "Rlib", N_("Path to R library"), NULL, paths.rlibpath,
277       MACHSET | BROWSER, sizeof paths.rlibpath, TAB_PROGS, NULL},
278 #endif
279     { "ox", N_("Path to oxl executable"), NULL, paths.oxlpath,
280       MACHSET | BROWSER, sizeof paths.oxlpath, TAB_PROGS, NULL},
281     { "octave", N_("Path to octave executable"), NULL, paths.octpath,
282       MACHSET | BROWSER, sizeof paths.octpath, TAB_PROGS, NULL},
283     { "stata", N_("Path to Stata executable"), NULL, paths.statapath,
284       MACHSET | BROWSER, sizeof paths.statapath, TAB_PROGS, NULL},
285     { "python", N_("Path to Python executable"), NULL, paths.pypath,
286       MACHSET | BROWSER, sizeof paths.pypath, TAB_PROGS, NULL},
287     { "julia", N_("Path to Julia executable"), NULL, paths.jlpath,
288       MACHSET | BROWSER, sizeof paths.jlpath, TAB_PROGS, NULL},
289 #ifndef PKGBUILD
290     { "lpsolve", N_("Path to lpsolve library"), NULL, paths.lppath,
291       MACHSET | BROWSER, sizeof paths.lppath, TAB_PROGS, NULL},
292 #endif
293 #ifdef HAVE_MPI
294     { "mpiexec", N_("Path to mpiexec"), NULL, paths.mpiexec,
295       MACHSET | BROWSER, sizeof paths.mpiexec, TAB_MPI, NULL},
296     { "mpi_hosts", N_("Path to MPI hosts file"), NULL, paths.mpi_hosts,
297       MACHSET | BROWSER, sizeof paths.mpi_hosts, TAB_MPI, NULL},
298     { "mpi_pref", N_("Installed MPI variant"), NULL, mpi_pref,
299       LISTSET, 8, TAB_MPI, NULL},
300 #endif
301     { "dbproxy", N_("HTTP proxy"), NULL, http_proxy,
302       USERSET, sizeof http_proxy, TAB_NET, NULL },
303     { "useproxy", N_("Use HTTP proxy"), NULL, &use_proxy,
304       BOOLSET, 1, TAB_NET, NULL },
305     { "Fixed_font", N_("Monospaced font"), NULL, fixedfontname,
306       USERSET, sizeof fixedfontname, TAB_NONE, NULL },
307     { "App_font", N_("Menu font"), NULL, appfontname,
308       USERSET, sizeof appfontname, TAB_NONE, NULL },
309     { "DataPage", "Default data page", NULL, datapage,
310       INVISET, sizeof datapage, TAB_NONE, NULL },
311     { "ScriptPage", "Default script page", NULL, scriptpage,
312       INVISET, sizeof scriptpage, TAB_NONE, NULL },
313     { "Png_font", N_("PNG graph font"), NULL, paths.pngfont,
314       INVISET, sizeof paths.pngfont, TAB_NONE, NULL },
315     { "Gp_extra_colors", N_("Gnuplot extra colors"), NULL, gpcolors,
316       INVISET, sizeof gpcolors, TAB_NONE, NULL },
317     { "tabwidth", N_("Number of spaces per tab"), NULL, &tabwidth,
318       INTSET | SPINSET, 0, TAB_EDITOR, NULL },
319     { "smarttab", N_("\"Smart\" Tab and Enter"), NULL, &smarttab,
320       BOOLSET, 0, TAB_EDITOR, NULL },
321     { "script_line_numbers", N_("Show line numbers"), NULL, &script_line_numbers,
322       BOOLSET, 0, TAB_EDITOR, NULL },
323     { "tabedit", N_("Script editor uses tabs"), NULL, &tabbed_editor,
324       BOOLSET, 0, TAB_EDITOR, NULL },
325 #ifdef HAVE_GTKSV_COMPLETION
326     { "hansl_completion", N_("Auto-completion"), NULL, &hansl_completion,
327       LISTSET | INTSET, 0, TAB_EDITOR, NULL },
328     { "console_completion", N_("Auto-completion"), NULL, &console_completion,
329       LISTSET | INTSET | INVISET, 0, TAB_EDITOR, NULL },
330 #endif
331     { "script_auto_bracket", N_("Enable auto-brackets"), NULL, &script_auto_bracket,
332       BOOLSET, 0, TAB_EDITOR, NULL },
333     { "sview_style", N_("Highlighting style"), NULL, &sview_style,
334       LISTSET, sizeof sview_style, TAB_EDITOR, NULL },
335     { "main_width", "main window width", NULL, &mainwin_width,
336       INVISET | INTSET, 0, TAB_NONE, NULL },
337     { "main_height", "main window height", NULL, &mainwin_height,
338       INVISET | INTSET, 0, TAB_NONE, NULL },
339     { "main_x", "main window x position", NULL, &main_x,
340       INVISET | INTSET, 0, TAB_NONE, NULL },
341     { "main_y", "main window y position", NULL, &main_y,
342       INVISET | INTSET, 0, TAB_NONE, NULL },
343     { "script_output_policy", "stickiness of output", NULL, &script_output_policy,
344       INVISET | INTSET, 0, TAB_NONE, NULL },
345     { "HC_by_default", N_("Use robust covariance matrix by default"), NULL,
346       &hc_by_default, BOOLSET, 0, TAB_VCV, NULL },
347     { "robust_z", N_("Use the normal distribution for robust p-values"), NULL,
348       &robust_z, BOOLSET, 0, TAB_VCV, NULL },
349     { "HC_xsect", N_("For cross-sectional data"), NULL, hc_xsect,
350       LISTSET, 5, TAB_VCV, NULL },
351     { "HC_tseri", N_("For time-series data"), NULL, hc_tseri,
352       LISTSET, 5, TAB_VCV, NULL },
353     { "HC_panel", N_("For panel data"), NULL, hc_panel,
354       LISTSET, 9, TAB_VCV, NULL },
355     { "HC_garch", N_("For GARCH estimation"), NULL, hc_garch,
356       LISTSET, 5, TAB_VCV, NULL },
357     { "manpref", N_("PDF manual preference"), NULL, &manpref,
358       LISTSET | INTSET, 0, TAB_MAIN, NULL },
359     { "modtab_colheads", "Model table column heads", NULL, &modtab_colheads,
360       INVISET | INTSET, 0, TAB_NONE, NULL },
361     { "modtab_tstats", "Model table t-ratios", NULL, &modtab_tstats,
362       INVISET | BOOLSET, 0, TAB_NONE, NULL },
363     { "modtab_pvalues", "Model table p-values", NULL, &modtab_pvalues,
364       INVISET | BOOLSET, 0, TAB_NONE, NULL },
365     { "modtab_asterisks", "Model table asterisks", NULL, &modtab_asterisks,
366       INVISET | BOOLSET, 0, TAB_NONE, NULL },
367     { "modtab_digits", "Model table digits", NULL, &modtab_digits,
368       INVISET | INTSET, 0, TAB_NONE, NULL },
369     { "modtab_decimals", "Model table decimal places", NULL, &modtab_decimals,
370       INVISET | INTSET, 0, TAB_NONE, NULL },
371     { "author_mail", "Package author email", NULL, &author_mail,
372       INVISET | SKIPSET, sizeof author_mail, TAB_NONE, NULL },
373     { NULL, NULL, NULL, NULL, 0, 0, TAB_NONE, NULL }
374 };
375 
376 /* accessor functions */
377 
using_hc_by_default(void)378 int using_hc_by_default (void)
379 {
380     return hc_by_default;
381 }
382 
get_manpref(void)383 int get_manpref (void)
384 {
385     return manpref;
386 }
387 
set_datapage(const char * str)388 void set_datapage (const char *str)
389 {
390     strcpy(datapage, str);
391 }
392 
set_scriptpage(const char * str)393 void set_scriptpage (const char *str)
394 {
395     strcpy(scriptpage, str);
396 }
397 
get_datapage(void)398 const char *get_datapage (void)
399 {
400     return datapage;
401 }
402 
get_scriptpage(void)403 const char *get_scriptpage (void)
404 {
405     return scriptpage;
406 }
407 
set_author_mail(const char * s)408 void set_author_mail (const char *s)
409 {
410     if (s != NULL && strlen(s) < sizeof author_mail) {
411 	strcpy(author_mail, s);
412     } else {
413 	author_mail[0] = '\0';
414     }
415 }
416 
get_author_mail(void)417 const char *get_author_mail (void)
418 {
419     return author_mail;
420 }
421 
get_sourceview_style(void)422 const char *get_sourceview_style (void)
423 {
424     return sview_style;
425 }
426 
autoicon_on(void)427 int autoicon_on (void)
428 {
429     if (dataset != NULL && dataset->v > 0) {
430 	return autoicon;
431     } else if (n_user_matrices() > 0) {
432 	return autoicon;
433     } else if (n_user_bundles() > 0) {
434 	return autoicon;
435     } else {
436 	return 0;
437     }
438 }
439 
get_icon_sizing(void)440 int get_icon_sizing (void)
441 {
442     return icon_sizing;
443 }
444 
use_tabbed_editor(void)445 int use_tabbed_editor (void)
446 {
447     return tabbed_editor;
448 }
449 
use_tabbed_model_viewer(void)450 int use_tabbed_model_viewer (void)
451 {
452     return tabbed_models;
453 }
454 
session_prompt_on(void)455 int session_prompt_on (void)
456 {
457     return session_prompt;
458 }
459 
set_session_prompt(int val)460 void set_session_prompt (int val)
461 {
462     session_prompt = val;
463 }
464 
get_keep_folder(void)465 int get_keep_folder (void)
466 {
467     return keep_folder;
468 }
469 
set_script_output_policy(int p,windata_t * vwin)470 void set_script_output_policy (int p, windata_t *vwin)
471 {
472     script_output_policy = p;
473 
474     if (script_output_policy < 0 ||
475 	script_output_policy > OUTPUT_POLICY_NEW_WINDOW) {
476 	/* invalid setting */
477 	script_output_policy = OUTPUT_POLICY_REPLACE;
478     }
479 
480     set_reuseable_output_window(p, vwin);
481 }
482 
get_script_output_policy(void)483 int get_script_output_policy (void)
484 {
485     return script_output_policy;
486 }
487 
get_model_table_prefs(int * colheads,int * use_tstats,int * do_pvals,int * do_asts,int * figs,char * fmt)488 void get_model_table_prefs (int *colheads,
489 			    int *use_tstats,
490 			    int *do_pvals,
491 			    int *do_asts,
492 			    int *figs,
493 			    char *fmt)
494 {
495     *colheads   = modtab_colheads;
496     *use_tstats = modtab_tstats;
497     *do_pvals   = modtab_pvalues;
498     *do_asts    = modtab_asterisks;
499     *figs       = modtab_digits;
500     *fmt        = modtab_decimals ? 'f' : 'g';
501 }
502 
set_model_table_prefs(int colheads,int use_tstats,int do_pvals,int do_asts,int figs,char fmt)503 void set_model_table_prefs (int colheads,
504 			    int use_tstats,
505 			    int do_pvals,
506 			    int do_asts,
507 			    int figs,
508 			    char fmt)
509 {
510     modtab_colheads  = colheads;
511     modtab_tstats    = use_tstats;
512     modtab_pvalues   = do_pvals;
513     modtab_asterisks = do_asts;
514     modtab_digits    = figs;
515     modtab_decimals  = (fmt == 'f')? 1 : 0;
516 }
517 
518 static gretlopt update_paths_opt = OPT_NONE;
519 
force_english_help(void)520 void force_english_help (void)
521 {
522     update_paths_opt |= OPT_N;
523     gretl_update_paths(&paths, update_paths_opt);
524 }
525 
fontname_get_size(const char * fontname)526 static int fontname_get_size (const char *fontname)
527 {
528     char *p = strrchr(fontname, ' ');
529 
530     return (p != NULL)? atoi(p+1) : 10;
531 }
532 
fontname_set_size(char * fontname,int size)533 static void fontname_set_size (char *fontname, int size)
534 {
535     char *p = strrchr(fontname, ' ');
536 
537     if (p != NULL) {
538 	sprintf(p, " %d", size);
539     }
540 }
541 
font_is_changed(const char * f_new,const char * f_old)542 static int font_is_changed (const char *f_new,
543 			    const char *f_old)
544 {
545     if (strcmp(f_new, f_old)) {
546 	return 1;
547     } else if (tmpfontscale > 0 &&
548 	       fontname_get_size(f_new) != tmpfontscale) {
549 	return 1;
550     } else {
551 	return 0;
552     }
553 }
554 
set_fixed_font(const char * fontname,int remember)555 void set_fixed_font (const char *fontname, int remember)
556 {
557     if (fontname == NULL) {
558 	/* initial set-up */
559 	fixed_font = pango_font_description_from_string(fixedfontname);
560     } else if (font_is_changed(fontname, fixedfontname)) {
561 	/* changed via the GUI */
562 	if (fixed_font != NULL) {
563 	    pango_font_description_free(fixed_font);
564 	}
565 	fixed_font = pango_font_description_from_string(fontname);
566 	if (remember) {
567 	    strcpy(fixedfontname, fontname);
568 	}
569 	infobox(_("This change will apply to newly opened windows"));
570     }
571 }
572 
update_persistent_graph_font(void)573 void update_persistent_graph_font (void)
574 {
575     strcpy(paths.pngfont, gretl_png_font());
576 }
577 
get_app_fontname(void)578 const char *get_app_fontname (void)
579 {
580     return appfontname;
581 }
582 
get_fixed_fontname(void)583 const char *get_fixed_fontname (void)
584 {
585     return fixedfontname;
586 }
587 
record_system_appfont(GtkSettings * settings,gchar ** pfont)588 static void record_system_appfont (GtkSettings *settings,
589 				   gchar **pfont)
590 {
591     g_object_get(G_OBJECT(settings), "gtk-font-name", pfont, NULL);
592 #if defined(G_OS_WIN32)
593     get_default_windows_app_font(system_appfont);
594 #else
595     if (*pfont != NULL) {
596 	strcpy(system_appfont, *pfont);
597     } else {
598 # if defined(OS_OSX)
599 	strcpy(system_appfont, "Lucida Grande 13");
600 # else
601 	strcpy(system_appfont, "sans 10");
602 # endif
603     }
604 #endif
605 }
606 
607 #ifdef G_OS_WIN32
608 
win32_set_font(const char * fontname,GtkSettings * settings)609 static void win32_set_font (const char *fontname,
610 			    GtkSettings *settings)
611 {
612     gchar *rc;
613 
614     rc = g_strdup_printf("style \"myfont\" {\n"
615 			 "  font_name = \"%s\"\n}\n"
616 			 "widget_class \"*\" style \"myfont\"\n"
617 			 "gtk-font-name = \"%s\"\n",
618 			 fontname, fontname);
619     gtk_rc_parse_string(rc);
620     g_object_set(G_OBJECT(settings), "gtk-font-name", fontname, NULL);
621     g_free(rc);
622 }
623 
624 #endif
625 
set_app_font(const char * fontname,int remember)626 void set_app_font (const char *fontname, int remember)
627 {
628     static int default_recorded;
629     GtkSettings *settings;
630     gchar *deffont = NULL;
631 
632 #if 0
633     fprintf(stderr, "set_app_font: fontname='%s', remember=%d, "
634 	    "appfontname='%s'\n", fontname, remember, appfontname);
635 #endif
636 
637     if (fontname != NULL && *fontname == '\0') {
638 	return;
639     }
640 
641     settings = gtk_settings_get_default();
642 
643     /* not font-related but, dammit, we want these! */
644     g_object_set(G_OBJECT(settings), "gtk-menu-images", TRUE, NULL);
645 
646     if (!default_recorded) {
647 	record_system_appfont(settings, &deffont);
648 #if 0
649 	fprintf(stderr, "record app font default: system '%s', gtk '%s'\n",
650 		system_appfont, deffont);
651 #endif
652 	default_recorded = 1;
653     }
654 
655 #ifdef G_OS_WIN32
656     if (fontname == NULL && *appfontname == '\0') {
657 	/* as we're called at initial startup from gretl.c */
658 	strcpy(appfontname, system_appfont);
659     }
660 #endif
661 
662     /* check for nothing else to be done */
663     if (deffont != NULL) {
664 	const char *test = fontname ? fontname : appfontname;
665 	int noop = 0;
666 
667 	if (!font_is_changed(test, deffont)) {
668 	    noop = 1;
669 	}
670 	g_free(deffont);
671 	if (noop) {
672 	    return;
673 	}
674     }
675 
676     if (fontname == NULL) {
677 	/* just loading @appfontname (pre-checked) */
678 #ifdef G_OS_WIN32
679 	win32_set_font(appfontname, settings);
680 #else
681 	g_object_set(G_OBJECT(settings), "gtk-font-name", appfontname, NULL);
682 #endif
683     } else {
684 	/* loading a user-specified font: check that it works */
685 	GtkWidget *w;
686 	PangoFontDescription *pfd;
687 	PangoContext *pc;
688 	PangoFont *font;
689 
690 	w = gtk_label_new("text");
691 	pfd = pango_font_description_from_string(fontname);
692 	pc = gtk_widget_get_pango_context(w);
693 	font = pango_context_load_font(pc, pfd);
694 
695 	if (font != NULL) {
696 	    /* OK, found it */
697 	    if (remember) {
698 		strcpy(appfontname, fontname);
699 	    }
700 #ifdef G_OS_WIN32
701 	    win32_set_font(fontname, settings);
702 #else
703 	    g_object_set(G_OBJECT(settings), "gtk-font-name", fontname, NULL);
704 #endif
705 	    g_object_unref(font);
706 	}
707 
708 	gtk_widget_destroy(w);
709 	pango_font_description_free(pfd);
710     }
711 }
712 
write_OK(gchar * dirname)713 static int write_OK (gchar *dirname)
714 {
715     int ok = 0;
716 
717     if (gretl_mkdir(dirname) == 0) {
718 	gchar *test = g_strdup_printf("%s%c%s", dirname, SLASH, "wtest");
719 
720 	if (test != NULL) {
721 	    ok = (gretl_test_fopen(test, "w") == 0);
722 	    g_free(test);
723 	}
724     }
725 
726     return ok;
727 }
728 
set_gretl_startdir(void)729 void set_gretl_startdir (void)
730 {
731     if (usecwd) {
732 	char *test = getenv("GRETL_STARTDIR");
733 	gchar *startdir = NULL;
734 
735 	/* the environment variable check is mostly for the macOS
736 	   package */
737 
738 	if (test != NULL) {
739 	    startdir = g_strdup(test);
740 	} else {
741 	    startdir = g_get_current_dir();
742 	}
743 
744 	if (startdir != NULL) {
745 	    int err = gretl_set_path_by_name("workdir", startdir);
746 
747 	    if (err) {
748 		fprintf(stderr, "%s\n", gretl_errmsg_get());
749 	    } else {
750 		fprintf(stderr, "working dir = '%s'\n", startdir);
751 	    }
752 	    g_free(startdir);
753 	}
754     }
755 }
756 
get_pkg_save_dir(char * dirname,int action)757 static void get_pkg_save_dir (char *dirname, int action)
758 {
759 
760     const char *subdir = NULL;
761     int try_sysdir = 1;
762     int ok = 0;
763 
764     if (action == SAVE_FUNCTIONS) {
765 	subdir = "functions";
766     } else if (action == SAVE_DATA_PKG) {
767 	subdir = "data";
768     } else if (action == SAVE_REMOTE_DB) {
769 	subdir = "db";
770     } else {
771 	return;
772     }
773 
774 #ifdef G_OS_WIN32
775     try_sysdir = 0;
776 #endif
777 
778     if (try_sysdir) {
779 	/* try 'system' location first */
780 	sprintf(dirname, "%s%s", gretl_home(), subdir);
781 	ok = write_OK(dirname);
782     }
783 
784     if (!ok) {
785 	/* go to user's dotdir */
786 	sprintf(dirname, "%s%s", gretl_dotdir(), subdir);
787 	ok = write_OK(dirname);
788     }
789 
790     if (!ok) {
791 	*dirname = '\0';
792     }
793 }
794 
get_default_dir_for_action(char * s,int action)795 void get_default_dir_for_action (char *s, int action)
796 {
797     *s = '\0';
798 
799     if (action == SAVE_FUNCTIONS ||
800 	action == SAVE_DATA_PKG ||
801 	action == SAVE_REMOTE_DB) {
802 	get_pkg_save_dir(s, action);
803     } else {
804 	strcpy(s, gretl_workdir());
805     }
806 
807     slash_terminate(s);
808 }
809 
810 #ifdef G_OS_WIN32
get_reg_base(const char * key)811 static const char *get_reg_base (const char *key)
812 {
813     if (!strncmp(key, "x12a", 4)) {
814         return "x12arima";
815     } else if (!strncmp(key, "tramo", 5)) {
816         return "tramo";
817     } else {
818 	return "gretl";
819     }
820 }
821 #endif
822 
823 #ifdef OS_OSX
824 
alt_ok(const char * prog)825 static int alt_ok (const char *prog)
826 {
827     char *p, test[MAXSTR];
828     int tr = strstr(prog, "tramo") != NULL;
829     int ok;
830 
831     strcpy(test, gretl_home());
832     p = strstr(test, "share/gretl");
833     if (p != NULL) {
834     	*p = 0;
835     }
836 
837     if (tr) {
838          strcat(test, "tramo/tramo");
839     } else {
840          strcat(test, "x12arima/x12a");
841     }
842 
843     ok = check_for_program(test);
844 
845     if (ok) {
846         if (tr) {
847             strcpy(paths.tramo, test);
848 	} else {
849 	    strcpy(paths.x12a, test);
850 	}
851     }
852 
853     return ok;
854 }
855 
856 #endif
857 
858 #ifdef HAVE_TRAMO
859 
860 #define tramo_ts(d) ((d)->structure == TIME_SERIES && \
861                      (d->pd == 1 || d->pd == 4 || d->pd == 12))
862 
863 static int tramo_ok = 0;
864 
get_tramo_ok(void)865 int get_tramo_ok (void)
866 {
867     return tramo_ok && tramo_ts(dataset);
868 }
869 
set_tramo_status(void)870 static void set_tramo_status (void)
871 {
872     const char *tramodir = gretl_tramo_dir();
873     int gui_up = (mdata != NULL);
874     int ok = 0;
875 
876     if (*tramodir != '\0') {
877 	const char *tramo = gretl_tramo();
878 
879 	ok = check_for_program(tramo);
880 # ifdef OS_OSX
881 	if (!ok) {
882 	    ok = alt_ok(tramo);
883 	}
884 # endif
885     }
886 
887     if (tramo_ok && !ok && gui_up) {
888 	warnbox_printf("Invalid path for %s", "TRAMO");
889     }
890 
891     tramo_ok = ok;
892 
893     if (gui_up) {
894 	flip(mdata->ui, "/menubar/Variable/Tramo", get_tramo_ok());
895     }
896 }
897 
898 #endif /* HAVE_TRAMO */
899 
900 #ifdef HAVE_X12A
901 
902 #define x12_ts(d) ((d)->structure == TIME_SERIES && \
903                    (d->pd == 4 || d->pd == 12))
904 
905 static int x12a_ok = 0;
906 
get_x12a_ok(void)907 int get_x12a_ok (void)
908 {
909     return x12a_ok && x12_ts(dataset);
910 }
911 
set_x12a_status(void)912 static void set_x12a_status (void)
913 {
914     const char *x12adir = gretl_x12_arima_dir();
915     int gui_up = (mdata != NULL);
916     int ok = 0;
917 
918     if (*x12adir != '\0') {
919 	const char *x12a = gretl_x12_arima();
920 
921 	ok = check_for_program(x12a);
922 # ifdef OS_OSX
923 	if (!ok) {
924 	    ok = alt_ok(x12a);
925 	}
926 # endif
927     }
928 
929     if (x12a_ok && !ok && gui_up) {
930 	warnbox_printf("Invalid path for %s", "X-12-ARIMA");
931     }
932 
933     x12a_ok = ok;
934 
935     if (gui_up) {
936 	flip(mdata->ui, "/menubar/Variable/X12A",
937 	     get_x12a_ok());
938     }
939 }
940 
941 #endif /* HAVE_X12A */
942 
943 #ifndef G_OS_WIN32
944 
root_check(void)945 static void root_check (void)
946 {
947     if (getuid() == 0) {
948 	int resp;
949 
950 	resp = yes_no_dialog("gretl", _("You seem to be running gretl "
951 					"as root.  Do you really want to do this?"),
952 			     NULL);
953 	if (resp == GRETL_NO) {
954 	    exit(EXIT_FAILURE);
955 	}
956     }
957 }
958 
gretl_config_init(void)959 int gretl_config_init (void)
960 {
961     int err = 0;
962 
963     get_gretl_rc_path(rcfile);
964     err = read_gretlrc();
965     set_gretl_startdir();
966     root_check();
967 
968     return err;
969 }
970 
971 #endif /* !G_OS_WIN32 */
972 
highlight_preferences_entry(const char * vname)973 static void highlight_preferences_entry (const char *vname)
974 {
975     GtkWidget *w;
976     int i;
977 
978     for (i=0; rc_vars[i].key != NULL; i++) {
979 	if (!strcmp(vname, rc_vars[i].key)) {
980 	    w = rc_vars[i].widget;
981 	    if (w != NULL && GTK_IS_ENTRY(w)) {
982 		gtk_editable_select_region(GTK_EDITABLE(w), 0, -1);
983 		gtk_widget_grab_focus(w);
984 	    }
985 	    break;
986 	}
987     }
988 }
989 
preferences_dialog_canceled(GtkWidget * w,int * c)990 static void preferences_dialog_canceled (GtkWidget *w, int *c)
991 {
992     *c = 1;
993 }
994 
page_has_help(int p)995 static int page_has_help (int p)
996 {
997     return p == TAB_EDITOR || p == TAB_VCV;
998 }
999 
sensitize_prefs_help(GtkNotebook * book,gpointer arg1,guint newpg,GtkWidget * button)1000 static void sensitize_prefs_help (GtkNotebook *book,
1001 				  gpointer arg1,
1002 				  guint newpg,
1003 				  GtkWidget *button)
1004 {
1005     gtk_widget_set_sensitive(button, page_has_help(newpg + 1));
1006 }
1007 
show_prefs_help(GtkWidget * w,GtkWidget * notebook)1008 static void show_prefs_help (GtkWidget *w, GtkWidget *notebook)
1009 {
1010     gint page;
1011 
1012     page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
1013 
1014     if (page + 1 == TAB_EDITOR) {
1015 	show_gui_help(EDITOR);
1016     } else if (page + 1 == TAB_VCV) {
1017 	show_gui_help(HCCME);
1018     }
1019 }
1020 
1021 /* To record state of preferences dialogs, and avoid opening
1022    both the 'global' one and the one specific to the console
1023    simultaneously, which would lead to bad effects.
1024 */
1025 static GtkWidget *all_prefs;
1026 static GtkWidget *console_prefs;
1027 
preferences_dialog_destroyed(GtkWidget * w,GtkWidget ** pw)1028 static void preferences_dialog_destroyed (GtkWidget *w,
1029 					  GtkWidget **pw)
1030 {
1031     int i;
1032 
1033     for (i=0; rc_vars[i].key != NULL; i++) {
1034 	rc_vars[i].widget = NULL;
1035     }
1036     if (pw != NULL) {
1037 	*pw = NULL;
1038     }
1039 }
1040 
preferences_dialog(int page,const char * varname,GtkWidget * parent)1041 int preferences_dialog (int page, const char *varname, GtkWidget *parent)
1042 {
1043     GtkWidget *dialog = all_prefs;
1044     GtkWidget *notebook;
1045     GtkWidget *button;
1046     GtkWidget *hbox;
1047     GtkWidget *vbox;
1048     int canceled = 0;
1049 
1050     if (dialog != NULL) {
1051 	gtk_window_present(GTK_WINDOW(dialog));
1052 	return 0;
1053     } else if (console_prefs != NULL) {
1054 	gtk_widget_destroy(console_prefs);
1055     }
1056 
1057     dialog = gretl_dialog_new(_("gretl: preferences"), parent,
1058 			      GRETL_DLG_RESIZE | GRETL_DLG_BLOCK);
1059     all_prefs = dialog;
1060 #if GTK_MAJOR_VERSION < 3
1061     gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
1062 #endif
1063     vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1064     gtk_box_set_spacing(GTK_BOX(vbox), 2);
1065 
1066     g_signal_connect(G_OBJECT(dialog), "destroy",
1067 		     G_CALLBACK(preferences_dialog_destroyed),
1068 		     &all_prefs);
1069 
1070     notebook = gtk_notebook_new();
1071     gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
1072 
1073     make_prefs_tab(notebook, TAB_MAIN, 0);
1074     make_prefs_tab(notebook, TAB_PROGS, 0);
1075     make_prefs_tab(notebook, TAB_EDITOR, 0);
1076     make_prefs_tab(notebook, TAB_NET, 0);
1077     make_prefs_tab(notebook, TAB_VCV, 0);
1078 #ifdef HAVE_MPI
1079     make_prefs_tab(notebook, TAB_MPI, 0);
1080 #endif
1081 
1082     hbox = gtk_dialog_get_action_area(GTK_DIALOG(dialog));
1083 
1084     /* Apply button */
1085     button = apply_button(hbox);
1086     g_signal_connect(G_OBJECT(button), "clicked",
1087 		     G_CALLBACK(apply_prefs_changes), parent);
1088     gtk_widget_grab_default(button);
1089 
1090     /* Cancel button */
1091     button = cancel_button(hbox);
1092     g_signal_connect(G_OBJECT(button), "clicked",
1093 		     G_CALLBACK(preferences_dialog_canceled),
1094 		     &canceled);
1095     g_signal_connect(G_OBJECT(button), "clicked",
1096 		     G_CALLBACK(delete_widget),
1097 		     dialog);
1098 
1099     /* OK button */
1100     button = ok_button(hbox);
1101     g_signal_connect(G_OBJECT(button), "clicked",
1102 		     G_CALLBACK(apply_prefs_changes), parent);
1103     g_signal_connect(G_OBJECT(button), "clicked",
1104 		     G_CALLBACK(delete_widget),
1105 		     dialog);
1106 
1107     /* Help button */
1108     button = context_help_button(hbox, -1);
1109     g_signal_connect(G_OBJECT(button), "clicked",
1110 		     G_CALLBACK(show_prefs_help),
1111 		     notebook);
1112     gtk_widget_set_sensitive(button, page_has_help(page));
1113     g_signal_connect(G_OBJECT(notebook), "switch-page",
1114 		     G_CALLBACK(sensitize_prefs_help),
1115 		     button);
1116 
1117     if (page > 1 && page < TAB_MAX) {
1118 	page--;
1119 	/* "show" the target page first (see GtkNoteBook API doc) */
1120 	gtk_widget_show(gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page));
1121 	gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page);
1122     }
1123 
1124     if (varname != NULL) {
1125 	highlight_preferences_entry(varname);
1126     }
1127 
1128     gtk_widget_show_all(dialog);
1129 
1130     return canceled;
1131 }
1132 
refocus_console(GtkWidget * widget,GtkWidget * caller)1133 static void refocus_console (GtkWidget *widget, GtkWidget *caller)
1134 {
1135     gtk_widget_grab_focus(caller);
1136 }
1137 
console_prefs_dialog(GtkWidget * caller)1138 int console_prefs_dialog (GtkWidget *caller)
1139 {
1140     GtkWidget *dialog = console_prefs;
1141     GtkWidget *parent;
1142     GtkWidget *button;
1143     GtkWidget *hbox;
1144     GtkWidget *vbox;
1145     int canceled = 0;
1146 
1147     if (dialog != NULL) {
1148 	gtk_window_present(GTK_WINDOW(dialog));
1149     } else if (all_prefs != NULL) {
1150 	gtk_widget_destroy(all_prefs);
1151     }
1152 
1153     parent = swallow ? mdata->main : caller;
1154     dialog = gretl_dialog_new(_("gretl: preferences"), parent,
1155 			      GRETL_DLG_RESIZE | GRETL_DLG_BLOCK);
1156     console_prefs = dialog;
1157 #if GTK_MAJOR_VERSION < 3
1158     gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
1159 #endif
1160     vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1161     gtk_box_set_spacing(GTK_BOX(vbox), 2);
1162 
1163     if (swallow) {
1164 	g_signal_connect(G_OBJECT(dialog), "destroy",
1165 			 G_CALLBACK(refocus_console),
1166 			 caller);
1167     }
1168     g_signal_connect(G_OBJECT(dialog), "destroy",
1169 		     G_CALLBACK(preferences_dialog_destroyed),
1170 		     &console_prefs);
1171 
1172     make_prefs_tab(vbox, TAB_EDITOR, 1);
1173 
1174     hbox = gtk_dialog_get_action_area(GTK_DIALOG(dialog));
1175 
1176     /* Cancel button */
1177     button = cancel_button(hbox);
1178     g_signal_connect(G_OBJECT(button), "clicked",
1179 		     G_CALLBACK(preferences_dialog_canceled),
1180 		     &canceled);
1181     g_signal_connect(G_OBJECT(button), "clicked",
1182 		     G_CALLBACK(delete_widget),
1183 		     dialog);
1184 
1185     /* OK button */
1186     button = ok_button(hbox);
1187     g_signal_connect(G_OBJECT(button), "clicked",
1188 		     G_CALLBACK(apply_prefs_changes), caller);
1189     g_signal_connect(G_OBJECT(button), "clicked",
1190 		     G_CALLBACK(delete_widget),
1191 		     dialog);
1192 
1193     gtk_widget_show_all(dialog);
1194 
1195     return canceled;
1196 }
1197 
flip_sensitive(GtkWidget * w,gpointer data)1198 static void flip_sensitive (GtkWidget *w, gpointer data)
1199 {
1200     GtkWidget *entry = GTK_WIDGET(data);
1201 
1202     gtk_widget_set_sensitive(entry, button_is_active(w));
1203 }
1204 
set_path_callback(char * setvar,char * setting)1205 void set_path_callback (char *setvar, char *setting)
1206 {
1207     int i = 0;
1208 
1209     while (rc_vars[i].key != NULL) {
1210 	if (rc_vars[i].var == (void *) setvar) {
1211 	    /* FIXME: utf-8 issues here? */
1212 	    if (rc_vars[i].widget != NULL) {
1213 		gtk_entry_set_text(GTK_ENTRY(rc_vars[i].widget),
1214 				   setting);
1215 	    }
1216 	    break;
1217 	}
1218 	i++;
1219     }
1220 }
1221 
browse_button_callback(GtkWidget * w,RCVAR * rc)1222 static void browse_button_callback (GtkWidget *w, RCVAR *rc)
1223 {
1224     GtkWidget *parent = g_object_get_data(G_OBJECT(w), "parent");
1225     int code = SET_PROG;
1226 
1227 #ifdef HAVE_MPI
1228     if (!strcmp(rc->key, "mpi_hosts")) {
1229 	file_selector_with_parent(SET_OTHER, FSEL_DATA_MISC, rc->var, parent);
1230 	return;
1231     }
1232 #endif
1233 
1234     if (strstr(rc->description, "directory") != NULL) {
1235 	code = SET_DIR;
1236     }
1237 
1238     file_selector_with_parent(code, FSEL_DATA_MISC, rc->var, parent);
1239 }
1240 
make_path_browse_button(RCVAR * rc,GtkWidget * w)1241 static GtkWidget *make_path_browse_button (RCVAR *rc, GtkWidget *w)
1242 {
1243     GtkWidget *top = gtk_widget_get_toplevel(w);
1244     GtkWidget *b;
1245 
1246     b = gtk_button_new_with_label(_("Browse..."));
1247     g_object_set_data(G_OBJECT(b), "parent", top);
1248     g_signal_connect(G_OBJECT(b), "clicked",
1249 		     G_CALLBACK(browse_button_callback),
1250 		     rc);
1251     return b;
1252 }
1253 
try_switch_locale(GtkComboBox * box,gpointer p)1254 static gboolean try_switch_locale (GtkComboBox *box, gpointer p)
1255 {
1256     static int lasterr;
1257     gchar *langstr;
1258     int err;
1259 
1260     if (lasterr) {
1261 	lasterr = 0;
1262 	return FALSE;
1263     }
1264 
1265     langstr = combo_box_get_active_text(box);
1266     err = test_locale(langstr);
1267     g_free(langstr);
1268 
1269     if (err) {
1270 	lasterr = err;
1271 	gui_errmsg(err);
1272 	gretl_error_clear();
1273 	gtk_combo_box_set_active(box, 0);
1274     }
1275 
1276     return FALSE;
1277 }
1278 
try_switch_style(GtkComboBox * box,GtkWidget * text)1279 static gboolean try_switch_style (GtkComboBox *box, GtkWidget *text)
1280 {
1281     gchar *style = combo_box_get_active_text(box);
1282 
1283     set_style_for_textview(text, style);
1284     g_free(style);
1285 
1286     return FALSE;
1287 }
1288 
embed_style_sampler(GtkWidget * vbox)1289 static GtkWidget *embed_style_sampler (GtkWidget *vbox)
1290 {
1291     GtkWidget *hbox, *text;
1292 
1293     hbox = gtk_hbox_new(TRUE, 5);
1294     text = create_sample_source(sview_style);
1295     gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, FALSE, 0);
1296     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 15);
1297 
1298     return text;
1299 }
1300 
1301 static const char *hc_strs[] = {
1302     "HC0", "HC1", "HC2", "HC3", "HC3a", "HAC"
1303 };
1304 
get_list_setting_strings(void * var,int * n)1305 static const char **get_list_setting_strings (void *var, int *n)
1306 {
1307     static const char *hc_panel_strs[] = {
1308 	"Arellano", "PCSE"
1309     };
1310     static const char *garch_strs[] = {
1311 	"QML", "BW"
1312     };
1313     static const char *manpref_strs[] = {
1314         N_("English (US letter paper)"),
1315         N_("English (A4 paper)"),
1316         N_("Translation, if available")
1317     };
1318 #ifdef HAVE_GTKSV_COMPLETION
1319     static const char *completion_strs[] = {
1320 	N_("none"),
1321 	N_("automatic, as you type"),
1322 	N_("on demand, via Tab")
1323     };
1324 #endif
1325     static const char *icon_sizing_strs[] = {
1326 	N_("Automatic"),
1327 	N_("small"),
1328 	N_("medium")
1329     };
1330     const char **strs = NULL;
1331 
1332     *n = 0;
1333 
1334     if (var == hc_xsect || var == hc_tseri) {
1335 	strs = hc_strs;
1336 	*n = sizeof hc_strs / sizeof hc_strs[0];
1337 	if (var == hc_xsect) *n -= 1;
1338     } else if (var == hc_panel) {
1339 	strs = hc_panel_strs;
1340 	*n = sizeof hc_panel_strs / sizeof hc_panel_strs[0];
1341     } else if (var == hc_garch) {
1342 	strs = garch_strs;
1343 	*n = sizeof garch_strs / sizeof garch_strs[0];
1344     } else if (var == &manpref) {
1345 	strs = manpref_strs;
1346 	*n = sizeof manpref_strs / sizeof manpref_strs[0];
1347 #ifdef HAVE_GTKSV_COMPLETION
1348     } else if (var == &hansl_completion || var == &console_completion) {
1349 	strs = completion_strs;
1350 	*n = sizeof completion_strs / sizeof completion_strs[0];
1351 #endif
1352     } else if (var == &icon_sizing) {
1353 	strs = icon_sizing_strs;
1354 	*n = sizeof icon_sizing_strs / sizeof icon_sizing_strs[0];
1355     } else if (var == sview_style) {
1356 	strs = get_sourceview_style_ids(n);
1357     } else if (var == graph_theme) {
1358 	strs = get_graph_theme_ids(n);
1359     }
1360 
1361 #ifdef HAVE_MPI
1362     else if (var == mpi_pref) {
1363 # ifdef G_OS_WIN32
1364 	static const char *mpi_strs[] = {
1365 	    "MS-MPI" /* FIXME? */
1366 	};
1367 # else
1368 	static const char *mpi_strs[] = {
1369 	    "OpenMPI", "MPICH"
1370 	};
1371 #endif
1372 
1373 	strs = mpi_strs;
1374 	*n = sizeof mpi_strs / sizeof mpi_strs[0];
1375     }
1376 #endif
1377 
1378 #if defined(MAC_THEMING)
1379     else if (var == themepref) {
1380 	static const char *theme_strs[] = {
1381 	    "Adwaita", "Clearlooks", "Lion-like", "Raleigh"
1382 	};
1383 
1384 	strs = theme_strs;
1385 	*n = sizeof theme_strs / sizeof theme_strs[0];
1386     }
1387 #elif defined(G_OS_WIN32) && GTK_MAJOR_VERSION < 3
1388     else if (var == themepref) {
1389 	static const char *theme_strs[] = {
1390             "Windows-10", "MS-Windows", "Clearlooks", "Raleigh"
1391 	};
1392 
1393 	strs = theme_strs;
1394 	*n = sizeof theme_strs / sizeof theme_strs[0];
1395     }
1396 #elif defined(G_OS_WIN32) && GTK_MAJOR_VERSION == 3
1397     else if (var == themepref) {
1398 	static const char *theme_strs[] = {
1399             "Windows 10", "Windows 7", "Adwaita"
1400 	};
1401 
1402 	strs = theme_strs;
1403 	*n = sizeof theme_strs / sizeof theme_strs[0];
1404     }
1405 #endif
1406 
1407     return strs;
1408 }
1409 
get_radio_setting_strings(void * var,int * n)1410 static const char **get_radio_setting_strings (void *var, int *n)
1411 {
1412     /* unused at present, but may be activated again at
1413        some point? */
1414     *n = 0;
1415     return NULL;
1416 }
1417 
get_default_hc_string(int ci)1418 const char *get_default_hc_string (int ci)
1419 {
1420     if (ci == GARCH) {
1421 	int k = libset_get_int(GARCH_ALT_VCV);
1422 
1423 	return (k == ML_BW)? "BW" : "QML";
1424     } else if (!robust_conf(ci)) {
1425 	return "QML";
1426     } else {
1427 	int xsect = dataset_is_cross_section(dataset);
1428 	int tseries = dataset_is_time_series(dataset);
1429 
1430 	if (tseries && libset_get_bool(FORCE_HC)) {
1431 	    xsect = 1;
1432 	} else if (ci == VAR) {
1433 	    xsect = 1;
1434 	}
1435 
1436 	if (xsect) {
1437 	    return hc_strs[libset_get_int(HC_VERSION)];
1438 	} else if (tseries) {
1439 	    /* (and not forced to an HC variant) */
1440 	    return "HAC";
1441 	} else {
1442 	    /* panel */
1443 	    return libset_get_bool(USE_PCSE) ? "PCSE" : "Arellano";
1444 	}
1445     }
1446 }
1447 
non_console_var(void * ptr)1448 static int non_console_var (void *ptr)
1449 {
1450 #ifdef HAVE_GTKSV_COMPLETION
1451     return (ptr == &smarttab || ptr == &script_line_numbers ||
1452 	    ptr == &tabbed_editor || ptr == &tabwidth ||
1453 	    ptr == &hansl_completion);
1454 #else
1455     return (ptr == &smarttab || ptr == &script_line_numbers ||
1456 	    ptr == &tabbed_editor || ptr == &tabwidth);
1457 #endif
1458 }
1459 
console_only(void * ptr)1460 static int console_only (void *ptr)
1461 {
1462 #ifdef HAVE_GTKSV_COMPLETION
1463     return (ptr == &console_completion);
1464 #else
1465     return 0;
1466 #endif
1467 }
1468 
1469 static void
get_table_sizes(int page,int * n_str,int * n_bool,int * n_browse,int * n_list,int console)1470 get_table_sizes (int page, int *n_str, int *n_bool, int *n_browse,
1471 		 int *n_list, int console)
1472 {
1473     int i;
1474 
1475     for (i=0; rc_vars[i].key != NULL; i++) {
1476 	if (rc_vars[i].tab == page) {
1477 	    if (console && non_console_var(rc_vars[i].var)) {
1478 		continue;
1479 	    } else if (!console && console_only(rc_vars[i].var)) {
1480 		continue;
1481 	    }
1482 	    if (rc_vars[i].flags & BROWSER) {
1483 		*n_browse += 1;
1484 	    } else if (rc_vars[i].flags & LISTSET) {
1485 		*n_list += 1;
1486 	    } else if (rc_vars[i].flags & SPINSET) {
1487 		*n_list += 1;
1488 	    }
1489 	    if (rc_vars[i].flags & BOOLSET) {
1490 		*n_bool += 1;
1491 	    } else if (rc_vars[i].flags & RADIOSET) {
1492 		*n_bool += 1;
1493 	    } else if (!(rc_vars[i].flags & INVISET)) {
1494 		*n_str += 1;
1495 	    }
1496 	}
1497     }
1498 }
1499 
radio_change_value(GtkWidget * w,int * v)1500 static void radio_change_value (GtkWidget *w, int *v)
1501 {
1502     if (button_is_active(w)) {
1503 	gint i = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "action"));
1504 
1505 	*v = i;
1506     }
1507 }
1508 
table_attach_fixed(GtkTable * table,GtkWidget * child,guint left,guint right,guint top,guint bottom)1509 static void table_attach_fixed (GtkTable *table,
1510 				GtkWidget *child,
1511 				guint left, guint right,
1512 				guint top, guint bottom)
1513 {
1514     gtk_table_attach(table, child, left, right, top, bottom,
1515 		     0, 0, 0, 0);
1516 }
1517 
themes_page(GtkButton * button,gpointer p)1518 static void themes_page (GtkButton *button, gpointer p)
1519 {
1520     if (browser_open("http://ricardo.ecn.wfu.edu/pub/gretl/plots/")) {
1521 	errbox("Failed to open URL");
1522     }
1523 }
1524 
add_themes_examples_button(GtkWidget * hbox)1525 static void add_themes_examples_button (GtkWidget *hbox)
1526 {
1527     GtkWidget *b;
1528 
1529     b = gtk_button_new_with_label(_("Examples"));
1530     gtk_box_pack_start(GTK_BOX(hbox), b, FALSE, FALSE, 5);
1531     g_signal_connect(G_OBJECT(b), "clicked",
1532 		     G_CALLBACK(themes_page), NULL);
1533 }
1534 
scroller_page(GtkWidget * vbox)1535 static GtkWidget *scroller_page (GtkWidget *vbox)
1536 {
1537     GtkWidget *scroller;
1538 
1539     scroller = gtk_scrolled_window_new(NULL, NULL);
1540     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
1541 				   GTK_POLICY_NEVER,
1542 				   GTK_POLICY_AUTOMATIC);
1543     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroller),
1544 					  vbox);
1545     return scroller;
1546 }
1547 
make_prefs_tab(GtkWidget * notebook,int tab,int console)1548 static void make_prefs_tab (GtkWidget *notebook, int tab,
1549 			    int console)
1550 {
1551     GtkWidget *b_table = NULL, *s_table = NULL;
1552     GtkWidget *l_table = NULL;
1553     GtkWidget *vbox, *w = NULL;
1554     GtkWidget *page;
1555     int s_len = 1, b_len = 0, l_len = 1;
1556     int s_cols, b_cols = 0, l_cols = 0;
1557     int b_col = 0;
1558     int n_str = 0;
1559     int n_bool = 0;
1560     int n_browse = 0;
1561     int n_list = 0;
1562     RCVAR *rc;
1563     int i;
1564 
1565     if (console) {
1566 	vbox = notebook; /* not really a notebook! */
1567     } else {
1568 	vbox = gtk_vbox_new(FALSE, 0);
1569 	gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1570 
1571 	if (tab == TAB_MAIN) {
1572 	    w = gtk_label_new(_("General"));
1573 	} else if (tab == TAB_PROGS) {
1574 	    w = gtk_label_new(_("Programs"));
1575 	} else if (tab == TAB_EDITOR) {
1576 	    w = gtk_label_new(_("Editor"));
1577 	} else if (tab == TAB_NET) {
1578 	    w = gtk_label_new(_("Network"));
1579 	} else if (tab == TAB_VCV) {
1580 	    w = gtk_label_new(_("HCCME"));
1581 #ifdef HAVE_MPI
1582 	} else if (tab == TAB_MPI) {
1583 	    w = gtk_label_new(_("MPI"));
1584 #endif
1585 	}
1586 	if (tab == TAB_PROGS) {
1587 	    page = scroller_page(vbox);
1588 	} else {
1589 	    page = vbox;
1590 	}
1591 
1592 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, w);
1593     }
1594 
1595     get_table_sizes(tab, &n_str, &n_bool, &n_browse, &n_list, console);
1596 
1597     s_cols = (n_browse > 0)? 3 : 2;
1598 
1599     if (tab == TAB_VCV && n_list > 0) {
1600 	/* VCV tab -- put the list entries first, right aligned */
1601 	l_cols = 2;
1602 	l_table = gtk_table_new(l_len, l_cols, FALSE);
1603 	gtk_table_set_row_spacings(GTK_TABLE(l_table), 5);
1604 	gtk_table_set_col_spacings(GTK_TABLE(l_table), 5);
1605 	gtk_box_pack_start(GTK_BOX(vbox), l_table, FALSE, FALSE, 0);
1606     }
1607 
1608     if (n_str > 0) {
1609 	s_table = gtk_table_new(s_len, s_cols, FALSE);
1610 	gtk_table_set_row_spacings(GTK_TABLE(s_table), 5);
1611 	gtk_table_set_col_spacings(GTK_TABLE(s_table), 5);
1612 	gtk_box_pack_start(GTK_BOX(vbox), s_table, FALSE, FALSE, 0);
1613     }
1614 
1615     if (n_bool > 0) {
1616 	b_cols = 2;
1617 	b_table = gtk_table_new(1, b_cols, FALSE);
1618 	gtk_table_set_row_spacings(GTK_TABLE(b_table), 5);
1619 	gtk_table_set_col_spacings(GTK_TABLE(b_table), 5);
1620 	gtk_box_pack_start(GTK_BOX(vbox), b_table, FALSE, FALSE, 10);
1621     }
1622 
1623     if (tab != TAB_VCV && n_list > 0) {
1624 	/* non-VCV tab -- list entries come last, and we
1625 	   use an hbox to pack them left */
1626 	GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
1627 
1628 	l_cols = 2;
1629 	l_table = gtk_table_new(l_len, l_cols, FALSE);
1630 	gtk_table_set_row_spacings(GTK_TABLE(l_table), 10);
1631 	gtk_table_set_col_spacings(GTK_TABLE(l_table), 10);
1632 	gtk_box_pack_start(GTK_BOX(hbox), l_table, FALSE, FALSE, 5);
1633 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1634     }
1635 
1636     for (i=0; rc_vars[i].key != NULL; i++) {
1637 	rc = &rc_vars[i];
1638 
1639 	if (rc->tab != tab) {
1640 	    /* the item is not on this page */
1641 	    continue;
1642 	} else if (console && non_console_var(rc->var)) {
1643 	    rc->widget = NULL;
1644 	    continue;
1645 	} else if (!console && console_only(rc->var)) {
1646 	    rc->widget = NULL;
1647 	    continue;
1648 	}
1649 
1650 	if ((rc->flags & BOOLSET) && rc->link == NULL) {
1651 	    /* simple boolean variable (check box) */
1652 	    int rcval = *(int *) (rc->var);
1653 
1654 	    rc->widget = gtk_check_button_new_with_label(_(rc->description));
1655 	    gtk_table_attach_defaults(GTK_TABLE (b_table), rc->widget,
1656 				      b_col, b_col + 1, b_len, b_len + 1);
1657 
1658 	    if (rcval) {
1659 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rc->widget), TRUE);
1660 	    } else {
1661 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rc->widget), FALSE);
1662 	    }
1663 
1664 	    /* special case: link between toggle and preceding entry */
1665 	    if (rc->len && !(rc->flags & FIXSET)) {
1666 		gtk_widget_set_sensitive(rc_vars[i-1].widget,
1667 					 button_is_active(rc->widget));
1668 		g_signal_connect(G_OBJECT(rc->widget), "clicked",
1669 				 G_CALLBACK(flip_sensitive),
1670 				 rc_vars[i-1].widget);
1671 	    }
1672 
1673 	    b_col++;
1674 
1675 	    if (tab == TAB_VCV || b_col == 2) {
1676 		/* boolean strings under TAB_VCV are too long to
1677 		   appear column-wise
1678 		*/
1679 		b_col = 0;
1680 		b_len++;
1681 		gtk_table_resize(GTK_TABLE(b_table), b_len + 1, 2);
1682 	    }
1683 
1684 	    if (rc->flags & FIXSET) {
1685 		gtk_widget_set_sensitive(rc->widget, FALSE);
1686 		if (rc->len) {
1687 		    gtk_widget_set_sensitive(rc_vars[i-1].widget, FALSE);
1688 		}
1689 	    }
1690 	} else if (rc->flags & BOOLSET) {
1691 	    /* radio-button dichotomy */
1692 	    int rcval = *(int *) (rc->var);
1693 	    GtkWidget *button;
1694 	    GSList *group = NULL;
1695 
1696 	    /* do we have some padding to do? */
1697 	    if (b_col == 1) {
1698 		w = gtk_label_new("   ");
1699 		gtk_table_attach_defaults(GTK_TABLE(b_table), w,
1700 					  b_col, b_col + 1,
1701 					  b_len, b_len + 1);
1702 		b_col = 0;
1703 		b_len++;
1704 		gtk_table_resize(GTK_TABLE(b_table), b_len + 1, 2);
1705 	    }
1706 
1707 	    b_len += 3;
1708 	    gtk_table_resize(GTK_TABLE(b_table), b_len + 1, 2);
1709 
1710 	    /* separator for the group? */
1711 	    w = gtk_hseparator_new();
1712 	    gtk_table_attach_defaults(GTK_TABLE(b_table), w,
1713 				      b_col, b_col + 1,
1714 				      b_len - 3, b_len - 2);
1715 
1716 	    /* then a first button */
1717 	    button = gtk_radio_button_new_with_label(group, _(rc->link));
1718 	    gtk_table_attach_defaults(GTK_TABLE(b_table), button,
1719 				      b_col, b_col + 1,
1720 				      b_len - 2, b_len - 1);
1721 	    if (!rcval) {
1722 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
1723 	    }
1724 
1725 	    group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
1726 
1727 	    /* and a second button */
1728 	    rc->widget = gtk_radio_button_new_with_label(group,
1729 							 _(rc->description));
1730 	    gtk_table_attach_defaults(GTK_TABLE(b_table), rc->widget,
1731 				      b_col, b_col + 1,
1732 				      b_len - 1, b_len);
1733 	    if (rcval) {
1734 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rc->widget), TRUE);
1735 	    }
1736 
1737 	    if (rc->flags & FIXSET) {
1738 		gtk_widget_set_sensitive(button, FALSE);
1739 		gtk_widget_set_sensitive(rc->widget, FALSE);
1740 	    }
1741 	} else if (rc->flags & RADIOSET) {
1742 	    int nopt, j, rcval = *(int *) (rc->var);
1743 	    int rcol;
1744 	    GtkWidget *b;
1745 	    GSList *group = NULL;
1746 	    const char **strs;
1747 
1748 	    if (b_len > 0) {
1749 		/* there are buttons above: add a separator and
1750 		   make this section full-width */
1751 		rcol = b_cols;
1752 		b_len++;
1753 		w = gtk_hseparator_new();
1754 		gtk_table_attach_defaults(GTK_TABLE(b_table), w,
1755 					  0, rcol, b_len - 1, b_len);
1756 	    } else {
1757 		rcol = b_col + 1;
1758 	    }
1759 
1760 	    b_len++;
1761 	    b = gtk_label_new(_(rc->description));
1762 	    gtk_table_attach_defaults(GTK_TABLE(b_table), b,
1763 				      b_col, rcol,
1764 				      b_len - 1, b_len);
1765 
1766 	    strs = get_radio_setting_strings(rc->var, &nopt);
1767 
1768 	    for (j=0; j<nopt; j++) {
1769 		b_len++;
1770 		gtk_table_resize(GTK_TABLE(b_table), b_len, 2);
1771 		b = gtk_radio_button_new_with_label(group, _(strs[j]));
1772 		gtk_table_attach_defaults(GTK_TABLE(b_table), b,
1773 					  b_col, rcol,
1774 					  b_len - 1, b_len);
1775 		g_object_set_data(G_OBJECT(b), "action",
1776 				  GINT_TO_POINTER(j));
1777 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b), j == rcval);
1778 		group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(b));
1779 		g_signal_connect(G_OBJECT(b), "clicked",
1780 				 G_CALLBACK(radio_change_value),
1781 				 rc->var);
1782 	    }
1783 	} else if (rc->flags & LISTSET) {
1784 	    int langs = rc->var == langpref;
1785 	    int gtheme = rc->var == graph_theme;
1786 	    int j, active = 0;
1787 
1788 	    l_len++;
1789 
1790 	    gtk_table_resize(GTK_TABLE(l_table), l_len, l_cols);
1791 	    w = gtk_label_new(_(rc->description));
1792 	    if (tab == TAB_MAIN) {
1793 		gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
1794 	    } else {
1795 		gtk_misc_set_alignment(GTK_MISC(w), 1.0, 0.5);
1796 	    }
1797 	    gtk_table_attach_defaults(GTK_TABLE(l_table),
1798 				      w, 0, 1, l_len - 1, l_len);
1799 
1800 	    rc->widget = gtk_combo_box_text_new();
1801 
1802 	    if (tab == TAB_MAIN) {
1803 		GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
1804 
1805 		gtk_box_pack_start(GTK_BOX(hbox), rc->widget, FALSE, FALSE, 5);
1806 		if (gtheme) {
1807 		    add_themes_examples_button(hbox);
1808 		}
1809 		gtk_table_attach(GTK_TABLE(l_table), hbox,
1810 				 1, 2, l_len - 1, l_len,
1811 				 GTK_EXPAND | GTK_FILL, 0, 0, 0);
1812 	    } else {
1813 		gtk_table_attach(GTK_TABLE(l_table), rc->widget,
1814 				 1, 2, l_len - 1, l_len,
1815 				 0, 0, 0, 0);
1816 	    }
1817 
1818 	    if (rc->flags & FLOATSET) {
1819 		/* special: graph scale */
1820 		double scale, *xvar = (double *) rc->var;
1821 		char numstr[4];
1822 
1823 		j = 0;
1824 		while (get_graph_scale(j, &scale)) {
1825 		    sprintf(numstr, "%.1f", scale);
1826 		    combo_box_append_text(rc->widget, numstr);
1827 		    if (scale == *xvar) {
1828 			active = j;
1829 		    }
1830 		    j++;
1831 		}
1832 	    } else if (langs) {
1833 		char *strvar = (char *) rc->var;
1834 		const char *str;
1835 		int jj = 0;
1836 
1837 		for (j=LANG_AUTO; j<LANG_MAX; j++) {
1838 		    str = lang_string_from_id(j);
1839 		    if (str != NULL) {
1840 			combo_box_append_text(rc->widget, str);
1841 			if (!strcmp(str, strvar)) {
1842 			    active = jj;
1843 			}
1844 			jj++;
1845 		    }
1846 		}
1847 	    } else {
1848 		char *strvar = NULL;
1849 		int *intvar = NULL;
1850 		const char **strs;
1851 		int nopt;
1852 
1853 		if (rc->flags & INTSET) {
1854 		    intvar = (int *) rc->var;
1855 		} else {
1856 		    strvar = (char *) rc->var;
1857 		}
1858 
1859 		strs = get_list_setting_strings(rc->var, &nopt);
1860 		for (j=0; j<nopt; j++) {
1861 		    combo_box_append_text(rc->widget, _(strs[j]));
1862 		    if (strvar != NULL && !strcmp(strs[j], strvar)) {
1863 			active = j;
1864 		    } else if (intvar != NULL && j == *intvar) {
1865 			active = j;
1866 		    }
1867 		}
1868 	    }
1869 	    if (tab == TAB_VCV) {
1870 		int ww = get_string_width("XXArellanoXXXXX");
1871 
1872 		gtk_widget_set_size_request(rc->widget, ww, -1);
1873 	    }
1874 	    gtk_combo_box_set_active(GTK_COMBO_BOX(rc->widget), active);
1875 	    if (langs) {
1876 		g_signal_connect(G_OBJECT(rc->widget), "changed",
1877 				 G_CALLBACK(try_switch_locale),
1878 				 NULL);
1879 	    } else if (rc->var == &sview_style) {
1880 		GtkWidget *sampler;
1881 
1882 		sampler = embed_style_sampler(vbox);
1883 		g_signal_connect(G_OBJECT(rc->widget), "changed",
1884 				 G_CALLBACK(try_switch_style),
1885 				 sampler);
1886 	    }
1887 	} else if (rc->flags & SPINSET) {
1888 	    int *intvar = (int *) rc->var;
1889 
1890 	    l_len++;
1891 
1892 	    gtk_table_resize(GTK_TABLE(l_table), l_len, l_cols);
1893 	    w = gtk_label_new(_(rc->description));
1894 	    gtk_misc_set_alignment(GTK_MISC(w), 1, 0.5);
1895 	    gtk_table_attach_defaults(GTK_TABLE(l_table),
1896 				      w, 0, 1, l_len - 1, l_len);
1897 
1898 	    /* for now, this is specific to tab-spaces */
1899 	    rc->widget = gtk_spin_button_new_with_range(2, 8, 1);
1900 	    gtk_spin_button_set_value(GTK_SPIN_BUTTON(rc->widget), *intvar);
1901 	    gtk_table_attach_defaults(GTK_TABLE(l_table),
1902 				      rc->widget, 1, 2, l_len - 1, l_len);
1903 	} else if (!(rc->flags & INVISET)) {
1904 	    /* visible string variable */
1905 	    char *strvar = (char *) rc->var;
1906 
1907 	    s_len++;
1908 
1909 	    gtk_table_resize(GTK_TABLE(s_table), s_len, s_cols);
1910 	    w = gtk_label_new(_(rc->description));
1911 	    gtk_misc_set_alignment(GTK_MISC(w), 1, 0.5);
1912 	    gtk_table_attach_defaults(GTK_TABLE(s_table), w,
1913 				      0, 1, s_len - 1, s_len);
1914 
1915 	    rc->widget = gtk_entry_new();
1916 	    gtk_table_attach_defaults(GTK_TABLE(s_table),
1917 				      rc->widget, 1, 2, s_len - 1, s_len);
1918 	    gtk_entry_set_text(GTK_ENTRY(rc->widget), strvar);
1919 
1920 	    if (rc->flags & BROWSER) {
1921 		/* add path browse button */
1922 		w = make_path_browse_button(rc, notebook);
1923 		table_attach_fixed(GTK_TABLE(s_table), w,
1924 				   2, 3, s_len - 1, s_len);
1925 	    }
1926 
1927 	    if (rc->flags & FIXSET) {
1928 		gtk_widget_set_sensitive(rc->widget, FALSE);
1929 		gtk_widget_set_sensitive(w, FALSE);
1930 	    }
1931 	}
1932     }
1933 }
1934 
set_gp_colors(void)1935 static void set_gp_colors (void)
1936 {
1937     const char *s = gpcolors;
1938     char cstr[2][8];
1939 
1940     *cstr[0] = *cstr[1] = '\0';
1941 
1942     if (sscanf(s, "%7s %7s", cstr[0], cstr[1]) == 2) {
1943 	set_graph_color_from_string(0, cstr[0]);
1944 	set_graph_color_from_string(1, cstr[1]);
1945     }
1946 }
1947 
set_gp_scale(void)1948 static void set_gp_scale (void)
1949 {
1950     gnuplot_png_set_default_scale(graph_scale);
1951 }
1952 
set_gp_theme(void)1953 static void set_gp_theme (void)
1954 {
1955     set_plotstyle(graph_theme);
1956 }
1957 
1958 #if defined(HAVE_TRAMO) || defined(HAVE_X12A)
1959 
maybe_revise_tramo_x12a_status(void)1960 static void maybe_revise_tramo_x12a_status (void)
1961 {
1962 # ifdef HAVE_TRAMO
1963     if (strcmp(paths.tramo, gretl_tramo())) {
1964 	set_tramo_status();
1965     }
1966 # endif
1967 
1968 # ifdef HAVE_X12A
1969     if (strcmp(paths.x12a, gretl_x12_arima())) {
1970 	set_x12a_status();
1971     }
1972 # endif
1973 }
1974 
1975 #endif
1976 
flag_changed(RCVAR * rcvar,int * changed)1977 static void flag_changed (RCVAR *rcvar, int *changed)
1978 {
1979     if (rcvar->flags & RESTART) {
1980 	*changed = 2;
1981     } else if (*changed == 0) {
1982 	*changed = 1;
1983     }
1984 }
1985 
rcvar_set_int(RCVAR * rcvar,int ival,int * changed)1986 static void rcvar_set_int (RCVAR *rcvar, int ival, int *changed)
1987 {
1988     int *intvar = (int *) rcvar->var;
1989 
1990     if (ival != *intvar) {
1991 	flag_changed(rcvar, changed);
1992 	*intvar = ival;
1993     }
1994 }
1995 
blank_ok(RCVAR * rcvar)1996 static int blank_ok (RCVAR *rcvar)
1997 {
1998     if (!strcmp(rcvar->key, "mpi_hosts")) {
1999 	return 1;
2000     } else if (!strcmp(rcvar->key, "dbproxy")) {
2001 	return 1;
2002     } else {
2003 	return 0;
2004     }
2005 }
2006 
rcvar_set_string(RCVAR * rcvar,const char * sval,int * changed)2007 static void rcvar_set_string (RCVAR *rcvar, const char *sval, int *changed)
2008 {
2009     char *strvar = (char *) rcvar->var;
2010 
2011     if (sval == NULL && blank_ok(rcvar)) {
2012 	/* allow "blanking out" of the item */
2013 	if (*strvar != '\0') {
2014 	    flag_changed(rcvar, changed);
2015 	    *strvar = '\0';
2016 	}
2017 	return;
2018     }
2019 
2020     if (sval != NULL && *sval != '\0' && strcmp(sval, strvar)) {
2021 	flag_changed(rcvar, changed);
2022 	*strvar = '\0';
2023 	strncat(strvar, sval, rcvar->len - 1);
2024     }
2025 }
2026 
rcvar_set_double(RCVAR * rcvar,const char * sval,int * changed)2027 static void rcvar_set_double (RCVAR *rcvar, const char *sval, int *changed)
2028 {
2029     double *xvar = (double *) rcvar->var;
2030 
2031     if (sval != NULL && *sval != '\0') {
2032 	double xval = atof(sval);
2033 
2034 	if (xval != *xvar) {
2035 	    flag_changed(rcvar, changed);
2036 	    *xvar = xval;
2037 	}
2038     }
2039 }
2040 
restart_message(void)2041 static void restart_message (void)
2042 {
2043     infobox(_("This change will take effect when you restart gretl"));
2044 }
2045 
2046 /* Register and react to changes from the main Preferences dialog
2047    or the console-specific preferences.
2048 */
2049 
apply_prefs_changes(GtkWidget * widget,GtkWidget * parent)2050 static void apply_prefs_changes (GtkWidget *widget, GtkWidget *parent)
2051 {
2052     RCVAR *rcvar;
2053     GtkWidget *w;
2054     int changed = 0;
2055     int i;
2056 
2057     for (i=0; rc_vars[i].key != NULL; i++) {
2058 	rcvar = &rc_vars[i];
2059 	w = rcvar->widget;
2060 	if (w == NULL) {
2061 	    continue;
2062 	}
2063 	if (rcvar->flags & BOOLSET) {
2064 	    int bval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
2065 
2066 	    rcvar_set_int(rcvar, bval, &changed);
2067 	} else if (rcvar->flags & SPINSET) {
2068 	    int ival = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w));
2069 
2070 	    rcvar_set_int(rcvar, ival, &changed);
2071 	} else if (rcvar->flags & (USERSET | MACHSET)) {
2072 	    gchar *sval = entry_box_get_trimmed_text(w);
2073 
2074 	    rcvar_set_string(rcvar, sval, &changed);
2075 	    g_free(sval);
2076 	} else if (rcvar->flags & LISTSET) {
2077 	    GtkComboBox *box = GTK_COMBO_BOX(w);
2078 
2079 	    if (rcvar->flags & INTSET) {
2080 		int ival = gtk_combo_box_get_active(box);
2081 
2082 		rcvar_set_int(rcvar, ival, &changed);
2083 	    } else {
2084 		gchar *sval = combo_box_get_active_text(box);
2085 
2086 		if (rcvar->flags & FLOATSET) {
2087 		    rcvar_set_double(rcvar, sval, &changed);
2088 		} else {
2089 		    rcvar_set_string(rcvar, sval, &changed);
2090 		}
2091 		g_free(sval);
2092 	    }
2093 	}
2094     }
2095 
2096     if (changed > 1) {
2097 	restart_message();
2098     }
2099 
2100 #if defined(HAVE_TRAMO) || defined(HAVE_X12A)
2101     maybe_revise_tramo_x12a_status();
2102 #endif
2103 
2104 #ifdef HAVE_MPI
2105     set_mpi_variant(mpi_pref);
2106 #endif
2107 
2108     if (use_proxy && *http_proxy == '\0') {
2109 	/* fix inconsistency */
2110 	use_proxy = 0;
2111     }
2112 
2113     /* update graphing info */
2114     gnuplot_png_set_default_scale(graph_scale);
2115     set_plotstyle(graph_theme);
2116 
2117     write_rc(OPT_NONE); /* note: calls gretl_update_paths */
2118 
2119     /* register these settings for the current session using
2120        the "libset" apparatus
2121     */
2122     libset_set_bool(SHELL_OK, shellok);
2123     libset_set_bool(ROBUST_Z, robust_z);
2124     set_xsect_hccme(hc_xsect);
2125     set_tseries_hccme(hc_tseri);
2126     set_panel_hccme(hc_panel);
2127     set_garch_alt_vcv(hc_garch);
2128 
2129     selector_register_hc_choice();
2130 
2131     if (parent != NULL) {
2132 	windata_t *vwin = window_get_active_vwin(parent);
2133 
2134 	if (vwin != NULL && vwin->sbuf != NULL) {
2135 	    /* called from sourceview window or tab, or console */
2136 	    update_script_editor_options(vwin);
2137 	}
2138     }
2139 
2140     gretl_www_init(http_proxy, use_proxy);
2141 }
2142 
boolvar_to_str(void * b,char * s)2143 static void boolvar_to_str (void *b, char *s)
2144 {
2145     if (*(int *) b) {
2146 	strcpy(s, "true");
2147     } else {
2148 	strcpy(s, "false");
2149     }
2150 }
2151 
2152 /* non-static because also called from dialogs.c on exit */
2153 
write_rc(gretlopt opt)2154 int write_rc (gretlopt opt)
2155 {
2156     RCVAR *rcvar;
2157     FILE *fp;
2158     char val[6];
2159     char *strvar;
2160     int i;
2161 
2162     fp = gretl_fopen(rcfile, "w");
2163     if (fp == NULL) {
2164 	file_write_errbox(rcfile);
2165 	return E_FOPEN;
2166     }
2167 
2168     fprintf(fp, "# gretl config file\n");
2169     fputs("# build date\n", fp);
2170     fprintf(fp, "build_date = %s\n", BUILD_DATE);
2171 
2172     for (i=0; rc_vars[i].var != NULL; i++) {
2173 	rcvar = &rc_vars[i];
2174 #ifdef G_OS_WIN32
2175 	/* let the registry or gretlnet.txt handle this */
2176 	if (!strcmp(rcvar->key, "gretldir")) {
2177 	    continue;
2178 	}
2179 #endif
2180 	if (rcvar->flags & SKIPSET) {
2181 	    /* don't bother writing out an empty entry */
2182 	    strvar = (char *) rcvar->var;
2183 	    if (*strvar == '\0') {
2184 		continue;
2185 	    }
2186 	}
2187 	fprintf(fp, "# %s\n", rcvar->description);
2188 	if (rcvar->flags & BOOLSET) {
2189 	    boolvar_to_str(rcvar->var, val);
2190 	    fprintf(fp, "%s = %s\n", rcvar->key, val);
2191 	} else if (rcvar->flags & INTSET) {
2192 	    fprintf(fp, "%s = %d\n", rcvar->key, *(int *) rcvar->var);
2193 	} else if (rcvar->flags & FLOATSET) {
2194 	    gretl_push_c_numeric_locale();
2195 	    fprintf(fp, "%s = %g\n", rcvar->key, *(double *) rcvar->var);
2196 	    gretl_pop_c_numeric_locale();
2197 	} else {
2198 	    strvar = (char *) rcvar->var;
2199 	    fprintf(fp, "%s = %s\n", rcvar->key, strvar);
2200 	}
2201     }
2202 
2203     rc_save_file_lists(fp);
2204     fclose(fp);
2205 
2206     if (!(opt & OPT_N)) {
2207 	gretl_update_paths(&paths, update_paths_opt);
2208     }
2209 
2210     return 0;
2211 }
2212 
sync_path_from_lib(const char * path_id)2213 void sync_path_from_lib (const char *path_id)
2214 {
2215     if (!strcmp(path_id, "tramo")) {
2216 	strcpy(paths.tramo, gretl_tramo());
2217 	write_rc(OPT_N);
2218 	restart_message();
2219     } else if (!strcmp(path_id, "x12a")) {
2220 	strcpy(paths.x12a, gretl_x12_arima());
2221 	write_rc(OPT_N);
2222 	restart_message();
2223     } else {
2224 	fprintf(stderr, "sync_path_from_lib: '%s' ??\n", path_id);
2225     }
2226 }
2227 
str_to_boolvar(const char * s,void * b)2228 static void str_to_boolvar (const char *s, void *b)
2229 {
2230     int *bvar = (int *) b;
2231 
2232     if (s == NULL) return;
2233 
2234     if (strcmp(s, "true") == 0 || strcmp(s, "1") == 0) {
2235 	*bvar = TRUE;
2236     } else {
2237 	*bvar = FALSE;
2238     }
2239 }
2240 
str_to_int(const char * s,void * b)2241 static void str_to_int (const char *s, void *b)
2242 {
2243     int *ivar = (int *) b;
2244 
2245     if (s == NULL) return;
2246 
2247     if (sscanf(s, "%d", ivar) != 1) {
2248 	if (!strcmp(s, "true")) {
2249 	    /* remedy for ex-boolean */
2250 	    *ivar = 1;
2251 	} else {
2252 	    *ivar = 0;
2253 	}
2254     }
2255 }
2256 
str_to_double(const char * s,void * b)2257 static void str_to_double (const char *s, void *b)
2258 {
2259     double *xvar = (double *) b;
2260 
2261     if (s != NULL && *s != '\0') {
2262 	*xvar = dot_atof(s);
2263     }
2264 }
2265 
2266 #if !defined(G_OS_WIN32) && !defined(OS_OSX)
2267 
maybe_fix_viewpdf(void)2268 static void maybe_fix_viewpdf (void)
2269 {
2270     gchar *prog = NULL;
2271     const gchar *viewers[] = {
2272 	"xpdf",
2273 	"acroread",
2274 	"evince",
2275 	"kpdf",
2276 	"gpdf",
2277 	NULL
2278     };
2279     int i;
2280 
2281     prog = g_find_program_in_path(viewpdf);
2282 
2283     if (prog != NULL) {
2284 	g_free(prog);
2285     } else {
2286 	for (i=0; viewers[i] != NULL; i++) {
2287 	    if (strcmp(viewers[i], viewpdf)) {
2288 		prog = g_find_program_in_path(viewers[i]);
2289 		if (prog != NULL) {
2290 		    strcpy(viewpdf, viewers[i]);
2291 		    g_free(prog);
2292 		    break;
2293 		}
2294 	    }
2295 	}
2296     }
2297 }
2298 
2299 #endif
2300 
2301 /* The various things we need to do after reading gretl's
2302    configuration info -- or perhaps after failing to do so.
2303    We do this only at start-up time. This function is
2304    called by the config-file reading function, either
2305    read_gretlrc() or on MS Windows, read_win32_config().
2306 */
2307 
common_read_rc_setup(int updated)2308 static int common_read_rc_setup (int updated)
2309 {
2310     int langid = 0;
2311     int err = 0;
2312 
2313     libset_set_bool(SHELL_OK, shellok);
2314     libset_set_bool(USE_CWD, usecwd);
2315     libset_set_bool(ROBUST_Z, robust_z);
2316     set_gp_colors();
2317     set_gp_scale();
2318 
2319     set_xsect_hccme(hc_xsect);
2320     set_tseries_hccme(hc_tseri);
2321     set_panel_hccme(hc_panel);
2322     set_garch_alt_vcv(hc_garch);
2323 
2324     err = gretl_set_paths(&paths);
2325     if (err) {
2326 	/* tell the user, then turn off the special alarm */
2327 	gui_errmsg(err);
2328 	set_gretl_alarm(0);
2329     }
2330 
2331     gretl_www_init(http_proxy, use_proxy);
2332     set_tex_use_pdf(latex);
2333     set_gp_theme();
2334 
2335 #if !defined(G_OS_WIN32) && !defined(OS_OSX)
2336     maybe_fix_viewpdf();
2337 #endif
2338 
2339 #ifdef HAVE_TRAMO
2340     set_tramo_status();
2341 #endif
2342 
2343 #ifdef HAVE_X12A
2344     set_x12a_status();
2345 # endif
2346 
2347     langid = lang_id_from_name(langpref);
2348 #ifdef G_OS_WIN32
2349     fprintf(stderr, "rc_setup: langpref='%s', langid=%d, lcnumeric=%d\n",
2350 	    langpref, langid, lcnumeric);
2351 #endif
2352     force_language(langid);
2353     if (langid == LANG_C) {
2354 	force_english_help();
2355     }
2356     set_lcnumeric(langid, lcnumeric);
2357 
2358     if (updated) {
2359 	update_addons_index(NULL);
2360     }
2361 
2362     return err;
2363 }
2364 
2365 /* On reading from text rc file, look up the key in the "key = value"
2366    line we just read, and set the value of the associated variable.
2367 */
2368 
find_and_set_rc_var(const char * key,const char * val)2369 static void find_and_set_rc_var (const char *key, const char *val)
2370 {
2371     RCVAR *rcvar;
2372     char *strvar;
2373     int i;
2374 
2375     for (i=0; rc_vars[i].key != NULL; i++) {
2376 	rcvar = &rc_vars[i];
2377 	if (!strcmp(key, rcvar->key)) {
2378 	    if (!(rcvar->flags & FIXSET)) {
2379 		if (rcvar->flags & BOOLSET) {
2380 		    str_to_boolvar(val, rcvar->var);
2381 		    if (!strcmp(key, "collect_plots")) {
2382 			/* special: set to "auto" */
2383 			libset_set_int(PLOT_COLLECT, 1);
2384 		    }
2385 		} else if (rcvar->flags & INTSET) {
2386 		    str_to_int(val, rcvar->var);
2387 		} else if (rcvar->flags & FLOATSET) {
2388 		    str_to_double(val, rcvar->var);
2389 		} else {
2390 		    strvar = (char *) rcvar->var;
2391 		    *strvar = '\0';
2392 		    strncat(strvar, val, rcvar->len - 1);
2393 		}
2394 		rcvar->flags |= GOTSET;
2395 	    }
2396 	    break;
2397 	}
2398     }
2399 }
2400 
2401 #ifdef G_OS_WIN32
2402 
maybe_get_network_settings(void)2403 static int maybe_get_network_settings (void)
2404 {
2405     const char *netfile;
2406     FILE *fp;
2407     char *strvar;
2408     int gotnet = 0;
2409 
2410     netfile = get_gretlnet_filename();
2411     if (netfile == NULL) {
2412 	return 0;
2413     }
2414 
2415     fp = gretl_fopen(netfile, "r");
2416 
2417     if (fp != NULL) {
2418 	char line[MAXLEN], key[32], linevar[MAXLEN];
2419 	int j, calldrive = tolower(netfile[0]);
2420 
2421 	while (fgets(line, MAXLEN, fp)) {
2422 	    int gotvar = 0;
2423 	    char *p = line;
2424 
2425 	    while (isspace(*p)) p++;
2426 	    if (*p == '#') continue;
2427 
2428 	    if (sscanf(p, "%31s", key) == 1) {
2429 		strcpy(linevar, p + strlen(key) + 3);
2430 		gretl_strstrip(linevar);
2431 		gotvar = 0;
2432 		for (j=0; rc_vars[j].key != NULL; j++) {
2433 		    if (!strcmp(key, rc_vars[j].key)) {
2434 			if (rc_vars[j].flags & BOOLSET) {
2435 			    str_to_boolvar(linevar, rc_vars[j].var);
2436 			} else if (rc_vars[j].flags & INTSET) {
2437 			    str_to_int(linevar, rc_vars[j].var);
2438 			} else {
2439 			    if (!strcmp(key, "gretldir") &&
2440 				tolower(linevar[0]) != calldrive) {
2441 				gotnet = 0;
2442 				goto network_quit;
2443 			    } else {
2444 				strvar = (char *) rc_vars[j].var;
2445 				*strvar = '\0';
2446 				strncat(strvar, linevar, rc_vars[j].len - 1);
2447 			    }
2448 			}
2449 			rc_vars[j].flags |= FIXSET;
2450 			gotvar = gotnet = 1;
2451 		    }
2452 		    if (gotvar) break;
2453 		}
2454 	    }
2455 	}
2456     network_quit:
2457 	fclose(fp);
2458     }
2459 
2460     return gotnet;
2461 }
2462 
2463 /* Try reading user settings from .gretl2rc in appdata directory: if
2464    this succeeds it will pre-empt reading from the registry --
2465    except that we'll respect the registry entry (or perhaps
2466    argv[0] at startup) for gretldir.
2467 */
2468 
win32_read_gretlrc(int * updated)2469 static void win32_read_gretlrc (int *updated)
2470 {
2471     char line[MAXLEN], key[32], linevar[MAXLEN];
2472     int got_recent = 0;
2473     FILE *fp;
2474 
2475     if (*rcfile == '\0') {
2476 	/* shouldn't happen */
2477 	return;
2478     }
2479 
2480     fp = gretl_fopen(rcfile, "r");
2481 
2482 #if 1
2483     fprintf(stderr, "rcfile: '%s' (%s)\n", rcfile,
2484 	    fp == NULL ? "not found" : "found");
2485 #endif
2486 
2487     if (fp == NULL) {
2488 	/* not necessarily an error: may be starting from scratch */
2489 	return;
2490     }
2491 
2492     while (fgets(line, sizeof line, fp) != NULL) {
2493 	if (line[0] == '#') {
2494 	    continue;
2495 	}
2496 	if (!strncmp(line, "recent", 6)) {
2497 	    got_recent = 1;
2498 	    break;
2499 	}
2500 	if (sscanf(line, "%s", key) == 1) {
2501 	    /* note: don't take gretldir from here */
2502 	    if (strcmp(key, "gretldir")) {
2503 		strcpy(linevar, line + strlen(key) + 3);
2504 		gretl_strstrip(linevar);
2505 		if (*linevar != '\0') {
2506 		    if (!strcmp(key, "build_date")) {
2507 			*updated = gretl_is_updated(linevar);
2508 		    } else if (!strcmp(key, "userdir")) {
2509 			/* legacy */
2510 			find_and_set_rc_var("workdir", linevar);
2511 		    } else {
2512 			find_and_set_rc_var(key, linevar);
2513 		    }
2514 		}
2515 	    }
2516 	}
2517     }
2518 
2519     if (got_recent) {
2520 	rc_read_file_lists(fp, line);
2521     }
2522 
2523     fclose(fp);
2524 }
2525 
2526 /* This function is not static since it is called from
2527    gretl_win32_init() in gretlwin32.c
2528 */
2529 
read_win32_config(int debug)2530 int read_win32_config (int debug)
2531 {
2532     RCVAR *rcvar;
2533     char value[MAXSTR];
2534     char *appdata;
2535     char *strvar;
2536     int updated = 0;
2537     int i, err = 0;
2538 
2539     if (chinese_locale()) {
2540 	strcpy(fixedfontname, "NSimSun 10");
2541 	strcpy(default_fixedfont, "NSimSun 10");
2542     } else if (japanese_locale()) {
2543 	strcpy(fixedfontname, "MS Gothic 10");
2544 	strcpy(default_fixedfont, "MS Gothic 10");
2545     }
2546 
2547     rcfile[0] = '\0';
2548 
2549 #ifndef PKGBUILD
2550     /* try "HOME" first */
2551     if (rcfile[0] == '\0') {
2552 	char *home = getenv("HOME");
2553 
2554 	if (home != NULL) {
2555 	    strcpy(rcfile, home);
2556 	    slash_terminate(rcfile);
2557 	    strcat(rcfile, ".gretl2rc");
2558 	}
2559     }
2560 #endif
2561 
2562     if (rcfile[0] == '\0') {
2563 	appdata = appdata_path();
2564 	if (appdata != NULL) {
2565 	    sprintf(rcfile, "%s\\gretl\\.gretl2rc", appdata);
2566 	    free(appdata);
2567 	}
2568     }
2569 
2570     /* see if we have a gretlnet.txt in place, and if so,
2571        read config from it */
2572     maybe_get_network_settings();
2573 
2574     /* read from user config file */
2575     win32_read_gretlrc(&updated);
2576 
2577     /* now read from registry for a few items, if they're
2578        not already set */
2579 
2580     for (i=0; rc_vars[i].key != NULL; i++) {
2581 	int regerr = 0;
2582 
2583 	rcvar = &rc_vars[i];
2584 
2585 	if (rcvar->flags & (FIXSET | GOTSET)) {
2586 	    /* already set via gretlnet.txt or user rcfile */
2587 	    continue;
2588 	}
2589 
2590 	*value = '\0';
2591 
2592 	/* note: by now we have already determined gretldir as
2593 	   best we can; don't overwrite its setting
2594 	*/
2595 	if ((rcvar->flags & MACHSET) && strcmp(rcvar->key, "gretldir")) {
2596 	    regerr = read_reg_val(HKEY_LOCAL_MACHINE,
2597 				  get_reg_base(rcvar->key),
2598 				  rcvar->key,
2599 				  value);
2600 	}
2601 
2602 	if (debug && *value != '\0') {
2603 	    fprintf(stderr, "reg: err = %d, '%s' -> '%s'\n", regerr, rcvar->key,
2604 		    value);
2605 	}
2606 
2607 	if (!regerr && *value != '\0') {
2608 	    /* replace defaults only if we actually got something */
2609 	    if (rcvar->flags & BOOLSET) {
2610 		str_to_boolvar(value, rcvar->var);
2611 	    } else if (rcvar->flags & INTSET) {
2612 		str_to_int(value, rcvar->var);
2613 	    } else {
2614 		strvar = (char *) rcvar->var;
2615 		*strvar = '\0';
2616 		strncat(strvar, value, rcvar->len - 1);
2617 	    }
2618 	}
2619     }
2620 
2621     err = common_read_rc_setup(updated);
2622 
2623     if (debug) {
2624 	fprintf(stderr, "read_win32_config: returning %d\n", err);
2625     }
2626 
2627     return err;
2628 }
2629 
2630 #else /* end of win32 version, now plain GTK */
2631 
2632 /* Note: even if we fail to read the rc file, we should still do
2633    common_read_rc_setup(), since that will establish defaults for
2634    basic paths, etc., and give gretl a chance of running OK.
2635 */
2636 
read_gretlrc(void)2637 static int read_gretlrc (void)
2638 {
2639     FILE *fp = gretl_fopen(rcfile, "r");
2640     int updated = 0;
2641 
2642     if (fp == NULL) {
2643 	fprintf(stderr, "Couldn't read %s\n", rcfile);
2644     } else {
2645 	char line[MAXLEN], key[32], linevar[MAXLEN];
2646 	int got_recent = 0;
2647 
2648 	while (fgets(line, sizeof line, fp)) {
2649 	    if (*line == '#') {
2650 		continue;
2651 	    }
2652 	    if (!strncmp(line, "recent", 6)) {
2653 		got_recent = 1;
2654 		break;
2655 	    }
2656 	    if (sscanf(line, "%31s", key) == 1) {
2657 		*linevar = '\0';
2658 		strncat(linevar, line + strlen(key) + 3, MAXLEN-1);
2659 		gretl_strstrip(linevar);
2660 		if (*linevar != '\0') {
2661 		    if (!strcmp(key, "userdir")) {
2662 			find_and_set_rc_var("workdir", linevar);
2663 		    } else if (!strcmp(key, "build_date")) {
2664 			updated = gretl_is_updated(linevar);
2665 		    } else {
2666 			find_and_set_rc_var(key, linevar);
2667 		    }
2668 		}
2669 	    }
2670 	}
2671 
2672 	if (got_recent) {
2673 	    rc_read_file_lists(fp, line);
2674 	}
2675 
2676 	fclose(fp);
2677     }
2678 
2679     return common_read_rc_setup(updated);
2680 }
2681 
2682 #endif /* end of non-Windows versions */
2683 
fontsel_code(GtkAction * action)2684 static int fontsel_code (GtkAction *action)
2685 {
2686     const gchar *s = gtk_action_get_name(action);
2687 
2688     if (!strcmp(s, "MenuFont")) {
2689 	return APP_FONT_SELECTION;
2690     } else {
2691 	return FIXED_FONT_SELECTION;
2692     }
2693 }
2694 
2695 /* font selection via GtkFontChooser */
2696 
2697 #if HAVE_GTK_FONT_CHOOSER
2698 
latin_font_filter(PangoFontFamily * family,PangoFontFace * face,gpointer data)2699 gboolean latin_font_filter (PangoFontFamily *family,
2700 			    PangoFontFace *face,
2701 			    gpointer data)
2702 {
2703     const char *facename = pango_font_face_get_face_name(face);
2704 
2705     if (strstr(facename, "Italic") || strstr(facename, "Bold")) {
2706 	return FALSE;
2707     } else {
2708 	return validate_single_font(family, FONT_FILTER_LATIN);
2709     }
2710 }
2711 
mono_font_filter(PangoFontFamily * family,PangoFontFace * face,gpointer data)2712 gboolean mono_font_filter (PangoFontFamily *family,
2713 			   PangoFontFace *face,
2714 			   gpointer data)
2715 {
2716     const char *facename = pango_font_face_get_face_name(face);
2717 
2718     if (strstr(facename, "Italic") || strstr(facename, "Bold") ||
2719 	strstr(facename, "Oblique")) {
2720 	return FALSE;
2721     } else {
2722 	return validate_single_font(family, FONT_FILTER_LATIN_MONO);
2723     }
2724 }
2725 
close_font_chooser(GtkWidget * w,GtkFontChooser * fc)2726 static void close_font_chooser (GtkWidget *w, GtkFontChooser *fc)
2727 {
2728     gretl_font_filter_cleanup();
2729     gtk_widget_destroy(GTK_WIDGET(fc));
2730 }
2731 
font_selection_ok(GtkWidget * w,GtkFontChooser * fc)2732 static void font_selection_ok (GtkWidget *w, GtkFontChooser *fc)
2733 {
2734     gchar *fontname = gtk_font_chooser_get_font(fc);
2735 
2736     gtk_widget_hide(GTK_WIDGET(fc));
2737 
2738     if (fontname != NULL && *fontname != '\0') {
2739 	int mono = widget_get_int(fc, "mono");
2740 
2741 	if (mono) {
2742 	    set_fixed_font(fontname, 1);
2743 	} else {
2744 	    set_app_font(fontname, 1);
2745 	}
2746 	write_rc(OPT_NONE);
2747     }
2748 
2749     g_free(fontname);
2750     gretl_font_filter_cleanup();
2751     gtk_widget_destroy(GTK_WIDGET(fc));
2752 }
2753 
font_selection_reset(GtkWidget * w,GtkFontChooser * fc)2754 static void font_selection_reset (GtkWidget *w, GtkFontChooser *fc)
2755 {
2756     int mono = widget_get_int(fc, "mono");
2757 
2758     gtk_widget_hide(GTK_WIDGET(fc));
2759 
2760     if (mono) {
2761 	set_fixed_font(default_fixedfont, 1);
2762     } else {
2763 	set_app_font(system_appfont, 1);
2764     }
2765     write_rc(OPT_NONE);
2766 
2767     gretl_font_filter_cleanup();
2768     gtk_widget_destroy(GTK_WIDGET(fc));
2769 }
2770 
chooser_font_selector(GtkAction * action)2771 static void chooser_font_selector (GtkAction *action)
2772 {
2773     static GtkWidget *fc = NULL;
2774     GtkFontFilterFunc filter;
2775     GtkWidget *hbox, *button;
2776     int which = fontsel_code(action);
2777     char *title = NULL;
2778     const char *fontname = NULL;
2779     int err = 0;
2780 
2781     if (fc != NULL) {
2782 	gtk_window_present(GTK_WINDOW(fc));
2783         return;
2784     }
2785 
2786     if (which == FIXED_FONT_SELECTION) {
2787 	title = _("Font for gretl output windows");
2788 	filter = (GtkFontFilterFunc) &mono_font_filter;
2789 	fontname = fixedfontname;
2790     } else if (which == APP_FONT_SELECTION) {
2791 	title = _("Font for menus and labels");
2792 	filter = (GtkFontFilterFunc) &latin_font_filter;
2793 	fontname = appfontname;
2794     }
2795 
2796     err = gretl_font_filter_init();
2797     if (err) {
2798 	errbox("Failed to initialize font filter");
2799 	return;
2800     }
2801 
2802     fc = gtk_font_chooser_dialog_new(title, GTK_WINDOW(mdata->main));
2803     gtk_font_chooser_set_font(GTK_FONT_CHOOSER(fc),
2804 			      fontname);
2805     gtk_font_chooser_set_filter_func(GTK_FONT_CHOOSER(fc),
2806 				     filter, NULL, NULL);
2807     gtk_window_set_position(GTK_WINDOW(fc), GTK_WIN_POS_MOUSE);
2808 
2809     if (which == FIXED_FONT_SELECTION) {
2810 	widget_set_int(fc, "mono", 1);
2811     }
2812 
2813     g_signal_connect(G_OBJECT(fc), "destroy",
2814 		     G_CALLBACK(gtk_widget_destroyed),
2815 		     &fc);
2816 
2817     button = gtk_dialog_get_widget_for_response(GTK_DIALOG(fc),
2818 						GTK_RESPONSE_OK);
2819     if (button != NULL) {
2820 	g_signal_connect(G_OBJECT(button), "clicked",
2821 			 G_CALLBACK(font_selection_ok),
2822 			 fc);
2823     }
2824 
2825     button = gtk_dialog_get_widget_for_response(GTK_DIALOG(fc),
2826 						GTK_RESPONSE_CANCEL);
2827     if (button != NULL) {
2828 	g_signal_connect(G_OBJECT(button), "clicked",
2829 			 G_CALLBACK(close_font_chooser),
2830 			 fc);
2831     }
2832 
2833     hbox = gtk_dialog_get_action_area(GTK_DIALOG(fc));
2834     button = gtk_button_new_with_label(_("Reset to default"));
2835     g_signal_connect(G_OBJECT(button), "clicked",
2836 		     G_CALLBACK(font_selection_reset), fc);
2837     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
2838     gtk_box_reorder_child(GTK_BOX(hbox), button, 0);
2839 
2840     gtk_widget_show_all(fc);
2841 }
2842 
2843 #else /* GTK, not using GtkFontChooser */
2844 
font_selection_ok(GtkWidget * w,GtkFontselHackDialog * fs)2845 static void font_selection_ok (GtkWidget *w, GtkFontselHackDialog *fs)
2846 {
2847     gchar *fontname;
2848 
2849     fontname = gtk_fontsel_hack_dialog_get_font_name(fs);
2850     gtk_widget_hide(GTK_WIDGET(fs));
2851 
2852     if (fontname != NULL && *fontname != '\0') {
2853 	int filter = gtk_fontsel_hack_dialog_get_filter(fs);
2854 
2855 	if (filter == FONT_HACK_LATIN_MONO) {
2856 	    set_fixed_font(fontname, 1);
2857 	} else if (filter == FONT_HACK_LATIN) {
2858 	    set_app_font(fontname, 1);
2859 	}
2860 	write_rc(OPT_NONE);
2861     }
2862 
2863     g_free(fontname);
2864     gtk_widget_destroy(GTK_WIDGET(fs));
2865 }
2866 
font_selection_reset(GtkWidget * w,GtkFontselHackDialog * fs)2867 static void font_selection_reset (GtkWidget *w, GtkFontselHackDialog *fs)
2868 {
2869     int filter = gtk_fontsel_hack_dialog_get_filter(fs);
2870 
2871     gtk_widget_hide(GTK_WIDGET(fs));
2872 
2873     if (filter == FONT_HACK_LATIN_MONO) {
2874 	set_fixed_font(default_fixedfont, 1);
2875     } else if (filter == FONT_HACK_LATIN) {
2876 	set_app_font(system_appfont, 1);
2877     }
2878     write_rc(OPT_NONE);
2879 
2880     gtk_widget_destroy(GTK_WIDGET(fs));
2881 }
2882 
gtk2_font_selector(GtkAction * action)2883 static void gtk2_font_selector (GtkAction *action)
2884 {
2885     static GtkWidget *fontsel = NULL;
2886     GtkWidget *hbox, *button;
2887     int filter, which = fontsel_code(action);
2888     char *title = NULL;
2889     const char *fontname = NULL;
2890 
2891     if (fontsel != NULL) {
2892 	gtk_window_present(GTK_WINDOW(fontsel));
2893         return;
2894     }
2895 
2896     if (which == FIXED_FONT_SELECTION) {
2897 	title = _("Font for gretl output windows");
2898 	filter = FONT_HACK_LATIN_MONO;
2899 	fontname = fixedfontname;
2900     } else if (which == APP_FONT_SELECTION) {
2901 	title = _("Font for menus and labels");
2902 	filter = FONT_HACK_LATIN;
2903 	fontname = appfontname;
2904     }
2905 
2906     fontsel = gtk_fontsel_hack_dialog_new(title);
2907 
2908     gtk_fontsel_hack_dialog_set_filter(GTK_FONTSEL_HACK_DIALOG(fontsel),
2909 				       filter);
2910     gtk_fontsel_hack_dialog_set_font_name(GTK_FONTSEL_HACK_DIALOG(fontsel),
2911 					  fontname);
2912 
2913     gtk_window_set_position(GTK_WINDOW(fontsel), GTK_WIN_POS_MOUSE);
2914 
2915     hbox = gtk_dialog_get_action_area(GTK_DIALOG(fontsel));
2916     button = gtk_button_new_with_label(_("Reset to default"));
2917     g_signal_connect(G_OBJECT(button), "clicked",
2918 		     G_CALLBACK(font_selection_reset),
2919 		     fontsel);
2920     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
2921     gtk_box_reorder_child(GTK_BOX(hbox), button, 0);
2922     gtk_widget_show(button);
2923     gtk_widget_show(hbox);
2924 
2925     g_signal_connect(G_OBJECT(fontsel), "destroy",
2926 		     G_CALLBACK(gtk_widget_destroyed),
2927 		     &fontsel);
2928     g_signal_connect(G_OBJECT(gtk_fontsel_hack_dialog_ok_button(fontsel)),
2929 		     "clicked", G_CALLBACK(font_selection_ok),
2930 		     fontsel);
2931     g_signal_connect(G_OBJECT(gtk_fontsel_hack_dialog_cancel_button(fontsel)),
2932 		     "clicked", G_CALLBACK(delete_widget),
2933 		     fontsel);
2934 
2935     gtk_widget_show(fontsel);
2936 }
2937 
2938 #endif /* end font-selection dialog variants */
2939 
font_selector(GtkAction * action)2940 void font_selector (GtkAction *action)
2941 {
2942 #if HAVE_GTK_FONT_CHOOSER
2943     chooser_font_selector(action);
2944 #else
2945     gtk2_font_selector(action);
2946 #endif
2947 }
2948 
impose_font_scale(int scale,int remember)2949 static void impose_font_scale (int scale, int remember)
2950 {
2951     char fontname[64];
2952 
2953     strcpy(fontname, fixedfontname);
2954     fontname_set_size(fontname, scale);
2955     set_fixed_font(fontname, remember);
2956 
2957 #ifdef G_OS_WIN32
2958     if (*appfontname == '\0') {
2959 	get_default_windows_app_font(appfontname);
2960     }
2961 #endif
2962 
2963     strcpy(fontname, appfontname);
2964     fontname_set_size(fontname, scale);
2965     set_app_font(fontname, remember);
2966 }
2967 
2968 #define FSCALE_DEFAULT 99
2969 
set_fscale_default(GtkWidget * w,int * resp)2970 static void set_fscale_default (GtkWidget *w, int *resp)
2971 {
2972     GtkWidget *dlg = g_object_get_data(G_OBJECT(w), "dlg");
2973 
2974     *resp = FSCALE_DEFAULT;
2975     gtk_widget_destroy(dlg);
2976 }
2977 
font_scale_selector(GtkAction * action)2978 void font_scale_selector (GtkAction *action)
2979 {
2980     const char *opt = N_("Remember this setting");
2981     GtkWidget *dlg, *hbox, *button;
2982     int fscale = tmpfontscale;
2983     int remember = 0;
2984     int resp = GRETL_CANCEL;
2985 
2986     if (fscale == 0) {
2987 	fscale = fontname_get_size(fixedfontname);
2988     }
2989 
2990     dlg = build_checks_dialog(_("gretl: font scale"), NULL,
2991 			      &opt,
2992 			      1, &remember,
2993 			      0, 0,
2994 			      0, NULL,
2995 			      &fscale, _("Scale for monospaced and menu fonts"),
2996 			      8, 24,
2997 			      0, mdata->main,
2998 			      &resp);
2999 
3000     hbox = gtk_dialog_get_action_area(GTK_DIALOG(dlg));
3001     button = gtk_button_new_with_label(_("Reset to default"));
3002     g_object_set_data(G_OBJECT(button), "dlg", dlg);
3003     g_signal_connect(G_OBJECT(button), "clicked",
3004 		     G_CALLBACK(set_fscale_default), &resp);
3005     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
3006     gtk_box_reorder_child(GTK_BOX(hbox), button, 0);
3007 
3008     gtk_widget_show_all(dlg);
3009 
3010     if (resp == GRETL_CANCEL) {
3011 	return;
3012     } else if (resp == FSCALE_DEFAULT) {
3013 	set_fixed_font(default_fixedfont, 1);
3014 	set_app_font(system_appfont, 1);
3015 	write_rc(OPT_NONE);
3016     } else if (fscale > 0) {
3017 	impose_font_scale(fscale, remember);
3018 	tmpfontscale = fscale;
3019     }
3020 }
3021 
update_persistent_graph_colors(void)3022 void update_persistent_graph_colors (void)
3023 {
3024     print_palette_string(gpcolors);
3025 }
3026 
dump_rc(void)3027 void dump_rc (void)
3028 {
3029     char dumper[MAXLEN];
3030     const char *hname;
3031     GDir *test;
3032     FILE *fp;
3033     char *tmp;
3034     char val[6];
3035     int i;
3036 
3037     sprintf(dumper, "%sconfig-dump.txt", gretl_workdir());
3038 
3039     fp = gretl_fopen(dumper, "w");
3040     if (fp == NULL) {
3041 	file_write_errbox(dumper);
3042 	return;
3043     }
3044 
3045     fprintf(fp, "gretl version %s\n", GRETL_VERSION);
3046     fprintf(fp, "built with GTK %d.%d.%d\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
3047 	    GTK_MICRO_VERSION);
3048 
3049     tmp = getenv("HOME");
3050     if (tmp != NULL) {
3051 	fprintf(fp, "HOME='%s'\n", tmp);
3052     } else {
3053 	fputs("HOME not set\n", fp);
3054     }
3055 
3056     for (i=0; rc_vars[i].var != NULL; i++) {
3057 	fprintf(fp, "# %s\n", rc_vars[i].description);
3058 	if (rc_vars[i].flags & BOOLSET) {
3059 	    boolvar_to_str(rc_vars[i].var, val);
3060 	    fprintf(fp, "%s = %s\n", rc_vars[i].key, val);
3061 	} else if (rc_vars[i].flags & INTSET) {
3062 	    fprintf(fp, "%s = %d\n", rc_vars[i].key, *(int *) rc_vars[i].var);
3063 	} else {
3064 	    fprintf(fp, "%s = %s\n", rc_vars[i].key, (char *) rc_vars[i].var);
3065 	}
3066     }
3067 
3068     hname = gretl_home();
3069     test = gretl_opendir(hname);
3070 
3071     if (test != NULL) {
3072 	fprintf(fp, "Directory '%s' exists, OK\n", hname);
3073 	g_dir_close(test);
3074     } else {
3075 	fprintf(fp, "Directory '%s' does not exist\n", hname);
3076     }
3077 
3078     printf("Config info written to %s\n", dumper);
3079 
3080     fclose(fp);
3081 }
3082 
gui_set_working_dir(char * dirname)3083 int gui_set_working_dir (char *dirname)
3084 {
3085     int err = gretl_set_path_by_name("workdir", dirname);
3086 
3087     if (err) {
3088 	gui_errmsg(err);
3089 	delete_from_filelist(FILE_LIST_WDIR, dirname);
3090     } else {
3091 	mkfilelist(FILE_LIST_WDIR, dirname, 0);
3092 	set_workdir_label();
3093     }
3094 
3095     return err;
3096 }
3097 
3098 struct wdir_setter {
3099     GtkWidget *dialog;
3100     GtkWidget *wdir_combo;
3101     GtkWidget *cwd_radio;
3102     GtkWidget *keep_radio;
3103     GtkWidget *ok_button;
3104 };
3105 
3106 /* callback from the file selector */
3107 
set_working_dir_callback(GtkWidget * w,char * path)3108 void set_working_dir_callback (GtkWidget *w, char *path)
3109 {
3110     set_combo_box_default_text(GTK_COMBO_BOX(w), path);
3111 }
3112 
wdir_browse_callback(GtkWidget * w,struct wdir_setter * wset)3113 static void wdir_browse_callback (GtkWidget *w, struct wdir_setter *wset)
3114 {
3115     GtkWidget *combo = wset->wdir_combo;
3116 
3117     file_selector_with_parent(SET_WDIR, FSEL_DATA_MISC, combo,
3118 			      wset->dialog);
3119 }
3120 
open_wdir(GtkButton * b,gpointer p)3121 static void open_wdir (GtkButton *b, gpointer p)
3122 {
3123 #if defined(G_OS_WIN32)
3124     win32_open_file(gretl_workdir());
3125 #elif defined(OS_OSX)
3126     osx_open_file(gretl_workdir());
3127 #else
3128     gretl_fork("xdg-open", gretl_workdir(), NULL);
3129 #endif
3130 }
3131 
3132 static void
add_wdir_content(GtkWidget * dialog,struct wdir_setter * wset)3133 add_wdir_content (GtkWidget *dialog, struct wdir_setter *wset)
3134 {
3135     GtkWidget *hbox, *vbox, *w = NULL;
3136     GtkWidget *entry;
3137     GSList *group = NULL;
3138     GList *list = NULL;
3139     gchar *deflt;
3140 
3141     vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
3142     list = get_working_dir_list();
3143 
3144     hbox = gtk_hbox_new(FALSE, 5);
3145     w = gtk_label_new(_("Working directory:"));
3146     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3147 
3148     deflt = g_strdup(gretl_workdir());
3149     trim_slash(deflt);
3150 
3151     /* combo + browse button for current working dir */
3152     w = combo_box_text_new_with_entry();
3153     gtk_container_add(GTK_CONTAINER(hbox), w);
3154     set_combo_box_strings_from_list(w, list);
3155     if (deflt != NULL) {
3156 	set_combo_box_default_text(GTK_COMBO_BOX(w), deflt);
3157     }
3158     entry = gtk_bin_get_child(GTK_BIN(w));
3159     gtk_entry_set_width_chars(GTK_ENTRY(entry), 32);
3160     gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
3161     wset->wdir_combo = w;
3162     w = gtk_button_new_with_label(_("Browse..."));
3163     g_signal_connect(G_OBJECT(w), "clicked",
3164 		     G_CALLBACK(wdir_browse_callback), wset);
3165     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3166     gtk_box_pack_start(GTK_BOX(vbox), hbox, 0, 0, 5);
3167 
3168     vbox_add_hsep(vbox);
3169 
3170     hbox = gtk_hbox_new(FALSE, 5);
3171     w = gtk_label_new(_("On start-up, gretl should use:"));
3172     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3173     gtk_box_pack_start(GTK_BOX(vbox), hbox, 0, 0, 5);
3174 
3175     /* radio 1 for "next time" */
3176     hbox = gtk_hbox_new(FALSE, 5);
3177     w = gtk_radio_button_new_with_label(group,
3178 					_("the directory selected above"));
3179     group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(w));
3180     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3181     gtk_container_add(GTK_CONTAINER(vbox), hbox);
3182 
3183     /* radio 2 for "next time" */
3184     hbox = gtk_hbox_new(FALSE, 5);
3185     w = gtk_radio_button_new_with_label(group, _("the current directory "
3186 						 "as determined via the shell"));
3187     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), usecwd);
3188     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3189     gtk_container_add(GTK_CONTAINER(vbox), hbox);
3190     wset->cwd_radio = w;
3191 
3192     vbox_add_hsep(vbox);
3193 
3194     hbox = gtk_hbox_new(FALSE, 5);
3195     w = gtk_label_new(_("The file selection dialog should:"));
3196     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3197     gtk_box_pack_start(GTK_BOX(vbox), hbox, 0, 0, 5);
3198 
3199     /* radio 1 for "remember folder" */
3200     hbox = gtk_hbox_new(FALSE, 5);
3201     w = gtk_radio_button_new_with_label(NULL,
3202 					_("remember the last-opened folder"));
3203     group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(w));
3204     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3205     gtk_container_add(GTK_CONTAINER(vbox), hbox);
3206     wset->keep_radio = w;
3207 
3208     /* radio 2 for "remember folder" */
3209     hbox = gtk_hbox_new(FALSE, 5);
3210     w = gtk_radio_button_new_with_label(group, _("always start in the "
3211 						 "working directory"));
3212     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), !keep_folder);
3213     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3214     gtk_container_add(GTK_CONTAINER(vbox), hbox);
3215 
3216     /* button to open working directory via OS */
3217     vbox_add_hsep(vbox);
3218     hbox = gtk_hbox_new(FALSE, 5);
3219     w = gtk_button_new_with_label(_("Open working directory"));
3220     gtk_box_pack_start(GTK_BOX(hbox), w, 0, 0, 5);
3221     gtk_container_add(GTK_CONTAINER(vbox), hbox);
3222     g_signal_connect(w, "clicked", G_CALLBACK(open_wdir), NULL);
3223 
3224     g_list_free(list);
3225     g_free(deflt);
3226 }
3227 
3228 static void
apply_wdir_changes(GtkWidget * w,struct wdir_setter * wset)3229 apply_wdir_changes (GtkWidget *w, struct wdir_setter *wset)
3230 {
3231     char tmp[MAXLEN];
3232     gchar *str;
3233     int err;
3234 
3235     str = combo_box_get_active_text(GTK_COMBO_BOX(wset->wdir_combo));
3236     *tmp = '\0';
3237     if (str != NULL) {
3238 	strncat(tmp, str, MAXLEN - 2);
3239 	g_free(str);
3240     }
3241 
3242     err = gretl_set_path_by_name("workdir", tmp);
3243 
3244     if (err) {
3245 	gui_errmsg(err);
3246 	delete_from_filelist(FILE_LIST_WDIR, tmp);
3247     } else {
3248 	/* sync with "local copy" */
3249 	strcpy(paths.workdir, gretl_workdir());
3250 	mkfilelist(FILE_LIST_WDIR, tmp, 0);
3251     }
3252 
3253     usecwd = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wset->cwd_radio));
3254     keep_folder = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wset->keep_radio));
3255 
3256     if (!err) {
3257 	if (w == wset->ok_button) {
3258 	    gtk_widget_destroy(wset->dialog);
3259 	}
3260 	set_workdir_label();
3261     }
3262 }
3263 
workdir_dialog(int from_wlabel)3264 static void workdir_dialog (int from_wlabel)
3265 {
3266     static GtkWidget *dialog;
3267     struct wdir_setter wset;
3268     GtkWidget *button;
3269     GtkWidget *hbox, *vbox;
3270 
3271     if (dialog != NULL) {
3272 	gtk_window_present(GTK_WINDOW(dialog));
3273 	return;
3274     }
3275 
3276     dialog = gretl_dialog_new(_("gretl: working directory"),
3277 			      mdata->main, GRETL_DLG_BLOCK | GRETL_DLG_RESIZE);
3278 
3279     vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
3280     gtk_box_set_spacing(GTK_BOX(vbox), 5);
3281     g_signal_connect(G_OBJECT(dialog), "destroy",
3282 		     G_CALLBACK(gtk_widget_destroyed),
3283 		     &dialog);
3284 
3285     wset.dialog = dialog;
3286     add_wdir_content(dialog, &wset);
3287 
3288     hbox = gtk_dialog_get_action_area(GTK_DIALOG(dialog));
3289 
3290     button = apply_button(hbox);
3291     g_signal_connect(G_OBJECT(button), "clicked",
3292 		     G_CALLBACK(apply_wdir_changes), &wset);
3293 
3294     button = cancel_button(hbox);
3295     g_signal_connect(G_OBJECT(button), "clicked",
3296 		     G_CALLBACK(delete_widget),
3297 		     dialog);
3298 
3299     wset.ok_button = button = ok_button(hbox);
3300     gtk_widget_grab_default(button);
3301     g_signal_connect(G_OBJECT(button), "clicked",
3302 		     G_CALLBACK(apply_wdir_changes), &wset);
3303 
3304     context_help_button(hbox, WORKDIR);
3305 
3306     gtk_widget_show_all(dialog);
3307 }
3308 
workdir_dialog0(void)3309 void workdir_dialog0 (void)
3310 {
3311     workdir_dialog(0);
3312 }
3313 
workdir_dialog1(void)3314 void workdir_dialog1 (void)
3315 {
3316     workdir_dialog(1);
3317 }
3318 
3319 #if defined(MAC_THEMING)
3320 
set_up_mac_look(void)3321 void set_up_mac_look (void)
3322 {
3323     if (!strcmp(themepref, "Adwaita") ||
3324 	!strcmp(themepref, "Clearlooks") ||
3325 	!strcmp(themepref, "Lion-like")) {
3326 	char *topdir = getenv("GTK_DATA_PREFIX");
3327 	gchar *gtkrc;
3328 
3329 	if (topdir != NULL) {
3330 	    gtkrc = g_strdup_printf("%s/share/themes/%s/gtk-2.0/gtkrc",
3331 				    topdir, themepref);
3332 	    gtk_rc_parse(gtkrc);
3333 	    g_free(gtkrc);
3334 	} else {
3335 #if defined(GTK_PREFIX)
3336 	    /* go with the build-time prefix */
3337 	    gtkrc = g_strdup_printf("%s/share/themes/%s/gtk-2.0/gtkrc",
3338 				    GTK_PREFIX, themepref);
3339 #else
3340 	    /* hard-wired? */
3341 	    const char *path = "/Library/Frameworks/gretl-dev.framework/Resources";
3342 
3343 	    gtkrc = g_strdup_printf("%s/share/themes/%s/gtk-2.0/gtkrc",
3344 				    path, themepref);
3345 #endif
3346 	    gtk_rc_parse(gtkrc);
3347 	    g_free(gtkrc);
3348 	}
3349     }
3350 }
3351 
3352 #elif defined (G_OS_WIN32) && GTK_MAJOR_VERSION < 3
3353 
set_up_windows_look(void)3354 void set_up_windows_look (void)
3355 {
3356     if (!strcmp(themepref, "Windows-10") ||
3357 	!strcmp(themepref, "MS-Windows") ||
3358 	!strcmp(themepref, "Clearlooks")) {
3359 	const char *prefix;
3360 	char sl[2] = {0};
3361 	gchar *gtkrc;
3362 	size_t n;
3363 	int needslash;
3364 
3365 # ifdef PKGBUILD
3366 	prefix = gretl_home();
3367 # else
3368 	prefix = GTK_PREFIX; /* defined at build-time */
3369 # endif
3370 	n = strlen(prefix);
3371 	needslash = (prefix[n-1] != '\\' && prefix[n-1] != '/');
3372 	sl[0] = strchr(prefix, '/') ? '/' : '\\';
3373 	gtkrc = g_strdup_printf("%s%sshare%sthemes%s%s%sgtk-2.0%sgtkrc",
3374 				prefix, (needslash)? sl : "", sl, sl,
3375 				themepref, sl, sl);
3376 	fprintf(stderr, "gtkrc = '%s'\n", gtkrc);
3377 	gtk_rc_parse(gtkrc);
3378 	g_free(gtkrc);
3379     } else {
3380 	GtkSettings *settings = gtk_settings_get_default();
3381 
3382 	g_object_set(G_OBJECT(settings), "gtk-theme-name", "Raleigh", NULL);
3383     }
3384 }
3385 
set_wimp_preferred(int s)3386 void set_wimp_preferred (int s)
3387 {
3388     if (s) {
3389 	strcpy(themepref, "Windows-10");
3390     } else {
3391 	strcpy(themepref, "Clearlooks");
3392     }
3393 }
3394 
3395 #elif defined (G_OS_WIN32) && GTK_MAJOR_VERSION == 3
3396 
set_up_windows_look(void)3397 void set_up_windows_look (void)
3398 {
3399     GtkSettings *settings = gtk_settings_get_default();
3400     char theme_name[16];
3401 
3402     if (!strcmp(themepref, "Windows 10")) {
3403 	strcpy(theme_name, "Windows-10");
3404     } else if (!strcmp(themepref, "Windows 7")) {
3405 	strcpy(theme_name, "win32");
3406     } else {
3407 	strcpy(theme_name, themepref);
3408     }
3409 
3410     g_object_set(G_OBJECT(settings), "gtk-theme-name", theme_name, NULL);
3411 }
3412 
3413 #endif
3414