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 /* gretl.c : main for gretl */
21 
22 #include "gretl.h"
23 #include "gretl_func.h"
24 #include "gretl_xml.h"
25 #include "libset.h"
26 #include "uservar.h"
27 
28 #include "treeutils.h"
29 #include "ssheet.h"
30 #include "console.h"
31 #include "session.h"
32 #include "database.h"
33 #include "datafiles.h"
34 #include "cmdstack.h"
35 #include "filelists.h"
36 #include "toolbar.h"
37 #include "menustate.h"
38 #include "fileselect.h"
39 #include "filters.h"
40 #include "calculator.h"
41 #include "fnsave.h"
42 #include "winstack.h"
43 #include "datawiz.h"
44 #include "varinfo.h"
45 #include "dlgutils.h"
46 #include "fncall.h"
47 #include "selector.h"
48 #include "guiprint.h"
49 #include "tabwin.h"
50 #include "gpt_control.h"
51 #include "gretl_ipc.h"
52 
53 #ifndef G_OS_WIN32
54 # include <unistd.h>
55 # include <sys/types.h>
56 # include "../pixmaps/gretl.xpm"  /* program icon for X */
57 #else
58 # include <windows.h>
59 # include "gretlwin32.h"
60 #endif
61 
62 #ifdef MAC_INTEGRATION
63 # include <gtkosxapplication.h>
64 #endif
65 
66 #define GUI_DEBUG 0
67 #define WIN32_DEBUG 0
68 
69 #if GUI_DEBUG
70 # include "version.h"
71 # include "build.h"
72 #endif
73 
74 #if defined(OS_OSX) && defined(PKGBUILD)
75 # define ALT_MAC_STARTUP
76 #endif
77 
78 /* update.c */
79 extern int update_query (void);
80 
81 /* functions private to gretl.c */
82 static void make_main_window (void);
83 
84 static gboolean main_popup_handler (GtkWidget *w, GdkEventButton *event,
85 				    gpointer data);
86 static GtkWidget *make_main_menu (void);
87 static void start_R_callback (void);
88 static void auto_store (void);
89 static void restore_sample_callback (void);
90 static void show_sample_callback (void);
91 static void mdata_select_all (void);
92 static void mdata_select_list (void);
93 static int gui_query_stop (void);
94 static void mdata_handle_paste (void);
95 
96 #ifdef MAC_INTEGRATION
97 static GtkUIManager *add_mac_menu (void);
98 static void finish_mac_ui (GtkUIManager *mgr);
99 #endif
100 
101 GtkTargetEntry gretl_drag_targets[] = {
102     { "text/uri-list",  0, GRETL_FILENAME },
103     { "db_series_ptr",  GTK_TARGET_SAME_APP, GRETL_DBSERIES_PTR },
104     { "model_ptr",      GTK_TARGET_SAME_APP, GRETL_MODEL_PTR },
105     { "remote_db_ptr",  GTK_TARGET_SAME_APP, GRETL_REMOTE_DB_PTR },
106     { "remote_pkg_ptr", GTK_TARGET_SAME_APP, GRETL_REMOTE_FNPKG_PTR },
107     { "graph_file",     GTK_TARGET_SAME_APP, GRETL_GRAPH_FILE }
108 };
109 
110 static void
111 mdata_handle_drag  (GtkWidget          *widget,
112 		    GdkDragContext     *dc,
113 		    gint                x,
114 		    gint                y,
115 		    GtkSelectionData   *data,
116 		    guint               info,
117 		    guint               time,
118 		    gpointer            p);
119 
120 static char *optdb, *optwebdb, *optpkg;
121 static int optrun, opteng, optbasque, optdump, optver;
122 #ifdef G_OS_WIN32
123 static int optdebug;
124 #endif
125 #ifdef GRETL_OPEN_HANDLER
126 static int optnew;
127 static int optsingle;
128 #endif
129 
130 static gchar *param_msg =
131     N_("\nYou may supply the name of a data or script file on the command line");
132 
133 static GOptionEntry options[] = {
134     { "run", 'r', 0, G_OPTION_ARG_NONE, &optrun,
135        N_("open a script file on startup"), NULL },
136     { "db", 'd', 0, G_OPTION_ARG_STRING, &optdb,
137       N_("open a database on startup"), "DATABASE" },
138     { "webdb", 'w', 0, G_OPTION_ARG_STRING, &optwebdb,
139       N_("open a remote (web) database on startup"), "REMOTE_DB" },
140     { "pkg", 'p', 0, G_OPTION_ARG_STRING, &optpkg,
141       N_("open (edit) a function package on startup"), "FUNCPKG" },
142     { "english", 'e', 0, G_OPTION_ARG_NONE, &opteng,
143       N_("force use of English"), NULL },
144     { "basque", 'q', 0, G_OPTION_ARG_NONE, &optbasque,
145       N_("force use of Basque"), NULL },
146     { "dump", 'c', 0, G_OPTION_ARG_NONE, &optdump,
147       N_("dump gretl configuration to file"), NULL },
148 #ifdef G_OS_WIN32
149     { "debug", 'b', 0, G_OPTION_ARG_NONE, &optdebug,
150       N_("send debugging info to console"), NULL },
151 #endif
152     { "version", 'v', 0, G_OPTION_ARG_NONE, &optver,
153       N_("print version information"), NULL },
154 #ifdef GRETL_OPEN_HANDLER
155     { "new", 'n', 0, G_OPTION_ARG_NONE, &optnew,
156       N_("start a new gretl instance unconditionally"), NULL },
157     { "single", 's', 0, G_OPTION_ARG_NONE, &optsingle,
158       N_("reuse an existing gretl instance unconditionally"), NULL },
159 #endif
160     { NULL, '\0', 0, 0, NULL, NULL, NULL },
161 };
162 
163 windata_t *mdata;
164 DATASET *dataset;
165 MODEL *model;
166 
167 char datafile[MAXLEN];
168 char scriptfile[MAXLEN];
169 
170 int data_status, orig_vars;
171 float gui_scale;
172 
173 /* defaults for some options */
174 int winsize = FALSE;
175 int main_x = -1;
176 int main_y = -1;
177 int mainwin_width = 520;
178 int mainwin_height = 420;
179 
180 #if defined(G_OS_WIN32)
181 char calculator[MAXSTR] = "calc.exe";
182 char latex[MAXSTR] = "pdflatex.exe";
183 char Rcommand[MAXSTR] = "RGui.exe";
184 #elif defined(OS_OSX)
185 char calculator[MAXSTR] = "/Applications/Calculator.app/Contents/MacOS/Calculator";
186 char latex[MAXSTR] = "pdflatex";
187 char Rcommand[MAXSTR] = "/Applications/R.app/Contents/MacOS/R";
188 #else
189 char Browser[MAXSTR] = "mozilla";
190 char calculator[MAXSTR] = "xcalc";
191 char latex[MAXSTR] = "pdflatex";
192 char viewpdf[MAXSTR] = "acroread";
193 char viewps[MAXSTR] = "gv";
194 char Rcommand[MAXSTR] = "xterm -e R";
195 #endif
196 
197 static char tryfile[MAXLEN];
198 
set_tryfile(const char * fname)199 void set_tryfile (const char *fname)
200 {
201     tryfile[0] = '\0';
202     strncat(tryfile, fname, MAXLEN - 1);
203 }
204 
get_tryfile(void)205 char *get_tryfile (void)
206 {
207     return tryfile;
208 }
209 
clear_tryfile(void)210 void clear_tryfile (void)
211 {
212     tryfile[0] = '\0';
213 }
214 
tryfile_is_set(void)215 int tryfile_is_set (void)
216 {
217     return tryfile[0] != '\0';
218 }
219 
spreadsheet_edit(void)220 static void spreadsheet_edit (void)
221 {
222     show_spreadsheet(SHEET_EDIT_VARLIST);
223 }
224 
varinfo_callback(void)225 static void varinfo_callback (void)
226 {
227     varinfo_dialog(mdata->active_var);
228 }
229 
tdisagg_callback(void)230 static void tdisagg_callback (void)
231 {
232     tdisagg_dialog(mdata->active_var);
233 }
234 
bds_callback(void)235 static void bds_callback (void)
236 {
237     bdstest_dialog(mdata->active_var, NULL);
238 }
239 
prefs_dialog_callback(void)240 static void prefs_dialog_callback (void)
241 {
242     preferences_dialog(0, NULL, mdata->main);
243 }
244 
open_script_callback(void)245 static void open_script_callback (void)
246 {
247     file_selector(OPEN_SCRIPT, FSEL_DATA_NONE, NULL);
248 }
249 
open_session_callback(void)250 static void open_session_callback (void)
251 {
252     file_selector(OPEN_SESSION, FSEL_DATA_NONE, NULL);
253 }
254 
edit_spec_callback(GtkAction * action,gpointer p)255 static void edit_spec_callback (GtkAction *action, gpointer p)
256 {
257     file_selector(OPEN_SPEC, FSEL_DATA_NONE, NULL);
258 }
259 
upload_package_callback(GtkAction * action,gpointer p)260 static void upload_package_callback (GtkAction *action, gpointer p)
261 {
262     file_selector(UPLOAD_PKG, FSEL_DATA_NONE, NULL);
263 }
264 
new_matrix_callback(GtkAction * action,gpointer p)265 static void new_matrix_callback (GtkAction *action, gpointer p)
266 {
267     gui_new_matrix(mdata->main);
268 }
269 
pc_change_callback(GtkAction * action,gpointer p)270 static void pc_change_callback (GtkAction *action, gpointer p)
271 {
272     const char *s = gtk_action_get_name(action);
273     int idxvals = !strcmp(s, "idxvals");
274 
275     if (mdata_selection_count() == 1) {
276 	single_percent_change_dialog(mdata->active_var, idxvals);
277     } else {
278 	multi_percent_change_dialog(idxvals);
279     }
280 }
281 
new_gfn_callback(GtkAction * action,gpointer p)282 static void new_gfn_callback (GtkAction *action, gpointer p)
283 {
284     start_new_function_package(NULL, p);
285 }
286 
email_data(gpointer p,guint u,GtkWidget * w)287 static void email_data (gpointer p, guint u, GtkWidget *w)
288 {
289     char gdttmp[FILENAME_MAX];
290     char *title = NULL;
291     int err;
292 
293     /* We need to handle the cases where (a) we have unsaved
294        data or (b) the dataset is saved as a binary file. To
295        do this we write out a temporary copy of the current
296        dataset (gzipped XML).
297     */
298 
299     if (*datafile != '\0') {
300 	const char *base = path_last_element(datafile);
301 	int len = strcspn(base, ".");
302 
303 	if (len > 0) {
304 	    title = g_strndup(base, len);
305 	}
306     }
307 
308     if (title == NULL) {
309 	sprintf(gdttmp, "%suntitled.gdt", gretl_dotdir());
310     } else {
311 	sprintf(gdttmp, "%s%s.gdt", gretl_dotdir(), title);
312 	g_free(title);
313     }
314 
315     err = gretl_write_gdt(gdttmp, NULL, dataset, OPT_Z, 0);
316     if (!err) {
317 	send_attachment(gdttmp);
318     }
319     gretl_remove(gdttmp);
320 }
321 
noalloc(void)322 static void noalloc (void)
323 {
324     fputs("Out of memory!\n", stderr);
325     exit(EXIT_FAILURE);
326 }
327 
script_type(const char * fname)328 static int script_type (const char *fname)
329 {
330     if (has_suffix(fname, ".inp")) {
331 	return EDIT_HANSL;
332     } else if (has_suffix(fname, ".R")) {
333 	return EDIT_R;
334     } else if (has_suffix(fname, ".plt") ||
335 	       has_suffix(fname, ".gp")) {
336 	return EDIT_GP;
337     } else if (has_suffix(fname, ".ox")) {
338 	return EDIT_OX;
339     } else if (has_suffix(fname, ".m")) {
340 	return EDIT_OCTAVE;
341     } else if (has_suffix(fname, ".py")) {
342 	return EDIT_PYTHON;
343     } else if (has_suffix(fname, ".jl")) {
344 	return EDIT_JULIA;
345     } else if (has_suffix(fname, ".do")) {
346 	return EDIT_STATA;
347     } else if (has_suffix(fname, ".mod")) {
348 	return EDIT_DYNARE;
349     } else if (has_suffix(fname, ".lp")) {
350 	return EDIT_LPSOLVE;
351     } else {
352 	return 0;
353     }
354 }
355 
maybe_fix_dbname(char * dbname)356 static void maybe_fix_dbname (char *dbname)
357 {
358     int err;
359 
360     if (strstr(dbname, ".bin") == NULL &&
361 	strstr(dbname, ".rat") == NULL &&
362 	strstr(dbname, ".RAT") == NULL &&
363 	strstr(dbname, ".bn7") == NULL) {
364 	strcat(dbname, ".bin");
365     }
366 
367     err = gretl_test_fopen(dbname, "rb");
368 
369     if (err && !g_path_is_absolute(dbname)) {
370 	gchar *tmp = g_build_filename(gretl_home(), "db",
371 				      dbname, NULL);
372 
373 	err = gretl_test_fopen(tmp, "rb");
374 	if (!err) {
375 	    strcpy(dbname, tmp);
376 	}
377 	g_free(tmp);
378     }
379 }
380 
381 #if !defined(ENABLE_NLS)
382 
real_nls_init(void)383 static void real_nls_init (void)
384 {
385     return;
386 }
387 
388 #elif defined(G_OS_WIN32) && defined(PKGBUILD)
389 
real_nls_init(void)390 static void real_nls_init (void)
391 {
392     char localedir[MAXSTR];
393 
394     gretl_build_path(localedir, gretl_home(), "locale", NULL);
395     record_win32_locale(setlocale(LC_ALL, ""));
396     bindtextdomain(PACKAGE, localedir);
397     textdomain(PACKAGE);
398     bind_textdomain_codeset(PACKAGE, "UTF-8");
399 }
400 
401 #elif defined(OS_OSX)
402 
403 #define LOCALE_CHECK 1
404 
405 #if LOCALE_CHECK
406 
407 #include <CoreFoundation/CoreFoundation.h>
408 
409 /* Use this to check what we get from setlocale() ? */
410 
macos_check_locale(void)411 static void macos_check_locale (void)
412 {
413     CFLocaleRef cfloc = CFLocaleCopyCurrent();
414     CFStringRef cfprop;
415     const char *s;
416 
417     cfprop = (CFStringRef) CFLocaleGetValue(cfloc, kCFLocaleIdentifier);
418     s = CFStringGetCStringPtr(cfprop, kCFStringEncodingASCII);
419     if (s != NULL) {
420 	fprintf(stderr, "macos_check_locale: CF gave ID '%s'\n", s);
421     }
422 
423     CFRelease(cfloc);
424 }
425 
426 #endif /* LOCALE_CHECK */
427 
real_nls_init(void)428 static void real_nls_init (void)
429 {
430     char *gretlhome = getenv("GRETL_HOME");
431     char localedir[MAXSTR];
432     char *p;
433 
434     if (gretlhome == NULL) {
435 	return;
436     }
437 
438     strcpy(localedir, gretlhome);
439     p = strstr(localedir, "share/gretl");
440     if (p != NULL) {
441 	strcpy(p, "share/locale");
442     }
443 
444     p = setlocale(LC_ALL, "");
445     fprintf(stderr, "NLS init: setlocale() gave '%s'\n", p);
446 #if LOCALE_CHECK
447     macos_check_locale();
448 #endif
449     bindtextdomain(PACKAGE, localedir);
450     textdomain(PACKAGE);
451     bind_textdomain_codeset(PACKAGE, "UTF-8");
452 }
453 
454 #else /* end OS X specific code */
455 
456 /* regular *nix treatment of NLS -- also applies
457    for non-package MSYS2 build on Windows */
458 
real_nls_init(void)459 static void real_nls_init (void)
460 {
461     setlocale(LC_ALL, "");
462     bindtextdomain(PACKAGE, LOCALEDIR);
463     textdomain(PACKAGE);
464     bind_textdomain_codeset(PACKAGE, "UTF-8");
465 }
466 
467 #endif /* NLS init variants */
468 
gui_nls_init(void)469 void gui_nls_init (void)
470 {
471     char *mylang = getenv("GRETL_LANG");
472 
473     if (mylang != NULL) {
474 	if (!g_ascii_strcasecmp(mylang, "english") ||
475 	    !g_ascii_strcasecmp(mylang, "C")) {
476 	    /* don't set up translation */
477 	    return;
478 	}
479     }
480 
481     real_nls_init();
482 }
483 
record_filearg(char * targ,const char * src)484 static void record_filearg (char *targ, const char *src)
485 {
486     if (*src == '.') {
487 	gchar *cdir = g_get_current_dir();
488 	gchar *tmp = g_build_filename(cdir, src, NULL);
489 
490 	strcpy(targ, tmp);
491 	g_free(cdir);
492 	g_free(tmp);
493     } else {
494 	strcpy(targ, src);
495     }
496 }
497 
498 #if !defined(G_OS_WIN32) && GTK_MAJOR_VERSION == 3
499 
500 /* cut out annoying runtime spew from GLib-GObject
501    warning about deprecated stuff
502 */
503 
logtrap(const gchar * domain,GLogLevelFlags level,const gchar * msg,gpointer p)504 static void logtrap (const gchar *domain,
505 		     GLogLevelFlags level,
506 		     const gchar *msg,
507 		     gpointer p)
508 {
509     if (strstr(msg, "deprecat") == NULL) {
510 	g_log_default_handler(domain, level, msg, p);
511     }
512 }
513 
quell_glib_spew(void)514 static void quell_glib_spew (void)
515 {
516     g_log_set_handler("GLib-GObject", G_LOG_LEVEL_WARNING,
517 		      (GLogFunc) logtrap, NULL);
518 }
519 
520 #endif
521 
522 #ifdef MAC_INTEGRATION
523 
524 static GtkosxApplication *MacApp;
525 
app_should_quit_cb(GtkosxApplication * App,gpointer p)526 static gboolean app_should_quit_cb (GtkosxApplication *App, gpointer p)
527 {
528     /* return exit_check(); */
529     return FALSE;
530 }
531 
app_will_quit_cb(GtkosxApplication * App,gpointer p)532 static void app_will_quit_cb (GtkosxApplication *App, gpointer p)
533 {
534     gtk_main_quit();
535 }
536 
app_open_file_cb(GtkosxApplication * app,gchar * path,gpointer p)537 static gboolean app_open_file_cb (GtkosxApplication *app,
538 				  gchar *path, gpointer p)
539 {
540     if (path != NULL) {
541 	if (!strcmp(tryfile, path)) {
542 	    /* we're already on it? */
543 	    return TRUE;
544 	}
545 	set_tryfile(path);
546 	return open_tryfile();
547     } else {
548 	clear_tryfile();
549 	return TRUE;
550     }
551 }
552 
install_mac_signals(GtkosxApplication * App)553 static void install_mac_signals (GtkosxApplication *App)
554 {
555     g_signal_connect(App, "NSApplicationBlockTermination",
556 		     G_CALLBACK(app_should_quit_cb), NULL);
557     g_signal_connect(App, "NSApplicationWillTerminate",
558 		     G_CALLBACK(app_will_quit_cb), NULL);
559     g_signal_connect(App, "NSApplicationOpenFile",
560 		     G_CALLBACK(app_open_file_cb), NULL);
561 }
562 
563 #endif /* MAC_INTEGRATION */
564 
565 #if !defined(G_OS_WIN32) && !defined(OS_OSX)
566 
protect_against_ubuntu(void)567 static void protect_against_ubuntu (void)
568 {
569     FILE *fp = fopen("/etc/os-release", "r");
570 
571     if (fp != NULL) {
572 	char line[80];
573 
574 	while (fgets(line, sizeof line, fp)) {
575 	    if (strstr(line, "buntu")) {
576 		setenv("UBUNTU_MENUPROXY", "0", 1);
577 		break;
578 	    }
579 	}
580 	fclose(fp);
581     }
582 }
583 
584 #endif /* end Linux-specific */
585 
586 /* callback from within potentially lengthy libgretl
587    operations: try to avoid having the GUI become
588    totally unresponsive
589 */
590 
gui_show_activity(void)591 static void gui_show_activity (void)
592 {
593     while (gtk_events_pending()) {
594 	gtk_main_iteration();
595     }
596 }
597 
598 #ifdef GRETL_OPEN_HANDLER
599 
absolutize_path(const char * fname)600 static gchar *absolutize_path (const char *fname)
601 {
602     gchar *ret;
603 
604     if (*fname == '\0' || *fname == '~' || g_path_is_absolute(fname)) {
605 	ret = g_strdup(fname);
606     } else {
607 	gchar *dirname = g_get_current_dir();
608 
609 	ret = g_build_filename(dirname, fname, NULL);
610 	g_free(dirname);
611     }
612 
613     return ret;
614 }
615 
maybe_hand_off(char * filearg,char * auxname)616 static gboolean maybe_hand_off (char *filearg, char *auxname)
617 {
618     long gpid = gretl_prior_instance();
619     gboolean ret = FALSE;
620 
621     /* Is there an already-running gretl instance? If so
622        we'll ask whether or not to start a new instance,
623        unless we got @optsingle, which says to reuse the
624        existing one.
625     */
626 
627     if (gpid > 0) {
628 	gint resp = GRETL_NO;
629 
630 	if (!optsingle) {
631 	    resp = no_yes_dialog("gretl", _("Start a new gretl instance?"));
632 	}
633 
634 	if (resp != GRETL_YES) {
635 	    /* try hand-off to prior gretl instance */
636 	    char *fname = filearg;
637 	    gchar *abspath;
638 
639 	    if (*fname == '\0') {
640 		fname = tryfile_is_set() ? tryfile : auxname;
641 	    }
642 	    abspath = absolutize_path(fname);
643 	    ret = forward_open_request(gpid, abspath);
644 	    g_free(abspath);
645 	}
646     }
647 
648     return ret;
649 }
650 
651 #endif /* GRETL_OPEN_HANDLER */
652 
653 #ifdef G_OS_WIN32
654 
655 /* The point of the following special code: when gretl is
656    invoked by the OS (via double-click on a file associated
657    with gretl in the registry) the command-line may contain
658    a "mixed language" filename that is not representable in
659    the locale Code Page. Such a filename will appear in
660    mangled form in the argv array, and we need to call on
661    Windows APIs to get a UTF-16 version of this array.
662 */
663 
alt_gtk_init(int * pargc,char *** pargv,char * filearg,GError ** popterr)664 static void alt_gtk_init (int *pargc,
665 			  char ***pargv,
666 			  char *filearg,
667 			  GError **popterr)
668 {
669     int argc_w = 0;
670     int initted = 0;
671     LPWSTR *argv_w;
672 
673     /* get args as UTF-16 */
674     argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
675 
676     if (argv_w != NULL) {
677 	gchar **argv_u8 = calloc(argc_w, sizeof *argv_u8);
678 	gchar **origp = argv_u8; /* for use with g_free */
679 	int n_u8 = argc_w;
680 	int i, uerr = 0;
681 
682 	/* for GTK, convert args to UTF-8 */
683 	for (i=0; i<argc_w && !uerr; i++) {
684 	    argv_u8[i] = g_utf16_to_utf8(argv_w[i], -1, NULL, NULL, NULL);
685 	    if (argv_u8[i] == NULL) {
686 		uerr = 1;
687 	    }
688 	}
689 	if (!uerr) {
690 	    gtk_init_with_args(&argc_w, &argv_u8, _(param_msg),
691 			       options, "gretl", popterr);
692 	    if (argc_w > 1 && *filearg == '\0') {
693 		strncat(filearg, argv_u8[1], MAXLEN - 1);
694 	    }
695 	    *pargc = argc_w; /* update (residual) arg count */
696 	    initted = 1;
697 	}
698 	/* clean up */
699 	for (i=0; i<n_u8; i++) {
700 	    g_free(origp[i]);
701 	}
702 	g_free(origp);
703 	LocalFree(argv_w);
704     }
705 
706     if (!initted) {
707 	/* try fallback? */
708 	gtk_init_with_args(pargc, pargv, _(param_msg), options,
709 			   "gretl", popterr);
710     }
711 }
712 
713 #endif /* G_OS_WIN32 */
714 
715 #ifdef ALT_MAC_STARTUP
716 
717 #include "osx_env.c"
718 
719 #endif /* specific to Mac package */
720 
have_data(void)721 static int have_data (void)
722 {
723     return dataset != NULL && dataset->v > 0;
724 }
725 
main(int argc,char ** argv)726 int main (int argc, char **argv)
727 {
728     char auxname[MAXLEN];
729     char filearg[MAXLEN];
730     GError *opterr = NULL;
731 
732 #if defined(G_OS_WIN32)
733     /* this must come before NLS initialization */
734     win32_set_gretldir();
735 #elif defined(ALT_MAC_STARTUP)
736     osx_setup_paths();
737 #elif !defined(OS_OSX)
738     /* Linux-specific */
739     protect_against_ubuntu();
740 #endif
741 
742     gui_nls_init();
743 
744     *tryfile = '\0';
745     *scriptfile = '\0';
746     *datafile = '\0';
747     *auxname = '\0';
748     *filearg = '\0';
749 
750 #if GUI_DEBUG
751     fprintf(stderr, "starting gretl %s, build date %s\n", GRETL_VERSION,
752 	    BUILD_DATE);
753 #endif
754 
755 #ifdef G_OS_WIN32
756     alt_gtk_init(&argc, &argv, filearg, &opterr);
757 #else
758     gtk_init_with_args(&argc, &argv, _(param_msg), options, "gretl", &opterr);
759 #endif
760     if (opterr != NULL) {
761 	g_print("%s\n", opterr->message);
762 	exit(EXIT_FAILURE);
763     }
764 
765 #ifdef MAC_INTEGRATION
766     MacApp = g_object_new(GTKOSX_TYPE_APPLICATION, NULL);
767     install_mac_signals(MacApp);
768     gtkosx_application_set_use_quartz_accelerators(MacApp, FALSE);
769 #endif
770 
771 #ifdef G_OS_WIN32
772     /* let's call this before doing libgretl_init */
773 # if WIN32_DEBUG
774     gretl_win32_debug_init(1);
775 # else
776     gretl_win32_debug_init(optdebug);
777 # endif
778 #elif GTK_MAJOR_VERSION == 3
779     quell_glib_spew();
780 #endif
781 
782     libgretl_init();
783     gretl_set_gui_mode();
784 
785 #ifdef G_OS_WIN32
786     gretl_win32_init(optdebug);
787 #else
788     gretl_config_init();
789 #endif
790 
791     if (optver) {
792 	gui_logo(NULL);
793 	exit(EXIT_SUCCESS);
794     } else if (optdump) {
795 	dump_rc();
796 	exit(EXIT_SUCCESS);
797     } else if (optdb != NULL) {
798 	strncat(auxname, optdb, MAXLEN - 1);
799 	maybe_fix_dbname(auxname);
800     } else if (optwebdb != NULL) {
801 	strncat(auxname, optwebdb, MAXLEN - 1);
802     } else if (optpkg != NULL) {
803 	strncat(auxname, optpkg, MAXLEN - 1);
804     }
805 
806     if (opteng) {
807 	force_language(LANG_C);
808 	force_english_help();
809     } else if (optbasque) {
810 	force_language(LANG_EU);
811     }
812 
813 #if GUI_DEBUG
814     fprintf(stderr, "finished option processing\n");
815 #endif
816 
817     /* set libgretl callbacks */
818     set_workdir_callback(gui_set_working_dir);
819     set_show_activity_func(gui_show_activity);
820     set_query_stop_func(gui_query_stop);
821     set_gui_model_list_callback(get_or_send_gui_models);
822     gui_exec_callback_init(); /* see library.c */
823 
824     /* allocate dataset struct */
825     dataset = datainfo_new();
826     if (dataset == NULL) {
827 	noalloc();
828     }
829 
830     /* allocate memory for models */
831     model = allocate_working_model();
832     if (model == NULL) {
833 	noalloc();
834     }
835 
836     library_command_init();
837     helpfile_init();
838     session_init();
839     init_fileptrs();
840 
841     if (argc > 1 && *filearg == '\0') {
842 	/* If we have a residual unhandled command-line argument,
843 	   it should be the name of a file to be opened.
844 	*/
845 	strncat(filearg, argv[1], MAXLEN - 1);
846     }
847 
848 #ifdef GRETL_OPEN_HANDLER
849     if (!optnew && maybe_hand_off(filearg, auxname)) {
850 	fflush(stderr);
851 	exit(EXIT_SUCCESS);
852     }
853 #endif
854 
855 #if GUI_DEBUG
856     fprintf(stderr, "finished miscellaneous init functions\n");
857 #endif
858 
859     if (argc > 1) {
860 	/* Record what is presumably a filename argument
861 	   given on the command line (by now any options will
862 	   have been extracted from the @argv array).
863 	*/
864 	record_filearg(tryfile, filearg);
865     }
866 
867 #if GUI_DEBUG
868     fprintf(stderr, "about to build GUI...\n");
869 #endif
870 
871 #if defined(G_OS_WIN32)
872     set_up_windows_look();
873 #elif defined(OS_OSX) && defined(HAVE_MAC_THEMES)
874     set_up_mac_look();
875 #endif
876 
877 #ifdef GRETL_PID_FILE
878     write_pid_to_file();
879     atexit(delete_pid_from_file);
880 #endif
881 
882     /* create the GUI */
883     set_fixed_font(NULL, 1);
884     gretl_stock_icons_init();
885 #if GUI_DEBUG
886     fprintf(stderr, " done gretl_stock_icons_init\n");
887 #endif
888     make_main_window();
889 
890 #if GUI_DEBUG
891     fprintf(stderr, " done make_main_window\n");
892 #endif
893 
894     add_files_to_menus();
895 
896 #if GUI_DEBUG
897     fprintf(stderr, " done add_files_to_menus\n");
898 #endif
899 
900     session_menu_state(FALSE);
901     restore_sample_state(FALSE);
902     dataset_menubar_state(FALSE);
903 
904 #if GUI_DEBUG
905     fprintf(stderr, "done setting GUI state\n");
906 #endif
907 
908     if (tryfile_is_set()) {
909 	open_tryfile();
910     }
911 
912     /* try opening specified database or package */
913     if (optdb != NULL) {
914 	open_named_db_index(auxname);
915     } else if (optwebdb != NULL) {
916 	open_named_remote_db_index(auxname);
917     } else if (optpkg != NULL) {
918 	edit_specified_package(auxname);
919     }
920 
921 #ifdef GRETL_OPEN_HANDLER
922     install_open_handler();
923 #endif
924 
925 #if GUI_DEBUG
926     fprintf(stderr, "calling gtk_main()\n");
927 #endif
928 
929     /* Enter the event loop */
930     gtk_main();
931 
932     /* clean up before exiting */
933     free_session(1);
934 
935     destroy_working_model(model);
936 
937     library_command_free();
938     libgretl_cleanup();
939 
940     if (data_status) {
941 	destroy_dataset(dataset);
942     }
943 
944     destroy_file_collections();
945     destroy_gui_package_info();
946     free_command_stack();
947 
948 #ifdef MAC_INTEGRATION
949     g_object_unref(MacApp);
950 #endif
951 
952     return EXIT_SUCCESS;
953 }
954 
check_varmenu_state(GtkTreeSelection * select,gpointer p)955 static void check_varmenu_state (GtkTreeSelection *select, gpointer p)
956 {
957     if (mdata->ui != NULL) {
958 	int vnum = 0;
959 	int sc = tree_selection_count(select, &vnum);
960 
961 	if (sc == 1 && vnum > 0) {
962 	    mdata->active_var = vnum;
963 	    maybe_reset_varinfo_dialog();
964 	}
965 
966 	variable_menu_state(sc == 1);
967     }
968 }
969 
970 /* if a keystroke (e.g. page up) would take us to row 0, countermand
971    this and go to row 1 instead
972 */
973 
mdata_avoid_zero(GtkTreeView * view,gpointer p)974 static void mdata_avoid_zero (GtkTreeView *view, gpointer p)
975 {
976     GtkTreePath *path = NULL;
977     int i;
978 
979     gtk_tree_view_get_cursor(view, &path, NULL);
980 
981     if (path != NULL) {
982 	i = gtk_tree_path_get_indices(path)[0];
983 	if (i == 0) {
984 	    GtkTreePath *newp;
985 
986 	    newp = gtk_tree_path_new_from_indices(1, -1);
987 	    gtk_tree_view_set_cursor(view, newp, NULL, FALSE);
988 	    gtk_tree_path_free(newp);
989 	}
990 	gtk_tree_path_free(path);
991     }
992 }
993 
is_control_key(guint k)994 int is_control_key (guint k)
995 {
996     if (k == GDK_Control_L || k == GDK_Control_R) {
997 	return 1;
998     } else if (k == GDK_Meta_L || k == GDK_Meta_R) {
999 	return 1;
1000     } else if (k == GDK_Alt_L || k == GDK_Alt_R) {
1001 	return 1;
1002     } else if (k == GDK_Escape) {
1003 	return 1;
1004     } else {
1005 	return 0;
1006     }
1007 }
1008 
1009 /* keystrokes recognized in the main gretl window */
1010 
catch_mdata_key(GtkWidget * w,GdkEventKey * event,windata_t * vwin)1011 static gint catch_mdata_key (GtkWidget *w, GdkEventKey *event,
1012 			     windata_t *vwin)
1013 {
1014     int Ctrl = (event->state & GDK_CONTROL_MASK);
1015     int Alt = (event->state & GDK_MOD1_MASK);
1016     int k = event->keyval;
1017 
1018     if (is_control_key(event->keyval)) {
1019 	return FALSE;
1020     }
1021 
1022     if (Ctrl && k == GDK_v) {
1023 	/* Ctrl-V for paste */
1024 	mdata_handle_paste();
1025 	return TRUE;
1026     } else if (swallow && Ctrl && (k == GDK_Page_Down || k == GDK_Tab)) {
1027 	gretl_console();
1028 	return TRUE;
1029     }
1030 
1031 #ifdef OS_OSX
1032     if (Ctrl && k == GDK_F2) {
1033 	/* Ctrl-F2 for menubar */
1034 	GtkWidget *menu;
1035 
1036 	menu = gtk_ui_manager_get_widget(mdata->ui, "/menubar");
1037 	if (menu != NULL) {
1038 	    gtk_menu_shell_select_first(GTK_MENU_SHELL(menu), TRUE);
1039 	}
1040 	return TRUE;
1041     } else if (cmd_key(event)) {
1042 	if (k == GDK_v) {
1043 	    mdata_handle_paste();
1044 	    return TRUE;
1045 	} else if (k == GDK_comma) {
1046 	    /* comand-, = preferences */
1047 	    prefs_dialog_callback();
1048 	    return TRUE;
1049 	}
1050     }
1051     if (Alt && k == alt_x_key) {
1052 	/* alt-x -> approx. equals */
1053 	k = GDK_x;
1054     }
1055 #endif
1056 
1057     if (k == GDK_F1) {
1058 	/* invoke help */
1059 	display_text_help(NULL);
1060 	return TRUE;
1061     } else if (k == GDK_g) {
1062 	/* invoke genr */
1063 	genr_callback();
1064 	return TRUE;
1065     } else if (k == GDK_c) {
1066 	/* launch the console */
1067 	gretl_console();
1068 	return TRUE;
1069     } else if (Alt) {
1070 	if (k == GDK_x) {
1071 	    /* Alt-x: invoke command minibuffer */
1072 	    minibuf_callback();
1073 	    return TRUE;
1074 	}
1075     }
1076 
1077     if (dataset->v == 0) {
1078 	goto suppress;
1079     }
1080 
1081     if (k == GDK_r) {
1082 	refresh_data();
1083 	return TRUE;
1084     }
1085 
1086     if (k == GDK_Return              /* display variable(s) */
1087 	|| k == GDK_Delete           /* delete variable(s) */
1088 	|| k == GDK_e || k == GDK_F2 /* edit variable's info */
1089 	|| k == GDK_t                /* graph variable */
1090 	) {
1091 	int selcount, vnum = 0;
1092 
1093 	selcount = vwin_selection_count(mdata, &vnum);
1094 
1095 	if (selcount == 1 && vnum != 0) {
1096 	    mdata->active_var = vnum;
1097 	    if (k == GDK_e || k == GDK_F2) {
1098 		varinfo_dialog(mdata->active_var);
1099 	    } else if (k == GDK_t) {
1100 		do_graph_var(mdata->active_var);
1101 	    } else if (k == GDK_Return) {
1102 		display_var();
1103 	    } else if (k == GDK_Delete) {
1104 		delete_single_var(mdata->active_var);
1105 	    }
1106 	} else if (selcount > 1) {
1107 	    if (k == GDK_Delete) {
1108 		delete_selected_vars();
1109 	    } else if (k == GDK_Return) {
1110 		display_selected();
1111 	    }
1112 	}
1113 
1114 	return TRUE;
1115     }
1116 
1117  suppress:
1118 
1119     /* suppress echo of useless keystrokes */
1120     if (k != GDK_Up && k != GDK_Down &&
1121 	k != GDK_Page_Up && k != GDK_Page_Down &&
1122 	k != GDK_Home && k != GDK_End) {
1123 	return TRUE;
1124     }
1125 
1126     return FALSE;
1127 }
1128 
series_get_parent_iter(int pv,GtkTreeIter * parent)1129 static int series_get_parent_iter (int pv, GtkTreeIter *parent)
1130 {
1131     GtkTreeModel *model =
1132 	gtk_tree_view_get_model(GTK_TREE_VIEW(mdata->listbox));
1133     GtkTreeIter iter;
1134     gchar *idstr;
1135     int ret = 0;
1136 
1137     if (!gtk_tree_model_get_iter_first(model, &iter)) {
1138 	return 0;
1139     }
1140 
1141     while (1) {
1142 	gtk_tree_model_get(model, &iter, 0, &idstr, -1);
1143 	if (atoi(idstr) == pv) {
1144 	    *parent = iter;
1145 	    ret = 1;
1146 	}
1147 	g_free(idstr);
1148 	if (ret || !gtk_tree_model_iter_next(model, &iter)) {
1149 	    break;
1150 	}
1151     }
1152 
1153     return ret;
1154 }
1155 
mdata_select_all(void)1156 static void mdata_select_all (void)
1157 {
1158     GtkTreeSelection *select;
1159 
1160     select = gtk_tree_view_get_selection(GTK_TREE_VIEW(mdata->listbox));
1161     gtk_tree_selection_select_all(select);
1162 }
1163 
get_line_pos(GtkTreeModel * mod)1164 static int get_line_pos (GtkTreeModel *mod)
1165 {
1166     GtkTreeIter iter;
1167     gchar *idstr;
1168     int i = 1, pos = 0;
1169 
1170     if (gtk_tree_model_get_iter_first(mod, &iter)) {
1171 	while (gtk_tree_model_iter_next(mod, &iter)) {
1172 	    gtk_tree_model_get(mod, &iter, 0, &idstr, -1);
1173 	    if (idstr != NULL && atoi(idstr) == mdata->active_var) {
1174 		pos = i;
1175 	    }
1176 	    g_free(idstr);
1177 	    if (pos) {
1178 		break;
1179 	    }
1180 	    i++;
1181 	}
1182     }
1183 
1184     return pos;
1185 }
1186 
panel_dummy_first_sibling(const char * s,gretlopt opt)1187 static int panel_dummy_first_sibling (const char *s, gretlopt opt)
1188 {
1189     int i;
1190 
1191     if (sscanf(s, "%d", &i) == 1 && i > 1) {
1192 	char numstr[16];
1193 
1194 	sprintf(numstr, "%d", i);
1195 	if (strlen(s) == strlen(numstr)) {
1196 	    if (opt == OPT_T) {
1197 		return current_series_index(dataset, "dt_1");
1198 	    } else {
1199 		return current_series_index(dataset, "du_1");
1200 	    }
1201 	}
1202     }
1203 
1204     return 0;
1205 }
1206 
get_lag_or_dummy_parent(int v)1207 static int get_lag_or_dummy_parent (int v)
1208 {
1209     const char *vname = dataset->varname[v];
1210     int pv = 0;
1211 
1212     if (series_get_lag(dataset, v) != 0) {
1213 	pv = series_get_parent_id(dataset, v);
1214     } else if (series_get_transform(dataset, v) == DUMMIFY) {
1215 	pv = series_get_parent_id(dataset, v);
1216     } else if (!strncmp(vname, "dt_", 3)) {
1217 	pv = panel_dummy_first_sibling(vname + 3, OPT_T);
1218     } else if (!strncmp(vname, "du_", 3)) {
1219 	pv = panel_dummy_first_sibling(vname + 3, OPT_U);
1220     }
1221 
1222     if (pv < 0 || pv >= dataset->v) {
1223 	pv = 0;
1224     }
1225 
1226     return pv;
1227 }
1228 
1229 /* populate the list of series in the main gretl window */
1230 
populate_varlist(void)1231 void populate_varlist (void)
1232 {
1233     static gint check_connected;
1234     static gint click_connected;
1235     GtkTreeView *view = GTK_TREE_VIEW(mdata->listbox);
1236     GtkTreeModel *model = gtk_tree_view_get_model(view);
1237     GtkTreeStore *store = GTK_TREE_STORE(model);
1238     GtkTreeSelection *select;
1239     GtkTreeIter iter;
1240     char id[12];
1241     int i, pos = 0;
1242 
1243     if (store != NULL) {
1244 	/* record line position? */
1245 	pos = get_line_pos(model);
1246     }
1247 
1248     gtk_tree_store_clear(store);
1249     gtk_tree_model_get_iter_first(model, &iter);
1250 
1251     for (i=0; i<dataset->v; i++) {
1252 	const char *vlabel;
1253 	int pv = 0;
1254 
1255 	if (series_is_hidden(dataset, i)) {
1256 	    continue;
1257 	}
1258 
1259 	vlabel = series_get_label(dataset, i);
1260 
1261 	if (i > 0) {
1262 	    pv = get_lag_or_dummy_parent(i);
1263 	}
1264 
1265 	if (pv > 0) {
1266 	    GtkTreeIter child_iter, parent_iter;
1267 
1268 	    if (series_get_parent_iter(pv, &parent_iter)) {
1269 		gtk_tree_store_insert_before(store, &child_iter,
1270 					     &parent_iter, NULL);
1271 		sprintf(id, "%d", i);
1272 		gtk_tree_store_set(store, &child_iter,
1273 				   0, id,
1274 				   1, dataset->varname[i],
1275 				   2, vlabel == NULL ? "" : vlabel,
1276 				   -1);
1277 	    } else {
1278 		pv = 0;
1279 	    }
1280 	}
1281 
1282 	if (pv == 0) {
1283 	    gtk_tree_store_append(store, &iter, NULL);
1284 	    sprintf(id, "%d", i);
1285 	    gtk_tree_store_set(store, &iter,
1286 			       0, id,
1287 			       1, dataset->varname[i],
1288 			       2, vlabel == NULL ? "" : vlabel,
1289 			       -1);
1290 	}
1291     }
1292 
1293     gtk_tree_model_get_iter_first(model, &iter);
1294 
1295     if (pos == 0) {
1296 	/* no saved position */
1297 	pos = 1;
1298 	gtk_tree_model_iter_next(model, &iter);
1299     } else {
1300 	/* try to return to previous position */
1301 	GtkTreeIter last;
1302 
1303 	i = 1;
1304 	while (1) {
1305 	    last = iter;
1306 	    if (!gtk_tree_model_iter_next(model, &iter)) {
1307 		/* reached the end! */
1308 		iter = last;
1309 		break;
1310 	    } else if (i == pos) {
1311 		/* found previous position */
1312 		break;
1313 	    }
1314 	    i++;
1315 	}
1316 	pos = i;
1317     }
1318 
1319     mdata->active_var = pos;
1320     select = gtk_tree_view_get_selection(view);
1321     gtk_tree_selection_select_iter(select, &iter);
1322 
1323     if (dataset->v > 1) {
1324 	GtkTreePath *path;
1325 
1326 	sprintf(id, "%d", pos);
1327 	path = gtk_tree_path_new_from_string(id);
1328 	gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1329 	gtk_tree_path_free(path);
1330     }
1331 
1332     if (!check_connected) {
1333 	g_signal_connect(G_OBJECT(select), "changed",
1334 			 G_CALLBACK(check_varmenu_state),
1335 			 mdata);
1336 	g_signal_connect(G_OBJECT(mdata->listbox), "cursor-changed",
1337 			 G_CALLBACK(mdata_avoid_zero),
1338 			 NULL);
1339 	check_connected = 1;
1340     }
1341 
1342     if (!click_connected) {
1343 	g_signal_connect(G_OBJECT(mdata->listbox), "button-press-event",
1344 			 G_CALLBACK(main_popup_handler),
1345 			 mdata);
1346 	g_signal_connect(G_OBJECT(mdata->listbox), "button-press-event",
1347 			 G_CALLBACK(main_varclick),
1348 			 mdata);
1349 	click_connected = 1;
1350     }
1351 
1352     variable_menu_state(TRUE);
1353 }
1354 
mdata_select_last_var(void)1355 void mdata_select_last_var (void)
1356 {
1357     GtkTreeIter iter, last;
1358     GtkTreeView *view;
1359     GtkTreeModel *model;
1360     GtkTreeSelection *select;
1361 
1362     view = GTK_TREE_VIEW(mdata->listbox);
1363     model = gtk_tree_view_get_model(view);
1364     gtk_tree_model_get_iter_first(model, &iter);
1365 
1366     while (1) {
1367 	last = iter;
1368 	if (!gtk_tree_model_iter_next(model, &iter)) {
1369 	    iter = last;
1370 	    break;
1371 	}
1372     }
1373 
1374     select = gtk_tree_view_get_selection(view);
1375     gtk_tree_selection_unselect_all(select);
1376     gtk_tree_selection_select_iter(select, &iter);
1377 }
1378 
real_select_list(const int * list)1379 static void real_select_list (const int *list)
1380 {
1381     GtkTreeIter iter;
1382     GtkTreeView *view;
1383     GtkTreeModel *model;
1384     GtkTreeSelection *select;
1385     gchar *idstr;
1386     int nsel = 0;
1387 
1388     view = GTK_TREE_VIEW(mdata->listbox);
1389     model = gtk_tree_view_get_model(view);
1390     select = gtk_tree_view_get_selection(view);
1391     gtk_tree_selection_unselect_all(select);
1392 
1393     gtk_tree_model_get_iter_first(model, &iter);
1394 
1395     while (nsel < list[0]) {
1396 	if (!gtk_tree_model_iter_next(model, &iter)) {
1397 	    break;
1398 	}
1399 	gtk_tree_model_get(model, &iter, 0, &idstr, -1);
1400 	if (in_gretl_list(list, atoi(idstr))) {
1401 	    gtk_tree_selection_select_iter(select, &iter);
1402 	    nsel++;
1403 	}
1404 	g_free(idstr);
1405     }
1406 }
1407 
mdata_select_list(void)1408 static void mdata_select_list (void)
1409 {
1410     if (n_user_lists() == 0) {
1411 	warnbox(_("No lists are currently defined"));
1412 	return;
1413     } else {
1414 	char lname[32];
1415 	int resp;
1416 
1417 	resp = select_list_dialog(lname);
1418 
1419 	if (!canceled(resp)) {
1420 	    int *list = get_list_by_name(lname);
1421 
1422 	    if (list != NULL) {
1423 		real_select_list(list);
1424 	    }
1425 	}
1426     }
1427 }
1428 
clear_varlist(GtkWidget * widget)1429 void clear_varlist (GtkWidget *widget)
1430 {
1431     GtkTreeModel *model;
1432 
1433     model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1434 
1435     if (GTK_IS_TREE_STORE(model)) {
1436 	gtk_tree_store_clear(GTK_TREE_STORE(model));
1437     } else if (GTK_IS_LIST_STORE(model)) {
1438 	gtk_list_store_clear(GTK_LIST_STORE(model));
1439     }
1440 }
1441 
get_gui_scale(void)1442 static float get_gui_scale (void)
1443 {
1444     GtkSettings *settings = gtk_settings_get_default();
1445     float scale = 1.0;
1446 
1447     if (settings != NULL) {
1448 	gchar *fontname = NULL;
1449 	int fsize;
1450 
1451 	g_object_get(G_OBJECT(settings), "gtk-font-name", &fontname, NULL);
1452 
1453 	if (fontname != NULL) {
1454 	    if (sscanf(fontname, "%*s %d", &fsize) == 1) {
1455 		if (fsize > 10 && fsize < 100) {
1456 		    scale = fsize / 10.0;
1457 		}
1458 	    }
1459 	    g_free(fontname);
1460 	}
1461     }
1462 
1463     return scale;
1464 }
1465 
1466 static gboolean
mainwin_config(GtkWidget * w,GdkEventConfigure * event,gpointer p)1467 mainwin_config (GtkWidget *w, GdkEventConfigure *event, gpointer p)
1468 {
1469     mainwin_width = event->width;
1470     mainwin_height = event->height;
1471 
1472     gdk_window_get_root_origin(gtk_widget_get_window(mdata->main),
1473 			       &main_x, &main_y);
1474 
1475     return FALSE;
1476 }
1477 
1478 /* scale up the main window if it seems to be too tiny in relation to
1479    the screen dimensions
1480 */
1481 
set_main_window_scale(void)1482 static void set_main_window_scale (void)
1483 {
1484     GdkScreen *s = gdk_screen_get_default();
1485 
1486     if (s != NULL) {
1487 	int w = gdk_screen_get_width(s);
1488 	int h = gdk_screen_get_height(s);
1489 	double aspect = 1.25;
1490 	double hfac = 2.10;
1491 
1492 	if (mainwin_height < h / hfac) {
1493 	    mainwin_height = h / hfac;
1494 	    if ((double) w / h > 1.35) {
1495 		/* widescreen */
1496 		aspect = 1.4;
1497 	    }
1498 	    w = aspect * mainwin_height;
1499 	    if (mainwin_width < w) {
1500 		mainwin_width = w;
1501 	    }
1502 	}
1503     }
1504 }
1505 
show_link_cursor(GtkWidget * w,gpointer p)1506 void show_link_cursor (GtkWidget *w, gpointer p)
1507 {
1508     GdkWindow *window = gtk_widget_get_window(w);
1509     GdkCursor *c = gdk_cursor_new(GDK_HAND2);
1510 
1511     if (c != NULL) {
1512 	gdk_window_set_cursor(window, c);
1513 	gdk_cursor_unref(c);
1514     }
1515 }
1516 
mainwin_get_vwin_insertion(void)1517 int mainwin_get_vwin_insertion (void)
1518 {
1519     int ins = -1;
1520 
1521     if (mdata->hpanes1 != NULL) {
1522 	if (gtk_paned_get_child2(GTK_PANED(mdata->hpanes1)) == NULL) {
1523 	    ins = 1;
1524 	} else if (mdata->hpanes2 != NULL) {
1525 	    if (gtk_paned_get_child1(GTK_PANED(mdata->hpanes2)) == NULL) {
1526 		ins = 2;
1527 	    } else if (gtk_paned_get_child2(GTK_PANED(mdata->hpanes2)) == NULL) {
1528 		ins = 3;
1529 	    }
1530 	}
1531     }
1532 
1533     return ins;
1534 }
1535 
mainwin_insert_vwin(windata_t * vwin)1536 int mainwin_insert_vwin (windata_t *vwin)
1537 {
1538     int ret = 0;
1539 
1540     if (vwin == NULL) {
1541 	return ret;
1542     }
1543     if (gtk_paned_get_child2(GTK_PANED(mdata->hpanes1)) == NULL) {
1544 	gtk_paned_add2(GTK_PANED(mdata->hpanes1), vwin->vbox);
1545 	gtk_paned_set_position(GTK_PANED(mdata->hpanes1), mainwin_width/2);
1546 	ret = 1;
1547     } else if (mdata->hpanes2 != NULL) {
1548 	GtkWidget *vp = gtk_widget_get_parent(mdata->hpanes2);
1549 
1550 	fprintf(stderr, "HERE hpanes2\n");
1551 	if (gtk_paned_get_child1(GTK_PANED(mdata->hpanes2)) == NULL) {
1552 	    gtk_paned_add1(GTK_PANED(mdata->hpanes2), vwin->vbox);
1553 	    fprintf(stderr, " add child 1\n");
1554 	    ret = 2;
1555 	} else if (gtk_paned_get_child2(GTK_PANED(mdata->hpanes2)) == NULL) {
1556 	    gtk_paned_add2(GTK_PANED(mdata->hpanes2), vwin->vbox);
1557 	    fprintf(stderr, " add child 2\n");
1558 	    gtk_paned_set_position(GTK_PANED(mdata->hpanes2), mainwin_width/2);
1559 	    ret = 3;
1560 	}
1561 	if (ret) {
1562 	    gtk_paned_set_position(GTK_PANED(vp), mainwin_height/2);
1563 	}
1564     }
1565 
1566     return ret;
1567 }
1568 
gretl_show_console(void)1569 static void gretl_show_console (void)
1570 {
1571     if (swallow) {
1572 	mainwin_insert_vwin(gretl_console());
1573     } else {
1574 	gretl_console();
1575     }
1576 }
1577 
make_main_window(void)1578 static void make_main_window (void)
1579 {
1580 #ifdef MAC_INTEGRATION
1581     GtkUIManager *mac_mgr = NULL;
1582 #endif
1583     GtkWidget *box, *dlabel;
1584     GtkWidget *hbox, *ebox;
1585     GtkWidget *wlabel = NULL;
1586     const char *titles[] = {
1587 	N_("ID #"),
1588 	N_("Variable name"),
1589 	N_("Descriptive label")
1590     };
1591     GType types[] = {
1592 	G_TYPE_STRING,
1593 	G_TYPE_STRING,
1594 	G_TYPE_STRING
1595     };
1596 
1597     mdata = gretl_viewer_new(MAINWIN, "gretl", NULL);
1598     if (mdata == NULL) {
1599 	noalloc();
1600     }
1601 
1602     gui_scale = get_gui_scale();
1603 #if GUI_DEBUG
1604     fprintf(stderr, " gui_scale = %g\n", (double) gui_scale);
1605 #endif
1606 
1607     if (!winsize || mainwin_width <= 200 || mainwin_height <= 200) {
1608 	/* set default window size */
1609 	mainwin_width = 650 * gui_scale;
1610 	mainwin_height = 460 * gui_scale;
1611 	if (swallow) {
1612 	    mainwin_width *= 1.6;
1613 	}
1614 	set_main_window_scale();
1615     }
1616 
1617     g_signal_connect(G_OBJECT(mdata->main), "configure-event",
1618 		     G_CALLBACK(mainwin_config), NULL);
1619     g_signal_connect(G_OBJECT(mdata->main), "delete-event",
1620 		     G_CALLBACK(exit_check), NULL);
1621     g_signal_connect(G_OBJECT(mdata->main), "destroy",
1622 		     G_CALLBACK(gtk_main_quit), NULL);
1623 
1624     gtk_window_set_default_size(GTK_WINDOW(mdata->main),
1625 				mainwin_width, mainwin_height);
1626 
1627     mdata->mbar = make_main_menu();
1628     if (mdata->mbar == NULL) {
1629 	exit(EXIT_FAILURE);
1630     }
1631 
1632 #if GUI_DEBUG
1633     fprintf(stderr, " got past make_main_menu()\n");
1634 #endif
1635 
1636     /* put the main menu bar in place */
1637     if (swallow) {
1638 	box = g_object_get_data(G_OBJECT(mdata->main), "topbox");
1639 	gtk_box_pack_start(GTK_BOX(box), mdata->mbar, TRUE, TRUE, 0);
1640     } else {
1641 	box = gtk_hbox_new(FALSE, 0);
1642 	gtk_box_pack_start(GTK_BOX(box), mdata->mbar, TRUE, TRUE, 0);
1643 	gtk_box_pack_start(GTK_BOX(mdata->vbox), box, FALSE, FALSE, 0);
1644     }
1645 
1646 #ifdef MAC_INTEGRATION
1647     mac_mgr = add_mac_menu();
1648 #endif
1649 
1650     /* this will hold the list of variables */
1651     box = gtk_vbox_new(FALSE, 0);
1652 
1653     /* label for name of datafile */
1654     dlabel = gtk_label_new(_(" No datafile loaded "));
1655     g_object_set_data(G_OBJECT(mdata->main), "dlabel", dlabel);
1656 
1657     /* label for working directory */
1658     hbox = gtk_hbox_new(FALSE, 5);
1659     ebox = gtk_event_box_new();
1660     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1661     gtk_box_pack_start(GTK_BOX(hbox), dlabel, FALSE, FALSE, 0);
1662     wlabel = gtk_label_new("");
1663     gtk_widget_set_tooltip_text(wlabel, _("Working directory: "
1664 					  "click to configure"));
1665     g_object_set_data(G_OBJECT(mdata->main), "wlabel", wlabel);
1666     gtk_container_add(GTK_CONTAINER(ebox), wlabel);
1667     gtk_box_pack_end(GTK_BOX(hbox), ebox, FALSE, FALSE, 5);
1668     g_signal_connect(ebox, "button-press-event",
1669 		     G_CALLBACK(workdir_dialog1), NULL);
1670     g_signal_connect(ebox, "enter-notify-event",
1671 		     G_CALLBACK(show_link_cursor), NULL);
1672 
1673 #if GUI_DEBUG
1674     fprintf(stderr, " adding main-window listbox...\n");
1675 #endif
1676 
1677     vwin_add_list_box(mdata, GTK_BOX(box), 3, 0, types, titles, 1);
1678 
1679     gtk_drag_dest_set(mdata->listbox,
1680 		      GTK_DEST_DEFAULT_ALL,
1681 		      gretl_drag_targets, 2,
1682 		      GDK_ACTION_COPY);
1683     g_signal_connect(G_OBJECT(mdata->listbox), "drag-data-received",
1684 		     G_CALLBACK(mdata_handle_drag),
1685 		     NULL);
1686     g_signal_connect(G_OBJECT(mdata->listbox), "key-press-event",
1687 		     G_CALLBACK(catch_mdata_key),
1688 		     mdata);
1689 
1690     gtk_box_pack_start(GTK_BOX(mdata->vbox), box, TRUE, TRUE, 0);
1691     mdata->status = gtk_label_new("");
1692     gtk_box_pack_start(GTK_BOX(mdata->vbox), mdata->status, FALSE, TRUE, 0);
1693 
1694 #if GUI_DEBUG
1695     fprintf(stderr, " finalizing main window...\n");
1696 #endif
1697 
1698     /* put stuff into list box, activate menus */
1699     if (have_data()) {
1700 	populate_varlist();
1701     }
1702 
1703 #if GUI_DEBUG
1704     fprintf(stderr, "  step 1 done\n");
1705 #endif
1706 
1707     /* set a proportional font for menus, etc. */
1708     set_app_font(NULL, 1);
1709 
1710 #if GUI_DEBUG
1711     fprintf(stderr, "  set_app_font done\n");
1712 #endif
1713 
1714     vwin_add_winlist(mdata);
1715     add_mainwin_toolbar(mdata->vbox);
1716 
1717 #if GUI_DEBUG
1718     fprintf(stderr, "  add_mainwin_toolbar done\n");
1719 #endif
1720 
1721     if (swallow) {
1722 	gretl_show_console();
1723     }
1724 
1725     gtk_widget_show_all(mdata->main);
1726 
1727 #ifdef MAC_INTEGRATION
1728     if (mac_mgr != NULL) {
1729 	finish_mac_ui(mac_mgr);
1730     }
1731 #endif
1732 
1733 #if GUI_DEBUG
1734     fprintf(stderr, "  gtk_widget_show_all done\n");
1735 #endif
1736 
1737     if (winsize && main_x >= 0 && main_y >= 0) {
1738 	gtk_window_move(GTK_WINDOW(mdata->main), main_x, main_y);
1739     }
1740 
1741     if (wlabel != NULL) {
1742 	set_workdir_label();
1743     }
1744 
1745 #if GUI_DEBUG
1746     fprintf(stderr, "  possible window_move done\n");
1747 #endif
1748 }
1749 
1750 #ifdef OS_OSX
1751 # define CTRL_ALL "<meta>A"
1752 # define HELPKEY "<meta>question"
1753 #else
1754 # define CTRL_ALL "<control>A"
1755 # define HELPKEY NULL
1756 #endif
1757 
1758 GtkActionEntry main_entries[] = {
1759     /* File */
1760     { "File",         NULL, N_("_File"), NULL, NULL, NULL },
1761     { "OpenDataMenu", NULL, N_("_Open data"), NULL, NULL, NULL },
1762     { "OpenData",     GTK_STOCK_OPEN, N_("_User file..."), NULL, NULL, G_CALLBACK(open_data) },
1763     { "DisplayDataFiles", GTK_STOCK_OPEN, N_("_Sample file..."), "", NULL, G_CALLBACK(show_files) },
1764     { "AppendData", NULL, N_("_Append data..."), NULL, NULL, G_CALLBACK(open_data) },
1765     { "SaveData",  GTK_STOCK_SAVE, N_("_Save data"), NULL, NULL, G_CALLBACK(auto_store) },
1766     { "SaveDataAs", GTK_STOCK_SAVE_AS, N_("Save data _as..."), NULL, NULL, G_CALLBACK(fsave_callback) },
1767     { "ExportData", NULL, N_("_Export data..."), NULL, NULL, G_CALLBACK(fsave_callback) },
1768     { "MailData", GRETL_STOCK_MAIL, N_("Send To..."), NULL, NULL, G_CALLBACK(email_data) },
1769     { "NewData", GTK_STOCK_NEW, N_("_New data set"), NULL, NULL, G_CALLBACK(newdata_callback) },
1770     { "ClearData", GTK_STOCK_CLEAR, N_("C_lear data set"), NULL, NULL, G_CALLBACK(verify_clear_data) },
1771 
1772     { "WorkingDir", NULL, N_("_Working directory..."), NULL, NULL, G_CALLBACK(workdir_dialog0) },
1773     { "ScriptFiles", NULL, N_("_Script files"), NULL, NULL, NULL },
1774     { "OpenScript", GTK_STOCK_OPEN, N_("_User file..."), "", NULL, G_CALLBACK(open_script_callback) },
1775     { "DisplayScripts", GTK_STOCK_OPEN, N_("_Example scripts..."), "", NULL, G_CALLBACK(show_files) },
1776     { "NewScript", GTK_STOCK_NEW, N_("_New script"), "", NULL, NULL },
1777     { "GretlScript", NULL, N_("gretl script"), NULL, NULL, G_CALLBACK(new_script_callback) },
1778     { "GnuplotScript", NULL, N_("gnuplot script"), NULL, NULL, G_CALLBACK(new_script_callback) },
1779     { "RScript", NULL, N_("R script"), NULL, NULL, G_CALLBACK(new_script_callback) },
1780     { "OctaveScript", NULL, N_("Octave script"), NULL, NULL, G_CALLBACK(new_script_callback) },
1781     { "PyScript", NULL, N_("Python script"), NULL, NULL, G_CALLBACK(new_script_callback) },
1782     { "JuliaScript", NULL, N_("Julia program"), NULL, NULL, G_CALLBACK(new_script_callback) },
1783     { "OxScript", NULL, N_("Ox program"), NULL, NULL, G_CALLBACK(new_script_callback) },
1784     { "StataScript", NULL, N_("Stata program"), NULL, NULL, G_CALLBACK(new_script_callback) },
1785     { "lpsolveScript", NULL, N_("lpsolve program"), NULL, NULL, G_CALLBACK(new_script_callback) },
1786 
1787     { "SessionFiles", NULL, N_("_Session files"), NULL, NULL, NULL },
1788     { "OpenSession", GTK_STOCK_OPEN, N_("_Open session..."), "", NULL, G_CALLBACK(open_session_callback) },
1789     { "SaveSession", GTK_STOCK_SAVE, N_("_Save session"), "", NULL,
1790       G_CALLBACK(save_session_callback) },
1791     { "SaveSessionAs", GTK_STOCK_SAVE_AS, N_("Save session _as..."), NULL, NULL,
1792       G_CALLBACK(save_session_callback) },
1793 
1794     { "Databases", NULL, N_("_Databases"), NULL, NULL, NULL },
1795     { "NativeDB", GTK_STOCK_OPEN, N_("_Gretl native..."), "", NULL, G_CALLBACK(show_files) },
1796     { "RATSDB", GTK_STOCK_OPEN, N_("_RATS 4..."), "", NULL, G_CALLBACK(open_data) },
1797     { "PcGiveDB", GTK_STOCK_OPEN, N_("_PcGive..."), "", NULL, G_CALLBACK(open_data) },
1798     { "RemoteDB", GTK_STOCK_NETWORK, N_("On database _server..."), NULL, NULL, G_CALLBACK(show_files) },
1799     { "DBnomics", GRETL_STOCK_DBN, "DB.NOMICS", NULL, NULL, NULL }, /* DB\u00B7NOMICS ? */
1800     { "DBNbrowse", NULL, N_("Browse..."), NULL, NULL, G_CALLBACK(show_files) },
1801     { "DBNseries", NULL, N_("Specific series..."), NULL, NULL, G_CALLBACK(dbnomics_specific_series) },
1802 
1803     { "Packages", NULL, N_("_Function packages"), NULL, NULL, NULL },
1804     { "LocalGfn", GTK_STOCK_OPEN, N_("On _local machine..."), "", NULL, G_CALLBACK(show_files) },
1805     { "RemoteGfn", GTK_STOCK_NETWORK, N_("On _server..."), NULL, NULL, G_CALLBACK(show_files) },
1806     { "EditGfn", GTK_STOCK_EDIT, N_("Edit package..."), NULL, NULL, G_CALLBACK(edit_gfn_callback) },
1807     { "NewGfn", GTK_STOCK_NEW, N_("_New package"), "", NULL, G_CALLBACK(new_gfn_callback) },
1808     { "UploadGfn", GTK_STOCK_NETWORK, N_("_Upload package..."), "", NULL, G_CALLBACK(upload_package_callback) },
1809     { "EditSpec", GTK_STOCK_EDIT, N_("Edit spec file..."), NULL, NULL, G_CALLBACK(edit_spec_callback) },
1810     { "AddonResources", NULL, N_("_Resource from addon"), NULL, NULL, NULL },
1811 
1812     { "Quit", GTK_STOCK_QUIT, NULL, NULL, NULL,  G_CALLBACK(menu_exit_check)},
1813 
1814     /* Tools */
1815     { "Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
1816     { "Preferences", NULL, N_("_Preferences"), NULL, NULL, NULL },
1817     { "PrefsGeneral", GTK_STOCK_PREFERENCES, N_("_General..."), NULL, NULL,
1818       G_CALLBACK(prefs_dialog_callback) },
1819     { "FontScale", GTK_STOCK_ZOOM_IN, N_("Font _scale..."), NULL, NULL,
1820       G_CALLBACK(font_scale_selector) },
1821     { "FixedFont", GTK_STOCK_SELECT_FONT, N_("Monospaced _font..."), NULL, NULL,
1822       G_CALLBACK(font_selector) },
1823     { "MenuFont", GTK_STOCK_SELECT_FONT, N_("_Menu font..."), NULL, NULL,
1824       G_CALLBACK(font_selector) },
1825     { "StatsTables", NULL, N_("_Statistical tables"), NULL, NULL, G_CALLBACK(stats_calculator) },
1826     { "PValues", NULL, N_("_P-value finder"), NULL, NULL, G_CALLBACK(stats_calculator) },
1827     { "DistGraphs", NULL, N_("_Distribution graphs"), NULL, NULL, G_CALLBACK(stats_calculator) },
1828     { "PlotCurve", NULL, N_("_Plot a curve"), NULL, NULL, G_CALLBACK(stats_calculator) },
1829     { "TestStats", NULL, N_("_Test statistic calculator"), NULL, NULL, G_CALLBACK(stats_calculator) },
1830     { "NonparamTests", NULL, N_("_Nonparametric tests"), NULL, NULL, G_CALLBACK(stats_calculator) },
1831     { "SetSeed", NULL, N_("_Seed for random numbers"), NULL, NULL, G_CALLBACK(rand_seed_dialog) },
1832     { "CommandLog", NULL, N_("_Command log"), NULL, NULL, G_CALLBACK(view_command_log) },
1833     { "ShowConsole", NULL, N_("_Gretl console"), NULL, NULL, G_CALLBACK(gretl_show_console) },
1834     { "Gnuplot", NULL, N_("_Gnuplot"), NULL, NULL, G_CALLBACK(launch_gnuplot_interactive) },
1835     { "StartR", NULL, N_("Start GNU _R"), NULL, NULL, G_CALLBACK(start_R_callback) },
1836     { "NistTest", NULL, N_("_NIST test suite"), NULL, NULL, NULL },
1837     { "NistBasic", NULL, N_("_Basic"), NULL, NULL, G_CALLBACK(do_nistcheck) },
1838     { "NistVerbose", NULL, N_("_Verbose"), NULL, NULL, G_CALLBACK(do_nistcheck) },
1839     { "NistVVerbose", NULL, N_("V_ery verbose"), NULL, NULL, G_CALLBACK(do_nistcheck) },
1840 
1841     /* Data */
1842     { "Data", NULL, N_("_Data"), NULL, NULL, NULL },
1843     { "DataSelectAll", NULL, N_("Select _all"), CTRL_ALL, NULL, G_CALLBACK(mdata_select_all) },
1844     { "DefineList", NULL, N_("Define or edit _list..."), NULL, NULL, G_CALLBACK(gui_define_list) },
1845     { "SelectList", NULL, N_("_Set selection from list..."), NULL, NULL, G_CALLBACK(mdata_select_list) },
1846     { "DisplayValues", NULL, N_("_Display values"), NULL, NULL, G_CALLBACK(display_selected) },
1847     { "EditValues", NULL, N_("_Edit values"), NULL, NULL, G_CALLBACK(spreadsheet_edit) },
1848     { "AddObs", NULL, N_("_Add observations..."), NULL, NULL, G_CALLBACK(do_add_obs) },
1849     { "RemoveObs", NULL, N_("_Remove extra observations"), NULL, NULL, G_CALLBACK(do_remove_obs) },
1850     { "DataInfo", NULL, N_("_Dataset info"), NULL, NULL, G_CALLBACK(dataset_info) },
1851     { "DataMarkers", NULL, N_("_Observation markers..."), NULL, NULL, G_CALLBACK(markers_callback) },
1852     { "VarLabels", NULL, N_("_Variable labels..."), NULL, NULL, G_CALLBACK(labels_callback) },
1853     { "DataStructure", NULL, N_("Dataset _structure..."), NULL, NULL, G_CALLBACK(data_structure_dialog) },
1854     { "DataCompact", NULL, N_("_Compact data..."), NULL, NULL, G_CALLBACK(do_compact_data_set) },
1855     { "DataExpand", NULL, N_("_Expand data..."), NULL, NULL, G_CALLBACK(do_expand_data_set) },
1856     { "DataTranspose", NULL, N_("_Transpose data..."), NULL, NULL, G_CALLBACK(gui_transpose_data) },
1857     { "DataSort", NULL, N_("_Sort data..."), NULL, NULL, G_CALLBACK(gui_sort_data) },
1858     { "GSETMISS", NULL, N_("Set missing _value code..."), NULL, NULL, G_CALLBACK(gretl_callback) },
1859 
1860     /* View */
1861     { "View", NULL, N_("_View"), NULL, NULL, NULL },
1862     { "IconView", NULL, N_("_Icon view"), NULL, NULL, G_CALLBACK(view_session) },
1863     { "GraphVars", NULL, N_("_Graph specified vars"), NULL, NULL, NULL },
1864     { "TSPlot", NULL, N_("_Time series plot..."), NULL, NULL, G_CALLBACK(selector_callback) },
1865     { "ScatterPlot", NULL, N_("X-Y _scatter..."), NULL, NULL, G_CALLBACK(selector_callback) },
1866     { "ImpulsePlot", NULL, N_("X-Y with _impulses..."), NULL, NULL, G_CALLBACK(selector_callback) },
1867     { "FactorPlot", NULL, N_("X-Y with _factor separation..."), NULL, NULL, G_CALLBACK(selector_callback) },
1868     { "FrischPlot", NULL, N_("X-Y with _control..."), NULL, NULL, G_CALLBACK(selector_callback) },
1869     { "GR_BOX", NULL, N_("_Boxplots..."), NULL, NULL, G_CALLBACK(selector_callback) },
1870     { "GR_FBOX", NULL, N_("_Factorized boxplot..."), NULL, NULL, G_CALLBACK(selector_callback) },
1871     { "GR_QQ", NULL, N_("_Q-Q plot..."), NULL, NULL, G_CALLBACK(selector_callback) },
1872     { "ThreeDPlot", NULL, N_("_3D plot..."), NULL, NULL, G_CALLBACK(selector_callback) },
1873     { "MapPlot", NULL, N_("_Display map"), NULL, NULL, G_CALLBACK(map_plot_callback) },
1874     { "MultiPlots", NULL, N_("_Multiple graphs"), NULL, NULL, NULL },
1875     { "MultiXY", NULL, N_("X-Y _scatters..."), NULL, NULL, G_CALLBACK(selector_callback) },
1876     { "MultiTS", NULL, N_("_Time series..."), NULL, NULL, G_CALLBACK(selector_callback) },
1877     { "summary", NULL, N_("_Summary statistics"), NULL, NULL, G_CALLBACK(menu_op_action) },
1878     { "corr", NULL, N_("_Correlation matrix"), NULL, NULL, G_CALLBACK(menu_op_action) },
1879     { "xtab", NULL, N_("Cross _Tabulation"), NULL, NULL, G_CALLBACK(menu_op_action) },
1880     { "pca", NULL, N_("_Principal components"), NULL, NULL, G_CALLBACK(menu_op_action) },
1881     { "mahal", NULL, N_("_Mahalanobis distances"), NULL, NULL, G_CALLBACK(menu_op_action) },
1882     { "xcorrgm", NULL, N_("C_ross-correlogram"), NULL, NULL, G_CALLBACK(xcorrgm_callback) },
1883 
1884     /* Add */
1885     { "Add", NULL, N_("_Add"), NULL, NULL, NULL },
1886     { "logs", NULL, N_("_Logs of selected variables"), NULL, NULL, G_CALLBACK(logs_etc_callback) },
1887     { "square", NULL, N_("_Squares of selected variables"), NULL, NULL, G_CALLBACK(logs_etc_callback) },
1888     { "lags", NULL, N_("_Lags of selected variables"), NULL, NULL, G_CALLBACK(logs_etc_callback) },
1889     { "diff", NULL, N_("_First differences of selected variables"), NULL, NULL,
1890       G_CALLBACK(logs_etc_callback) },
1891     { "ldiff", NULL, N_("_Log differences of selected variables"), NULL, NULL,
1892       G_CALLBACK(logs_etc_callback) },
1893     { "sdiff", NULL, N_("_Seasonal differences of selected variables"), NULL, NULL,
1894       G_CALLBACK(logs_etc_callback) },
1895     { "pcdiff", NULL, N_("_Percentage change of selected variables"), NULL, NULL,
1896       G_CALLBACK(pc_change_callback) },
1897     { "idxvals", NULL, N_("_100-based indices of selected variables"), NULL, NULL,
1898       G_CALLBACK(pc_change_callback) },
1899     { "stdize", NULL, N_("_Standardize selected variables"), NULL, NULL,
1900       G_CALLBACK(logs_etc_callback) },
1901     { "AddIndex", NULL, N_("_Index variable"), NULL, NULL, G_CALLBACK(add_index) },
1902     { "AddTime", NULL, N_("_Time trend"), NULL, NULL, G_CALLBACK(add_index) },
1903     { "AddUnit", NULL, N_("_Panel unit index"), NULL, NULL, G_CALLBACK(add_index) },
1904     { "AddRandom", NULL, N_("_Random variable..."), NULL, NULL, G_CALLBACK(stats_calculator) },
1905     { "PeriodDums", NULL, N_("_Periodic dummies"), NULL, NULL, G_CALLBACK(add_dummies) },
1906     { "UnitDums", NULL, N_("_Unit dummies"), NULL, NULL, G_CALLBACK(add_dummies) },
1907     { "TimeDums", NULL, N_("_Time dummies"), NULL, NULL, G_CALLBACK(add_dummies) },
1908     { "RangeDum", NULL, N_("_Observation range dummy"), NULL, NULL, G_CALLBACK(range_dummy_dialog) },
1909     { "dummify", NULL, N_("Dummies for _discrete variable..."), NULL, NULL,
1910       G_CALLBACK(add_dummies) },
1911     { "NewMatrix", NULL, N_("_Define matrix..."), NULL, NULL, G_CALLBACK(new_matrix_callback) },
1912 
1913     /* Sample */
1914     { "Sample", NULL, N_("_Sample"), NULL, NULL, NULL },
1915     { "SMPL", NULL, N_("_Set range..."), NULL, NULL, G_CALLBACK(sample_range_dialog) },
1916     { "FullRange", NULL, N_("_Restore full range"), NULL, NULL, G_CALLBACK(restore_sample_callback) },
1917     { "ShowSample", NULL, N_("_Show status"), NULL, NULL, G_CALLBACK(show_sample_callback) },
1918     { "SMPLBOOL", NULL, N_("_Restrict, based on criterion..."), NULL, NULL,
1919       G_CALLBACK(sample_restrict_dialog) },
1920     { "SMPLRAND", NULL, N_("R_andom sub-sample..."), NULL, NULL, G_CALLBACK(sample_range_dialog) },
1921     { "SampleWReplace", NULL, N_("_Resample with replacement..."), NULL, NULL,
1922       G_CALLBACK(gui_resample_data) },
1923     { "DropMissing", NULL, N_("Drop observations with _missing values..."), NULL, NULL,
1924       G_CALLBACK(drop_missing_data) },
1925     { "PermaSample", NULL, N_("Make current subsample permanent..."), NULL, NULL,
1926       G_CALLBACK(perma_sample_callback) },
1927     { "CountMissing", NULL, N_("_Count missing values"), NULL, NULL, G_CALLBACK(count_missing) },
1928 
1929     /* Variable */
1930     { "Variable", NULL, N_("_Variable"), NULL, NULL, NULL },
1931     { "VarDisplay", NULL, N_("_Display values"), NULL, NULL, G_CALLBACK(display_var) },
1932     { "VarSummary", NULL, N_("_Summary statistics"), NULL, NULL, G_CALLBACK(menu_op_action) },
1933     { "normtest", NULL, N_("_Normality test"), NULL, NULL, G_CALLBACK(menu_op_action) },
1934     { "FreqDist", NULL, N_("_Frequency distribution..."), NULL, NULL, G_CALLBACK(do_freq_dist) },
1935     { "Density", NULL, N_("Estimated _density plot..."), NULL, NULL, G_CALLBACK(do_kernel) },
1936     { "boxplot", NULL, N_("_Boxplot"), NULL, NULL, G_CALLBACK(boxplot_callback) },
1937     { "qqplot", NULL, N_("Normal _Q-Q plot..."), NULL, NULL, G_CALLBACK(do_qqplot) },
1938     { "Gini", NULL, N_("_Gini coefficient"), NULL, NULL, G_CALLBACK(do_gini) },
1939     { "rmplot", NULL, N_("_Range-mean graph"), NULL, NULL, G_CALLBACK(do_range_mean) },
1940     { "VarTSPlot", NULL, N_("_Time series plot"), NULL, NULL, G_CALLBACK(ts_plot_callback) },
1941     { "PanPlot", NULL, N_("_Panel plot..."), NULL, NULL, G_CALLBACK(ts_plot_callback) },
1942     { "URTests", NULL, N_("_Unit root tests"), NULL, NULL, NULL },
1943     { "adf", NULL, N_("_Augmented Dickey-Fuller test"), NULL, NULL, G_CALLBACK(ur_callback) },
1944     { "dfgls", NULL, N_("ADF-GLS test"), NULL, NULL, G_CALLBACK(ur_callback) },
1945     { "kpss", NULL, N_("_KPSS test"), NULL, NULL, G_CALLBACK(ur_callback) },
1946     { "levinlin", NULL, N_("_Levin-Lin-Chu test"), NULL, NULL, G_CALLBACK(ur_callback) },
1947     { "fractint", NULL, N_("_Fractional integration"), NULL, NULL, G_CALLBACK(do_fractint) },
1948     { "corrgm", NULL, N_("_Correlogram"), NULL, NULL, G_CALLBACK(do_corrgm) },
1949     { "pergm", NULL, N_("_Periodogram"), NULL, NULL, G_CALLBACK(do_pergm) },
1950     { "Filter", NULL, N_("_Filter"), NULL, NULL, NULL },
1951     { "FilterSMA", NULL, N_("_Simple moving average"), NULL, NULL, G_CALLBACK(filter_callback) },
1952     { "FilterEMA", NULL, N_("_Exponential moving average"), NULL, NULL, G_CALLBACK(filter_callback) },
1953     { "FilterHP", NULL, N_("_Hodrick-Prescott"), NULL, NULL, G_CALLBACK(filter_callback) },
1954     { "FilterBK", NULL, N_("_Baxter-King"), NULL, NULL, G_CALLBACK(filter_callback) },
1955     { "FilterBW", NULL, N_("_Butterworth"), NULL, NULL, G_CALLBACK(filter_callback) },
1956     { "FilterPoly", NULL, N_("_Polynomial trend"), NULL, NULL, G_CALLBACK(filter_callback) },
1957     { "FilterFD", NULL, N_("_Fractional difference"), NULL, NULL, G_CALLBACK(filter_callback) },
1958 #ifdef HAVE_X12A
1959     { "X12A", NULL, N_("_X-12-ARIMA analysis"), NULL, NULL, G_CALLBACK(do_tramo_x12a) },
1960 #endif
1961 #ifdef HAVE_TRAMO
1962     { "Tramo", NULL, N_("_TRAMO analysis"), NULL, NULL, G_CALLBACK(do_tramo_x12a) },
1963 #endif
1964     { "Hurst", NULL, N_("_Hurst exponent"), NULL, NULL, G_CALLBACK(do_hurst) },
1965     { "BDS", NULL, N_("BDS nonlinearity test"), NULL, NULL, G_CALLBACK(bds_callback) },
1966     { "tdisagg", NULL, N_("Disaggregate..."), NULL, NULL, G_CALLBACK(tdisagg_callback) },
1967     { "EditAttrs", NULL, N_("_Edit attributes"), NULL, NULL, G_CALLBACK(varinfo_callback) },
1968     { "VSETMISS", NULL, N_("Set missing _value code..."), NULL, NULL, G_CALLBACK(gretl_callback) },
1969     { "GENR", NULL, N_("Define _new variable..."), NULL, NULL, G_CALLBACK(gretl_callback) },
1970 
1971     /* Model */
1972     { "Model", NULL, N_("_Model"), NULL, NULL, NULL },
1973     { "ols", NULL, N_("_Ordinary Least Squares"), NULL, NULL, G_CALLBACK(model_callback) },
1974     { "ivreg", NULL, N_("_Instrumental variables"), NULL, NULL, NULL },
1975     { "tsls", NULL, N_("_Two-Stage Least Squares"), NULL, NULL, G_CALLBACK(model_callback) },
1976     { "iv-liml", NULL, N_("_LIML"), NULL, NULL, G_CALLBACK(model_callback) },
1977     { "iv-gmm", NULL, N_("_GMM"), NULL, NULL, G_CALLBACK(model_callback) },
1978     { "LinearModels", NULL, N_("Other _linear models"), NULL, NULL, NULL },
1979     { "wls", NULL, N_("_Weighted Least Squares"), NULL, NULL, G_CALLBACK(model_callback) },
1980     { "hsk", NULL, N_("H_eteroskedasticity corrected"), NULL, NULL, G_CALLBACK(model_callback) },
1981     { "regls", NULL, N_("_Regularized least squares"), NULL, NULL, G_CALLBACK(model_callback) },
1982     { "mpols", NULL, N_("High _precision OLS"), NULL, NULL, G_CALLBACK(model_callback) },
1983     { "anova", NULL, N_("ANOVA"), NULL, NULL, G_CALLBACK(model_callback) },
1984     { "TSModels", NULL, N_("_Univariate time series"), NULL, NULL, NULL },
1985     { "arima", NULL, N_("ARI_MA"), NULL, NULL, G_CALLBACK(model_callback) },
1986     { "garch", NULL, N_("_GARCH"), NULL, NULL, G_CALLBACK(model_callback) },
1987     { "midasreg", NULL, "MIDAS", NULL, NULL, G_CALLBACK(model_callback) },
1988     { "AR-GLS", NULL, N_("_AR errors (GLS)"), NULL, NULL, NULL },
1989     { "ar1", NULL, N_("_AR(1)"), NULL, NULL, G_CALLBACK(model_callback) },
1990     { "ar", NULL, N_("_AR (general)"), NULL, NULL, G_CALLBACK(model_callback) },
1991     { "TSMulti", NULL, N_("_Multivariate time series"), NULL, NULL, NULL },
1992     { "var", NULL, N_("_Vector Autoregression"), NULL, NULL, G_CALLBACK(selector_callback) },
1993     { "VLAGSEL", NULL, N_("VAR _lag selection"), NULL, NULL, G_CALLBACK(selector_callback) },
1994     { "vecm", NULL, N_("V_ECM"), NULL, NULL, G_CALLBACK(selector_callback) },
1995     { "coint2", NULL, N_("Cointegration test (_Johansen)"), NULL, NULL, G_CALLBACK(selector_callback) },
1996     { "coint", NULL, N_("Cointegration test (_Engle-Granger)"), NULL, NULL, G_CALLBACK(selector_callback) },
1997     { "PanelModels", NULL, N_("_Panel"), NULL, NULL, NULL },
1998     { "panel", NULL, N_("_Fixed or random effects"), NULL, NULL, G_CALLBACK(model_callback) },
1999     { "PANEL_WLS", NULL, N_("_Weighted least squares"), NULL, NULL, G_CALLBACK(model_callback) },
2000     { "PANEL_B", NULL, N_("_Between model"), NULL, NULL, G_CALLBACK(model_callback) },
2001     { "dpanel", NULL, N_("_Dynamic panel model"), NULL, NULL, G_CALLBACK(model_callback) },
2002     { "FE_LOGISTIC", NULL, N_("FE logistic"), NULL, NULL, G_CALLBACK(model_callback) },
2003     { "LimdepModels", NULL, N_("_Limited dependent variable"), NULL, NULL, NULL },
2004     { "logit", NULL, N_("_Logit"), NULL, NULL, NULL },
2005     { "blogit", NULL, N_("_Binary"), NULL, NULL, G_CALLBACK(model_callback) },
2006     { "ologit", NULL, N_("_Ordered"), NULL, NULL, G_CALLBACK(model_callback) },
2007     { "mlogit", NULL, N_("_Multinomial"), NULL, NULL, G_CALLBACK(model_callback) },
2008     { "probit", NULL, N_("_Probit"), NULL, NULL, NULL },
2009     { "bprobit", NULL, N_("_Binary"), NULL, NULL, G_CALLBACK(model_callback) },
2010     { "oprobit", NULL, N_("_Ordered"), NULL, NULL, G_CALLBACK(model_callback) },
2011     { "biprobit", NULL, N_("Bi_variate"), NULL, NULL, G_CALLBACK(model_callback) },
2012     { "reprobit", NULL, N_("_Random effects"), NULL, NULL, G_CALLBACK(model_callback) },
2013     { "tobit", NULL, N_("To_bit"), NULL, NULL, G_CALLBACK(model_callback) },
2014     { "heckit", NULL, N_("_Heckit"), NULL, NULL, G_CALLBACK(model_callback) },
2015     { "countmod", NULL, N_("_Count data"), NULL, NULL, G_CALLBACK(model_callback) },
2016     { "duration", NULL, N_("_Duration data"), NULL, NULL, G_CALLBACK(model_callback) },
2017     { "logistic", NULL, N_("Lo_gistic"), NULL, NULL, G_CALLBACK(model_callback) },
2018     { "intreg", NULL, N_("_Interval regression"), NULL, NULL, G_CALLBACK(model_callback) },
2019     { "RobustModels", NULL, N_("_Robust estimation"), NULL, NULL, NULL },
2020     { "lad", NULL, N_("Least _Absolute Deviation"), NULL, NULL, G_CALLBACK(model_callback) },
2021     { "quantreg", NULL, N_("_Quantile regression"), NULL, NULL, G_CALLBACK(model_callback) },
2022     { "loess", NULL, N_("_Loess"), NULL, NULL, G_CALLBACK(selector_callback) },
2023     { "nadarwat", NULL, N_("_Nadaraya-Watson"), NULL, NULL, G_CALLBACK(selector_callback) },
2024     { "nls", NULL, N_("_Nonlinear Least Squares"), NULL, NULL, G_CALLBACK(gretl_callback) },
2025     { "mle", NULL, N_("_Maximum likelihood"), NULL, NULL, G_CALLBACK(gretl_callback) },
2026     { "gmm", NULL, N_("_GMM"), NULL, NULL, G_CALLBACK(gretl_callback) },
2027     { "system", NULL, N_("_Simultaneous equations"), NULL, NULL, G_CALLBACK(gretl_callback) },
2028 
2029     /* Help */
2030     { "Help", NULL, N_("_Help"), NULL, NULL, NULL },
2031     { "TextCmdRef", GTK_STOCK_HELP, N_("_Command reference"), HELPKEY, NULL, G_CALLBACK(display_text_help) },
2032     { "FuncRef", GTK_STOCK_HELP, N_("_Function reference"), "", NULL, G_CALLBACK(display_text_help) },
2033     { "PkgHelp", GTK_STOCK_HELP, N_("_Packages"), "", NULL, G_CALLBACK(display_text_help) },
2034     { "UserGuide", GRETL_STOCK_PDF, N_("_User's guide"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2035     { "PDFCmdRef", GRETL_STOCK_PDF, N_("_Command reference"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2036     { "KbdRef", GRETL_STOCK_PDF, N_("_Keyboard shortcuts"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2037     { "Primer", GRETL_STOCK_PDF, N_("_Hansl primer"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2038     { "Pkgbook", GRETL_STOCK_PDF, N_("_Function package guide"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2039     { "gretlMPI", GRETL_STOCK_PDF, N_("_gretl + MPI"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2040     { "gretlSVM", GRETL_STOCK_PDF, N_("_gretl + SVM"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2041     { "gretlDBN", GRETL_STOCK_PDF, N_("_gretl + DB.NOMICS"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2042     { "GeoplotDoc", GRETL_STOCK_PDF, N_("Creating maps"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2043     { "LpsolveDoc", GRETL_STOCK_PDF, N_("Linear programming"), NULL, NULL, G_CALLBACK(display_pdf_help) },
2044     { "UpdateCheck", GTK_STOCK_NETWORK, N_("Check for _updates"), NULL, NULL, G_CALLBACK(update_query) },
2045     { "SFAddons", NULL, N_("Check for _addons"), NULL, NULL, G_CALLBACK(show_files) },
2046     { "About", GTK_STOCK_ABOUT, N_("_About gretl"), NULL, NULL, G_CALLBACK(about_dialog) }
2047 };
2048 
count_substrings(gchar ** S)2049 static int count_substrings (gchar **S)
2050 {
2051     int i, n = 0;
2052 
2053     for (i=0; S[i] != NULL; i++) {
2054 	if (S[i][0] != '\0') {
2055 	    n++;
2056 	}
2057     }
2058 
2059     return n;
2060 }
2061 
2062 /* Given an "internal" menu path, as in gretlmain.xml (with up
2063    to three slash-separated components), return its user-visible
2064    counterpart, translated and with mnemonics stripped.
2065 */
2066 
main_menu_user_string(const gchar * mpath)2067 static gchar *main_menu_user_string (const gchar *mpath)
2068 {
2069     gchar *ret = NULL;
2070     gchar **S;
2071 
2072     if (mpath == NULL) {
2073 	return NULL;
2074     }
2075 
2076     if (!strncmp(mpath, "/menubar/", 9)) {
2077 	mpath += 8;
2078     } else if (!strncmp(mpath, "MAINWIN/", 8)) {
2079 	mpath += 8;
2080     } else if (*mpath == '/') {
2081 	mpath += 1;
2082     } else if (!strncmp(mpath, "MODELWIN/", 9)) {
2083 	/* this @mpath is model-window only */
2084 	return NULL;
2085     }
2086 
2087     S = g_strsplit(mpath, "/", 0);
2088 
2089     if (S != NULL && S[0] != NULL) {
2090 	const gchar *p[3] = {NULL, NULL, NULL};
2091 	int nmain = G_N_ELEMENTS(main_entries);
2092 	int i, j, ns = count_substrings(S);
2093 	int matched = 0;
2094 
2095 	for (i=0; i<nmain && !p[0]; i++) {
2096 	    if (main_entries[i].callback == NULL &&
2097 		!strcmp(S[0], main_entries[i].name)) {
2098 		p[0] = main_entries[i].label;
2099 		matched++;
2100 		if (S[1] != NULL) {
2101 		    for (j=i+1; j<nmain && !p[1]; j++) {
2102 			if (main_entries[j].callback == NULL &&
2103 			    !strcmp(S[1], main_entries[j].name)) {
2104 			    p[1] = main_entries[j].label;
2105 			    matched++;
2106 			}
2107 		    }
2108 		    if (S[2] != NULL) {
2109 			for (j=i+1; j<nmain && !p[2]; j++) {
2110 			    if (main_entries[j].callback == NULL &&
2111 				!strcmp(S[2], main_entries[j].name)) {
2112 				p[2] = main_entries[j].label;
2113 				matched++;
2114 			    }
2115 			}
2116 		    }
2117 		}
2118 	    }
2119 	}
2120 	if (matched < ns) {
2121 	    fprintf(stderr, "Invalid menu path '%s' (matched = %d)\n", mpath, matched);
2122 	} else if (p[2] != NULL) {
2123 	    ret = g_strdup_printf("%s/%s/%s", _(p[0]), _(p[1]), _(p[2]));
2124 	} else if (p[1] != NULL) {
2125 	    ret = g_strdup_printf("%s/%s", _(p[0]), _(p[1]));
2126 	} else if (p[0] != NULL) {
2127 	    ret = g_strdup_printf("%s", _(p[0]));
2128 	}
2129     }
2130 
2131     g_strfreev(S);
2132 
2133     if (ret != NULL) {
2134 	gretl_delchar('_', ret);
2135     }
2136 
2137     return ret;
2138 }
2139 
user_friendly_menu_path(const char * mpath,gboolean modelwin)2140 gchar *user_friendly_menu_path (const char *mpath,
2141 				gboolean modelwin)
2142 {
2143     gchar *ret = NULL;
2144 
2145     if (modelwin) {
2146 	if (!strcmp(mpath, "Analysis")) {
2147 	    ret = g_strdup(_("_Analysis"));
2148 	    gretl_delchar('_', ret);
2149 	} else {
2150 	    ret = g_strdup(_(mpath));
2151 	}
2152     } else {
2153 	ret = main_menu_user_string(mpath);
2154     }
2155 
2156     return ret;
2157 }
2158 
add_conditional_items(windata_t * vwin)2159 static void add_conditional_items (windata_t *vwin)
2160 {
2161     GtkUIManager *ui = vwin->ui;
2162     int add_appfont = 1;
2163 
2164     if (add_appfont) {
2165 	gtk_ui_manager_add_ui(ui, gtk_ui_manager_new_merge_id(ui),
2166 			      "/menubar/Tools/Preferences",
2167 			      N_("_Menu font..."),
2168 			      "MenuFont",
2169 			      GTK_UI_MANAGER_MENUITEM,
2170 			      FALSE);
2171     }
2172 
2173 #ifdef HAVE_X12A
2174     gtk_ui_manager_add_ui(ui, gtk_ui_manager_new_merge_id(ui),
2175 			  "/menubar/Variable/X12A",
2176 			  N_("_X-12-ARIMA analysis"),
2177 			  "X12A",
2178 			  GTK_UI_MANAGER_MENUITEM,
2179 			  FALSE);
2180 #endif
2181 
2182 #ifdef HAVE_TRAMO
2183     gtk_ui_manager_add_ui(ui, gtk_ui_manager_new_merge_id(ui),
2184 			  "/menubar/Variable/Tramo",
2185 			  N_("_TRAMO analysis"),
2186 			  "Tramo",
2187 			  GTK_UI_MANAGER_MENUITEM,
2188 			  FALSE);
2189 #endif
2190 
2191     maybe_add_packages_to_menus(vwin);
2192 }
2193 
2194 /* retrieve the XML description of the main window menus */
2195 
get_main_ui(void)2196 static gchar *get_main_ui (void)
2197 {
2198     gchar *main_ui = NULL;
2199     gchar *fname;
2200     int err;
2201 
2202     fname = g_strdup_printf("%sui%cgretlmain.xml", gretl_home(), SLASH);
2203     err = gretl_file_get_contents(fname, &main_ui, NULL);
2204     g_free(fname);
2205 
2206     return err ? NULL : main_ui;
2207 }
2208 
2209 #ifdef MAC_INTEGRATION
2210 
new_gretl_instance(GtkAction * action,gpointer data)2211 static void new_gretl_instance (GtkAction *action, gpointer data)
2212 {
2213     char *topdir = getenv("GTK_DATA_PREFIX");
2214 
2215     if (topdir != NULL) {
2216 	gchar *cmd;
2217 
2218 	cmd = g_strdup_printf("open -n %s/../../../Gretl.app", topdir);
2219 	system(cmd);
2220 	g_free(cmd);
2221     }
2222 }
2223 
mac_minimize(GtkAction * action,gpointer data)2224 static void mac_minimize (GtkAction *action, gpointer data)
2225 {
2226     if (data != NULL) {
2227 	gtk_window_iconify(GTK_WINDOW(data));
2228     }
2229 }
2230 
2231 static GtkActionEntry mac_entries[] = {
2232     { "FileMenu", NULL, "_File", NULL, NULL, NULL },
2233     { "NewInstanceAction", NULL, "_New gretl instance", NULL, NULL,
2234       G_CALLBACK(new_gretl_instance)},
2235 };
2236 
2237 const gchar *mac_ui =
2238     "<ui>"
2239     "  <menubar>"
2240     "    <menu name='File' action='FileMenu'>"
2241     "      <menuitem name='NewInstance' action='NewInstanceAction'/>"
2242     "    </menu>"
2243     "  </menubar>"
2244     "</ui>";
2245 
add_mac_menu(void)2246 static GtkUIManager *add_mac_menu (void)
2247 {
2248     GtkUIManager *mgr;
2249     GtkActionGroup *actions;
2250     GtkWidget *menu;
2251     GtkAccelGroup *accel_group;
2252     GError *error = NULL;
2253 
2254     mgr = gtk_ui_manager_new();
2255     actions = gtk_action_group_new("MacActions");
2256     gtk_action_group_set_translation_domain(actions, "gretl");
2257     gtk_action_group_add_actions(actions, mac_entries,
2258 				 G_N_ELEMENTS(mac_entries),
2259 				 mdata->main);
2260     gtk_ui_manager_insert_action_group(mgr, actions, 0);
2261     g_object_unref(actions);
2262 
2263     if (!gtk_ui_manager_add_ui_from_string(mgr, mac_ui, -1, &error)) {
2264 	g_message("building mac menu failed: %s", error->message);
2265 	g_error_free(error);
2266     }
2267 
2268     menu = gtk_ui_manager_get_widget(mgr, "/menubar/");
2269     g_object_ref_sink(menu);
2270 
2271     return mgr;
2272 }
2273 
2274 /* add minimal top-of-screen gretl menu */
2275 
finish_mac_ui(GtkUIManager * mac_mgr)2276 static void finish_mac_ui (GtkUIManager *mac_mgr)
2277 {
2278     GtkWidget *menu;
2279 
2280     menu = gtk_ui_manager_get_widget(mac_mgr, "/menubar");
2281     if (menu != NULL) {
2282 	/* @menu needs a gtk window toplevel */
2283 	gtk_box_pack_end(GTK_BOX(mdata->vbox), menu, FALSE, FALSE, 0);
2284 	gtk_widget_hide(menu);
2285 	gtkosx_application_set_menu_bar(MacApp, GTK_MENU_SHELL(menu));
2286     }
2287     gtkosx_application_set_use_quartz_accelerators(MacApp, FALSE);
2288     gtkosx_application_ready(MacApp);
2289 }
2290 
2291 #endif /* MAC_INTEGRATION */
2292 
make_main_menu(void)2293 static GtkWidget *make_main_menu (void)
2294 {
2295     GtkWidget *menu = NULL;
2296     GtkActionGroup *actions;
2297     gchar *main_ui = NULL;
2298     GError *error = NULL;
2299 
2300     main_ui = get_main_ui();
2301 #if GUI_DEBUG
2302     fprintf(stderr, "   main_ui = %p\n", (void *) main_ui);
2303 #endif
2304     if (main_ui == NULL) {
2305 	return NULL;
2306     }
2307 
2308     mdata->ui = gtk_ui_manager_new();
2309     actions = gtk_action_group_new("Actions");
2310     gtk_action_group_set_translation_domain(actions, "gretl");
2311     gtk_action_group_add_actions(actions, main_entries,
2312 				 G_N_ELEMENTS(main_entries), mdata);
2313     gtk_ui_manager_insert_action_group(mdata->ui, actions, 0);
2314     g_object_unref(actions);
2315 
2316     gtk_window_add_accel_group(GTK_WINDOW(mdata->main),
2317 			       gtk_ui_manager_get_accel_group(mdata->ui));
2318 
2319     if (!gtk_ui_manager_add_ui_from_string(mdata->ui, main_ui, -1, &error)) {
2320 	g_message("building menus failed: %s", error->message);
2321 	g_error_free(error);
2322     } else {
2323 #if GUI_DEBUG
2324 	fprintf(stderr, "   adding conditional menu items...\n");
2325 #endif
2326 	add_conditional_items(mdata);
2327 #if GUI_DEBUG
2328 	fprintf(stderr, "   conditional items done\n");
2329 #endif
2330 	menu = gtk_ui_manager_get_widget(mdata->ui, "/menubar");
2331 	if (menu == NULL) {
2332 	    fprintf(stderr, "/menubar widget is NULL!\n");
2333 	} else {
2334 	    GtkWidget *dataitem;
2335 
2336 	    dataitem = gtk_ui_manager_get_widget(mdata->ui, "/menubar/Data");
2337 	    if (dataitem == NULL) {
2338 		fprintf(stderr, "/menubar/Data widget is NULL!\n");
2339 		menu = NULL;
2340 	    } else {
2341 		g_signal_connect(G_OBJECT(dataitem), "activate",
2342 				 G_CALLBACK(check_var_labels_state), mdata);
2343 	    }
2344 	}
2345     }
2346 
2347     g_free(main_ui);
2348 
2349     return menu;
2350 }
2351 
name_new_list(GtkWidget * widget,dialog_t * dlg)2352 static void name_new_list (GtkWidget *widget, dialog_t *dlg)
2353 {
2354     char *lname = (char *) edit_dialog_get_data(dlg);
2355     const gchar *buf = edit_dialog_get_text(dlg);
2356 
2357     if (buf == NULL || gui_validate_varname(buf, GRETL_TYPE_LIST, NULL)) {
2358 	return;
2359     }
2360 
2361     strncat(lname, buf, VNAMELEN - 1);
2362     edit_dialog_close(dlg);
2363 }
2364 
real_make_mainwin_list(const int * list,const char * lname)2365 static void real_make_mainwin_list (const int *list,
2366 				    const char *lname)
2367 {
2368     int err = remember_list(list, lname, NULL);
2369     char *lstr = NULL;
2370 
2371     if (err) {
2372 	gui_errmsg(err);
2373     } else {
2374 	lstr = gretl_list_to_string(list, dataset, &err);
2375     }
2376 
2377     if (lstr != NULL) {
2378 	/* record to command log */
2379 	lib_command_sprintf("list %s =%s", lname, lstr);
2380 	record_command_verbatim();
2381 	free(lstr);
2382     }
2383 }
2384 
2385 /* respond to "Define list", selected from main window
2386    right-click popup menu when two or more series are
2387    selected
2388 */
2389 
make_list_from_main(void)2390 void make_list_from_main (void)
2391 {
2392     int *list = main_window_selection_as_list();
2393 
2394     if (list != NULL) {
2395 	char lname[VNAMELEN];
2396 	int cancel = 0;
2397 	gchar *msg;
2398 
2399 	*lname = '\0';
2400 	msg = g_strdup_printf("%s\n (%s%s%s)",
2401 			      _("Enter name for list of series"),
2402 			      dataset->varname[list[1]],
2403 			      (list[0] == 2)? " " : " ... ",
2404 			      dataset->varname[list[list[0]]]);
2405 
2406 	blocking_edit_dialog(0, _("gretl: name list"), msg,
2407 			     NULL, name_new_list, lname,
2408 			     VARCLICK_NONE, mdata->main,
2409 			     &cancel);
2410 	g_free(msg);
2411 
2412 	if (!cancel && *lname != '\0') {
2413 	    real_make_mainwin_list(list, lname);
2414 	}
2415 
2416 	free(list);
2417     }
2418 }
2419 
gui_restore_sample(DATASET * dset)2420 int gui_restore_sample (DATASET *dset)
2421 {
2422     int err = 0;
2423 
2424     if (dset != NULL && dset->Z != NULL) {
2425 	err = restore_full_sample(dset, NULL);
2426 	if (err) {
2427 	    gui_errmsg(err);
2428 	} else {
2429 	    restore_sample_state(FALSE);
2430 	    mark_session_changed();
2431 	}
2432     }
2433 
2434     return err;
2435 }
2436 
restore_sample_callback(void)2437 static void restore_sample_callback (void)
2438 {
2439     int err = gui_restore_sample(dataset);
2440 
2441     if (!err) {
2442 	set_sample_label(dataset);
2443 	lib_command_strcpy("smpl --full");
2444 	record_command_verbatim();
2445     }
2446 }
2447 
show_sample_callback(void)2448 static void show_sample_callback (void)
2449 {
2450     char *buf;
2451     PRN *prn;
2452 
2453     if (bufopen(&prn)) {
2454 	return;
2455     }
2456 
2457     pprintf(prn, "%s\n\n", _("sample status"));
2458     print_sample_status(dataset, prn);
2459     buf = gretl_print_steal_buffer(prn);
2460     infobox(buf);
2461     free(buf);
2462     gretl_print_destroy(prn);
2463 }
2464 
start_R_callback(void)2465 static void start_R_callback (void)
2466 {
2467     start_R(NULL, 1, 1);
2468 }
2469 
2470 #ifndef G_OS_WIN32
2471 
gretl_fork(const char * progvar,const char * arg,const char * opt)2472 int gretl_fork (const char *progvar, const char *arg,
2473 		const char *opt)
2474 {
2475     const char *prog = NULL;
2476     gchar *argv[4] = {NULL, NULL, NULL, NULL};
2477     GError *err = NULL;
2478     gboolean run;
2479 
2480 #ifdef OS_OSX
2481     if (!strcmp(progvar, "calculator")) {
2482 	prog = calculator;
2483     }
2484 #else
2485     if (!strcmp(progvar, "Browser")) {
2486 	prog = Browser;
2487     } else if (!strcmp(progvar, "calculator")) {
2488 	prog = calculator;
2489     } else if (!strcmp(progvar, "viewpdf")) {
2490 	prog = viewpdf;
2491     } else if (!strcmp(progvar, "viewps")) {
2492 	prog = viewps;
2493     } else {
2494 	prog = progvar;
2495     }
2496 #endif
2497 
2498     if (prog == NULL) {
2499 	errbox_printf("Internal error: variable %s is undefined", progvar);
2500 	return 1;
2501     }
2502 
2503     argv[0] = g_strdup(prog);
2504 
2505     if (opt != NULL) {
2506 	argv[1] = g_strdup(arg);
2507 	argv[2] = g_strdup(opt);
2508     } else if (arg != NULL) {
2509 	argv[1] = g_strdup(arg);
2510     }
2511 
2512     run = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
2513 			NULL, NULL, NULL, &err);
2514 
2515     if (err != NULL) {
2516 	errbox(err->message);
2517 	if (err->domain == G_SPAWN_ERROR &&
2518 	    err->code == G_SPAWN_ERROR_NOENT) {
2519 	    preferences_dialog(TAB_PROGS, progvar, mdata->main);
2520 	}
2521 	g_error_free(err);
2522     }
2523 
2524     g_free(argv[0]);
2525     g_free(argv[1]);
2526     g_free(argv[2]);
2527 
2528     return !run;
2529 }
2530 
2531 #endif
2532 
2533 /* Icon handling for X11 */
2534 
2535 #ifndef G_OS_WIN32
2536 
set_wm_icon(GtkWidget * w)2537 void set_wm_icon (GtkWidget *w)
2538 {
2539     GdkPixbuf *icon = gdk_pixbuf_new_from_xpm_data(gretl_xpm);
2540 
2541 # ifdef MAC_INTEGRATION
2542     if (icon != NULL) {
2543 	gtkosx_application_set_dock_icon_pixbuf(MacApp, icon);
2544 	gtk_window_set_icon(GTK_WINDOW(w), icon);
2545 	g_object_unref(icon);
2546     }
2547 # else
2548     if (icon != NULL) {
2549 	gtk_window_set_icon(GTK_WINDOW(w), icon);
2550 	g_object_unref(icon);
2551     }
2552 # endif
2553 }
2554 
2555 #endif /* !G_OS_WIN32 */
2556 
has_db_suffix(const char * fname)2557 static int has_db_suffix (const char *fname)
2558 {
2559     return has_suffix(fname, ".bin") ||
2560 	has_suffix(fname, ".rat") ||
2561 	has_suffix(fname, ".bn7");
2562 }
2563 
2564 /* Drag 'n' drop: respond to data dropped into the main window */
2565 
2566 static void
mdata_handle_drag(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,gpointer p)2567 mdata_handle_drag  (GtkWidget *widget,
2568 		    GdkDragContext *context,
2569 		    gint x,
2570 		    gint y,
2571 		    GtkSelectionData *data,
2572 		    guint info,
2573 		    guint time,
2574 		    gpointer p)
2575 {
2576     const guchar *seldata = NULL;
2577     gchar *dfname;
2578     char tmp[MAXLEN];
2579     int pos, skip = 5;
2580 
2581     if (data != NULL) {
2582 	seldata = gtk_selection_data_get_data(data);
2583     }
2584 
2585     /* handle drag of pointer from database window */
2586     if (info == GRETL_DBSERIES_PTR && data != NULL) {
2587 	drag_import_db_series();
2588 	return;
2589     }
2590 
2591     if (info != GRETL_FILENAME) {
2592 	return;
2593     }
2594 
2595     /* ignore the wrong sort of data */
2596     if (data == NULL || (dfname = (gchar *) seldata) == NULL ||
2597 	strlen(dfname) <= 5 || strncmp(dfname, "file:", 5)) {
2598 	return;
2599     }
2600 
2601     if (strncmp(dfname, "file://", 7) == 0) skip = 7;
2602 #ifdef G_OS_WIN32
2603     if (strncmp(dfname, "file:///", 8) == 0) skip = 8;
2604 #endif
2605 
2606     /* there may be multiple files: we ignore all but the first */
2607     *tmp = 0;
2608     if ((pos = gretl_charpos('\r', dfname)) > 0 ||
2609 	(pos = gretl_charpos('\n', dfname) > 0)) {
2610 	strncat(tmp, dfname + skip, pos - skip);
2611     } else {
2612 	strcat(tmp, dfname + skip);
2613     }
2614 
2615     /* handle spaces and such then transcribe */
2616     unescape_url(tmp);
2617     set_tryfile(tmp);
2618 
2619     open_tryfile();
2620 }
2621 
open_tryfile(void)2622 gboolean open_tryfile (void)
2623 {
2624     gboolean ret = FALSE;
2625     int ftype = 0;
2626 
2627     if (has_db_suffix(tryfile)) {
2628 	ret = open_named_db_index(tryfile);
2629     } else if (has_suffix(tryfile, ".gretl") &&
2630 	       gretl_is_pkzip_file(tryfile)) {
2631 	ret = verify_open_session();
2632     } else if ((ftype = script_type(tryfile))) {
2633 	ret = do_open_script(ftype);
2634     } else if (has_suffix(tryfile, ".gfn") &&
2635 	       gretl_is_xml_file(tryfile)) {
2636 	ret = edit_specified_package(tryfile);
2637     } else {
2638 	ret = verify_open_data(NULL, 0);
2639     }
2640 
2641     return ret;
2642 }
2643 
2644 /* the callback for Save Data (Ctrl-S) in main window */
2645 
auto_store(void)2646 static void auto_store (void)
2647 {
2648     if (data_status & SESSION_DATA) {
2649 	/* the data file is embedded in a session file */
2650 	save_session_dataset();
2651     } else {
2652 	/* ensure there's no stale selection around */
2653 	set_selector_storelist(NULL);
2654 	if ((data_status & USER_DATA) && has_native_data_suffix(datafile)) {
2655 	    /* bypass filename selection */
2656 	    do_store(datafile, AUTO_SAVE_DATA, NULL);
2657 	} else {
2658 	    file_selector(SAVE_DATA, FSEL_DATA_NONE, NULL);
2659 	}
2660     }
2661 }
2662 
mdata_text_received(GtkClipboard * cb,const gchar * text,gpointer data)2663 static void mdata_text_received (GtkClipboard *cb,
2664 				 const gchar *text,
2665 				 gpointer data)
2666 {
2667     if (text != NULL) {
2668 	char fullname[FILENAME_MAX];
2669 	PRN *prn = NULL;
2670 	int append = 0;
2671 	int err, resp;
2672 
2673 	resp = paste_data_dialog(&append);
2674 	if (canceled(resp)) {
2675 	    return;
2676 	}
2677 
2678 	err = user_fopen(CLIPTEMP, fullname, &prn);
2679 
2680 	if (!err) {
2681 	    int ci = append ? APPEND_DATA : OPEN_DATA;
2682 
2683 	    pputs(prn, text);
2684 	    gretl_print_destroy(prn);
2685 	    set_tryfile(fullname);
2686 	    do_open_data(NULL, ci);
2687 	    gretl_remove(fullname);
2688 	}
2689     }
2690 }
2691 
mdata_handle_paste(void)2692 static void mdata_handle_paste (void)
2693 {
2694     static GtkClipboard *cb;
2695 
2696     if (cb == NULL) {
2697 	cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
2698     }
2699 
2700     gtk_clipboard_request_text(cb, mdata_text_received, NULL);
2701 }
2702 
mdata_selection_count(void)2703 int mdata_selection_count (void)
2704 {
2705     return vwin_selection_count(mdata, NULL);
2706 }
2707 
mdata_active_var(void)2708 int mdata_active_var (void)
2709 {
2710     int selcount, v = 0;
2711 
2712     selcount = vwin_selection_count(mdata, &v);
2713 
2714     if (selcount == 1 && v != 0) {
2715 	mdata->active_var = v;
2716     } else {
2717 	mdata->active_var = 0;
2718     }
2719 
2720     return mdata->active_var;
2721 }
2722 
2723 static gboolean
main_popup_handler(GtkWidget * w,GdkEventButton * event,gpointer data)2724 main_popup_handler (GtkWidget *w, GdkEventButton *event, gpointer data)
2725 {
2726     if (right_click(event)) {
2727 	/* ignore all but right-clicks */
2728 	int selvar = 0;
2729 	int selcount = vwin_selection_count(mdata, &selvar);
2730 
2731 	if (mdata->popup) {
2732 	    gtk_widget_destroy(mdata->popup);
2733 	    mdata->popup = NULL;
2734 	}
2735 
2736 	if (selcount == 1) {
2737 	    mdata->popup = build_var_popup(selvar);
2738 	} else if (selcount > 1) {
2739 	    mdata->popup = build_selection_popup();
2740 	}
2741 
2742 	if (mdata->popup != NULL) {
2743 	    gtk_menu_popup(GTK_MENU(mdata->popup), NULL, NULL, NULL, NULL,
2744 			   event->button, event->time);
2745 	    g_signal_connect(G_OBJECT(mdata->popup), "destroy",
2746 			     G_CALLBACK(gtk_widget_destroyed),
2747 			     &mdata->popup);
2748 	}
2749 
2750 	return TRUE;
2751     }
2752 
2753     return FALSE;
2754 }
2755 
script_stopper(int set)2756 static int script_stopper (int set)
2757 {
2758     static int stop;
2759     int ret = 0;
2760 
2761     if (set) {
2762 	/* set the stop signal */
2763 	stop = 1;
2764     } else if (stop) {
2765 	ret = 1;
2766 	stop = 0;
2767     }
2768 
2769     return ret;
2770 }
2771 
gui_query_stop(void)2772 static int gui_query_stop (void)
2773 {
2774     return script_stopper(0);
2775 }
2776 
2777 /* callback from "stop" button in script output viewer */
2778 
do_stop_script(GtkWidget * w,windata_t * vwin)2779 void do_stop_script (GtkWidget *w, windata_t *vwin)
2780 {
2781     script_stopper(1);
2782 }
2783