1 /*
2 * gretl -- Gnu Regression, Econometrics and Time-series Library
3 * Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "gretl.h"
21 #include "var.h"
22 #include "dlgutils.h"
23 #include "guiprint.h"
24 #include "session.h"
25 #include "tabwin.h"
26 #include "fnsave.h"
27 #include "toolbar.h"
28 #include "cmdstack.h"
29 #include "winstack.h"
30 #include "gretl_ipc.h"
31
32 #include "uservar.h"
33
34 #define WDEBUG 0
35
36 enum {
37 WINDOW_NEXT,
38 WINDOW_PREV
39 };
40
41 static gint select_other_window (gpointer self, int seq);
42
43 /* Below: apparatus for keeping track of open gretl windows.
44
45 This provides the basis for a pop-up listing of windows as
46 a means of navigating the multi-window gretl GUI; it also
47 gives the basis for checking whether a window performing
48 a given role is already open, so as to avoid duplication,
49 and for closing any windows that are "invalidated" when
50 the gretl session is switched (e.g. by opening a new
51 data file).
52 */
53
54 /* get the top-level widget associated with pre-defined
55 @action
56 */
57
window_from_action(GtkAction * action)58 static GtkWidget *window_from_action (GtkAction *action)
59 {
60 GtkWidget *w;
61
62 w = g_object_get_data(G_OBJECT(action), "target");
63
64 if (w != NULL && !GTK_IS_WIDGET(w)) {
65 /* shouldn't happen, but... */
66 w = NULL;
67 }
68
69 return w;
70 }
71
vwin_from_action(GtkAction * action)72 static windata_t *vwin_from_action (GtkAction *action)
73 {
74 GtkWidget *w = window_from_action(action);
75
76 if (w != NULL) {
77 return g_object_get_data(G_OBJECT(w), "vwin");
78 }
79
80 return NULL;
81 }
82
83 /* callback to bring a selected window to the top */
84
gretl_window_raise(GtkAction * action,gpointer data)85 static void gretl_window_raise (GtkAction *action, gpointer data)
86 {
87 GtkWidget *w = window_from_action(action);
88
89 if (w != NULL && GTK_IS_WINDOW(w)) {
90 gtk_window_present(GTK_WINDOW(w));
91 }
92 }
93
94 /* select an icon to represent a window playing
95 the given @role in the gretl GUI */
96
window_list_icon(int role)97 static const gchar *window_list_icon (int role)
98 {
99 const gchar *id = NULL;
100
101 if (role == MAINWIN) {
102 id = GRETL_STOCK_GRETL;
103 } else if (role == VIEW_MODEL || role == VAR ||
104 role == VECM || role == SYSTEM) {
105 id = GRETL_STOCK_MODEL;
106 } else if (role == CONSOLE) {
107 id = GRETL_STOCK_CONSOLE;
108 } else if (role >= EDIT_HEADER &&
109 role < EDIT_MAX) {
110 id = GTK_STOCK_EDIT;
111 } else if (role == GNUPLOT) {
112 id = GRETL_STOCK_SCATTER;
113 } else if (role == PKG_REGISTRY) {
114 id = GTK_STOCK_PREFERENCES;
115 } else if (role == DBNOMICS_TOP ||
116 role == DBNOMICS_DB ||
117 role == DBNOMICS_SERIES ||
118 role == VIEW_DBSEARCH) {
119 id = GRETL_STOCK_DBN;
120 } else if (BROWSER_ROLE(role)) {
121 id = GTK_STOCK_INDEX;
122 } else if (help_role(role)) {
123 id = GRETL_STOCK_BOOK;
124 } else if (role == STAT_TABLE) {
125 id = GRETL_STOCK_CALC;
126 } else if (role == VIEW_SCRIPT ||
127 role == VIEW_PKG_SAMPLE) {
128 id = GTK_STOCK_EXECUTE;
129 } else if (role == OPEN_SESSION) {
130 id = GRETL_STOCK_ICONS;
131 } else if (role == PRINT ||
132 role == SCRIPT_OUT ||
133 role == VIEW_LOG) {
134 id = GRETL_STOCK_PAGE;
135 } else if (role == SSHEET) {
136 id = GRETL_STOCK_TABLE;
137 } else if (role == SAVE_FUNCTIONS) {
138 id = GRETL_STOCK_TOOLS;
139 } else if (role == VIEW_DBNOMICS || role == VIEW_BUNDLE) {
140 id = GRETL_STOCK_BUNDLE;
141 }
142
143 return id;
144 }
145
146 static int n_listed_windows;
147 static GtkActionGroup *window_group;
148
get_window_title(GtkWidget * w)149 static const gchar *get_window_title (GtkWidget *w)
150 {
151 const gchar *s = NULL;
152
153 if (GTK_IS_WINDOW(w)) {
154 s = gtk_window_get_title(GTK_WINDOW(w));
155
156 if (s != NULL && !strncmp(s, "gretl", 5)) {
157 s += 5;
158 s += strspn(s, " ");
159 if (*s == ':') {
160 s++;
161 s += strspn(s, " ");
162 }
163 }
164 }
165
166 return s;
167 }
168
window_label(GtkWidget * w,int role)169 static const char *window_label (GtkWidget *w, int role)
170 {
171 if (role == MAINWIN) {
172 #ifdef GRETL_PID_FILE
173 static char label[32];
174 int seqno = gretl_sequence_number();
175 gchar *tmp;
176
177 if (seqno > 1) {
178 strcpy(label, _("Main window"));
179 tmp = g_strdup_printf(" (%d)", seqno);
180 strcat(label, tmp);
181 g_free(tmp);
182 return label;
183 }
184 #endif
185 return _("Main window");
186 } else {
187 return get_window_title(w);
188 }
189 }
190
plot_window_set_label(GtkWidget * w)191 void plot_window_set_label (GtkWidget *w)
192 {
193 gchar *aname = g_strdup_printf("%p", (void *) w);
194 GtkAction *action;
195
196 action = gtk_action_group_get_action(window_group, aname);
197 if (action != NULL) {
198 gtk_action_set_label(action, window_label(w, GNUPLOT));
199 }
200 g_free(aname);
201 }
202
203 /* callback to be invoked just before destroying a window that's
204 on the list of open windows: remove its entry from the list
205 */
206
window_list_remove(GtkWidget * w,GtkActionGroup * group)207 static void window_list_remove (GtkWidget *w, GtkActionGroup *group)
208 {
209 GtkAction *action;
210 gchar *aname = g_strdup_printf("%p", (void *) w);
211
212 #if WDEBUG
213 fprintf(stderr, "window_list_remove: %s (%s)\n", aname,
214 window_label(w, 0));
215 #endif
216
217 action = gtk_action_group_get_action(group, aname);
218 if (action != NULL) {
219 gtk_action_group_remove_action(group, action);
220 n_listed_windows--;
221 }
222 g_free(aname);
223 }
224
225 /* callback for command-accent on Mac or Alt-PgUp/PgDn on
226 X11 and Windows: switch window-focus within gretl
227 */
228
maybe_select_other_window(GdkEventKey * event,gpointer data)229 static gint maybe_select_other_window (GdkEventKey *event,
230 gpointer data)
231 {
232 #ifdef OS_OSX
233 if (cmd_key(event)) {
234 if (event->keyval == GDK_asciitilde) {
235 return select_other_window(data, WINDOW_PREV);
236 } else if (event->keyval == GDK_grave) {
237 return select_other_window(data, WINDOW_NEXT);
238 }
239 }
240 #else
241 if (event->state & GDK_MOD1_MASK) {
242 if (event->keyval == GDK_Page_Up ||
243 event->keyval == GDK_KP_Page_Up) {
244 return select_other_window(data, WINDOW_PREV);
245 } else if (event->keyval == GDK_Page_Down ||
246 event->keyval == GDK_KP_Page_Down) {
247 return select_other_window(data, WINDOW_NEXT);
248 }
249 }
250 #endif
251
252 return FALSE;
253 }
254
catch_winlist_key(GtkWidget * w,GdkEventKey * event,gpointer data)255 static gint catch_winlist_key (GtkWidget *w, GdkEventKey *event,
256 gpointer data)
257 {
258 #ifdef OS_OSX
259 if ((event->state & GDK_MOD1_MASK) && event->keyval == alt_w_key) {
260 /* alt-w -> Sigma */
261 window_list_popup(w, (GdkEvent *) event, data);
262 return TRUE;
263 }
264 #else /* non-Mac */
265 if (event->state & GDK_MOD1_MASK) {
266 if (event->keyval == GDK_w) {
267 window_list_popup(w, (GdkEvent *) event, data);
268 return TRUE;
269 }
270 }
271 #endif
272
273 return maybe_select_other_window(event, data);
274 }
275
window_list_add(GtkWidget * w,int role)276 void window_list_add (GtkWidget *w, int role)
277 {
278 GtkActionEntry entry = {
279 /* name, stock_id, label, accelerator, tooltip, callback */
280 NULL, NULL, NULL, NULL, NULL, G_CALLBACK(gretl_window_raise)
281 };
282 GtkAction *action;
283 const char *label;
284 gchar *modlabel = NULL;
285 gchar *aname = NULL;
286
287 label = window_label(w, role);
288 if (label == NULL) {
289 return;
290 } else if (strchr(label, '_') != NULL) {
291 modlabel = double_underscores_new(label);
292 }
293
294 #if WDEBUG
295 fprintf(stderr, "window_list_add: %p (%s)\n", (void *) w, label);
296 #endif
297
298 if (window_group == NULL) {
299 /* create the window list action group */
300 window_group = gtk_action_group_new("WindowList");
301 }
302
303 /* set up an action entry for window @w */
304 entry.name = aname = g_strdup_printf("%p", (void *) w);
305 entry.stock_id = window_list_icon(role);
306 entry.label = (modlabel != NULL)? modlabel : label,
307
308 /* add new action entry to group */
309 gtk_action_group_add_actions(window_group, &entry, 1, NULL);
310
311 /* grab the added action and stick @w onto it as data */
312 action = gtk_action_group_get_action(window_group, aname);
313 g_object_set_data(G_OBJECT(action), "target", w);
314
315 if (role != MAINWIN) {
316 /* attach time to window */
317 g_object_set_data(G_OBJECT(w), "time", GUINT_TO_POINTER(time(NULL)));
318 /* attach callback to remove from window list */
319 g_signal_connect(G_OBJECT(w), "destroy",
320 G_CALLBACK(window_list_remove),
321 window_group);
322 }
323
324 if (role != EDIT_HANSL) {
325 /* allow for Alt-w = omega */
326 g_signal_connect(G_OBJECT(w), "key-press-event",
327 G_CALLBACK(catch_winlist_key), w);
328 }
329
330 n_listed_windows++;
331
332 g_free(aname);
333 g_free(modlabel);
334 }
335
336 /* GCompareFunc: returns "a negative integer if the first value comes
337 before the second, 0 if they are equal, or a positive integer if
338 the first value comes after the second."
339 */
340
sort_window_list(gconstpointer a,gconstpointer b)341 static gint sort_window_list (gconstpointer a, gconstpointer b)
342 {
343 GtkWidget *wa = window_from_action((GtkAction *) a);
344 GtkWidget *wb = window_from_action((GtkAction *) b);
345 guint ta, tb;
346
347 /* sort main window first, otherwise by time when the
348 window was created */
349
350 if (wa == mdata->main) return -1;
351 if (wb == mdata->main) return 1;
352
353 /* bullet-proofing */
354 if (wa == NULL || wb == NULL) {
355 return 0;
356 }
357
358 ta = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(wa), "time"));
359 tb = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(wb), "time"));
360
361 return ta - tb;
362 }
363
364 /* use real UTF-8 bullet character if possible, otherwise asterisk */
365
make_bullet(char * bullet)366 static void make_bullet (char *bullet)
367 {
368 GtkSettings *settings = gtk_settings_get_default();
369 gchar *fontname = NULL;
370
371 g_object_get(G_OBJECT(settings), "gtk-font-name", &fontname, NULL);
372
373 if (fontname != NULL) {
374 PangoFontDescription *desc;
375
376 desc = pango_font_description_from_string(fontname);
377 if (font_has_symbol(desc, 0x2022)) {
378 sprintf(bullet, " %c%c%c", 0xE2, 0x80, 0xA2);
379 }
380 if (desc != NULL) {
381 pango_font_description_free(desc);
382 }
383 }
384
385 if (*bullet == '\0') {
386 strcpy(bullet, " *");
387 }
388 }
389
390 /* show a bullet or asterisk next to the entry for
391 the current window */
392
maybe_revise_action_label(GtkAction * action,GtkWidget * test)393 static void maybe_revise_action_label (GtkAction *action,
394 GtkWidget *test)
395 {
396 static char bullet[5];
397 static int blen;
398 const gchar *label = gtk_action_get_label(action);
399 gchar *repl = NULL;
400 int n = strlen(label);
401 int marked = 0;
402
403 if (*bullet == '\0') {
404 make_bullet(bullet);
405 blen = strlen(bullet);
406 }
407
408 if (n > blen && !strcmp(label + n - blen, bullet)) {
409 marked = 1;
410 }
411
412 if (test == window_from_action(action)) {
413 if (!marked) {
414 /* add asterisk */
415 repl = g_strdup_printf("%s %s", label, bullet);
416 }
417 } else if (marked) {
418 /* remove asterisk */
419 repl = g_strndup(label, strlen(label) - blen);
420 }
421
422 if (repl != NULL) {
423 gtk_action_set_label(action, repl);
424 g_free(repl);
425 }
426 }
427
window_list_revise_label(GtkWidget * targ,const char * label)428 void window_list_revise_label (GtkWidget *targ,
429 const char *label)
430 {
431 GList *wlist = gtk_action_group_list_actions(window_group);
432 GList *list = wlist;
433 GtkAction *action;
434
435 while (list != NULL) {
436 action = (GtkAction *) list->data;
437 if (targ == window_from_action(action)) {
438 gtk_action_set_label(action, label);
439 break;
440 }
441 list = list->next;
442 }
443
444 g_list_free(wlist);
445 }
446
winlist_popup_done(GtkMenuShell * mshell,GtkWidget * window)447 static gboolean winlist_popup_done (GtkMenuShell *mshell,
448 GtkWidget *window)
449 {
450 windata_t *vwin = window_get_active_vwin(window);
451
452 if (vwin != NULL) {
453 /* don't leave focus on the winlist button */
454 if (vwin->role == VIEW_MODEL ||
455 vwin->role == VAR ||
456 vwin->role == VECM) {
457 gtk_widget_grab_focus(vwin->text);
458 } else if (vwin == mdata) {
459 gtk_widget_grab_focus(vwin->listbox);
460 }
461 }
462
463 return FALSE;
464 }
465
add_cascade_item(GtkWidget * menu,GtkWidget * item)466 static void add_cascade_item (GtkWidget *menu,
467 GtkWidget *item)
468 {
469 GtkWidget *image;
470
471 item = gtk_image_menu_item_new_with_label(_("Arrange"));
472 image = gtk_image_new_from_stock(GRETL_STOCK_WINLIST,
473 GTK_ICON_SIZE_MENU);
474 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
475 image);
476 g_signal_connect(G_OBJECT(item), "activate",
477 G_CALLBACK(cascade_session_windows),
478 NULL);
479 gtk_widget_show(item);
480 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
481 }
482
add_log_item(GtkWidget * menu,GtkWidget * item)483 static void add_log_item (GtkWidget *menu,
484 GtkWidget *item)
485 {
486 GtkWidget *image;
487
488 item = gtk_image_menu_item_new_with_label(_("command log"));
489 image = gtk_image_new_from_stock(GRETL_STOCK_PAGE,
490 GTK_ICON_SIZE_MENU);
491 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
492 image);
493 g_signal_connect(G_OBJECT(item), "activate",
494 G_CALLBACK(view_command_log),
495 NULL);
496 gtk_widget_show(item);
497 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
498 }
499
add_iconview_item(GtkWidget * menu,GtkWidget * item)500 static void add_iconview_item (GtkWidget *menu,
501 GtkWidget *item)
502 {
503 GtkWidget *image;
504
505 item = gtk_image_menu_item_new_with_label(_("icon view"));
506 image = gtk_image_new_from_stock(GRETL_STOCK_ICONS,
507 GTK_ICON_SIZE_MENU);
508 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
509 image);
510 g_signal_connect(G_OBJECT(item), "activate",
511 G_CALLBACK(view_session),
512 NULL);
513 gtk_widget_show(item);
514 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
515 }
516
517 /* pop up a list of open windows from which the user can
518 select one to raise and focus */
519
window_list_popup(GtkWidget * src,GdkEvent * event,gpointer data)520 void window_list_popup (GtkWidget *src, GdkEvent *event,
521 gpointer data)
522 {
523 static GtkWidget *menu;
524 GdkEventType evtype;
525 GList *wlist = gtk_action_group_list_actions(window_group);
526 GList *list;
527 GtkWidget *item, *lwin;
528 GtkWidget *thiswin = NULL;
529 GtkAction *action;
530 int log_up = 0;
531 int icons_up = 0;
532
533 if (menu != NULL) {
534 /* we need to make sure this is up to date */
535 gtk_widget_destroy(menu);
536 menu = NULL;
537 }
538
539 if (n_listed_windows > 1) {
540 wlist = g_list_sort(wlist, sort_window_list);
541 }
542
543 if (data != NULL) {
544 thiswin = GTK_WIDGET(data);
545 }
546
547 menu = gtk_menu_new();
548 list = g_list_first(wlist);
549
550 while (list != NULL) {
551 action = (GtkAction *) list->data;
552 lwin = window_from_action(action);
553 if (is_command_log_viewer(lwin)) {
554 log_up = 1;
555 } else if (widget_is_iconview(lwin)) {
556 icons_up = 1;
557 }
558 if (n_listed_windows > 1 && thiswin != NULL) {
559 maybe_revise_action_label(action, thiswin);
560 }
561 gtk_action_set_accel_path(action, NULL);
562 item = gtk_action_create_menu_item(action);
563 gtk_widget_show(item);
564 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
565 list = list->next;
566 }
567 g_list_free(wlist);
568
569 if (n_listed_windows > 1) {
570 add_cascade_item(menu, item);
571 }
572
573 if (!log_up || !icons_up) {
574 item = gtk_separator_menu_item_new();
575 gtk_widget_show(item);
576 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
577 if (!log_up) {
578 add_log_item(menu, item);
579 }
580 if (!icons_up) {
581 add_iconview_item(menu, item);
582 }
583 }
584
585 if (thiswin != NULL) {
586 g_signal_connect(G_OBJECT(menu), "deactivate",
587 G_CALLBACK(winlist_popup_done),
588 thiswin);
589 }
590
591 evtype = event != NULL ? event->type : 0;
592
593 if (evtype == GDK_BUTTON_PRESS) {
594 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
595 event->button.button, event->button.time);
596 } else if (evtype == GDK_KEY_PRESS) {
597 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
598 0, event->key.time);
599 } else {
600 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
601 0, gtk_get_current_event_time());
602 }
603 }
604
vwin_winlist_popup(GtkWidget * src,GdkEvent * event,windata_t * vwin)605 static void vwin_winlist_popup (GtkWidget *src,
606 GdkEvent *event,
607 windata_t *vwin)
608 {
609 /* Note: this function may look redundant, given the
610 window_list_popup() function, but it's not. This is
611 due to the presence of tabbed windows whose content
612 (scripts, models) can be dragged out of their
613 tabbed context: in that case @vwin's associated
614 "toplevel" can change between invocations of
615 this function and therefore cannot be "hard-wired"
616 into the callback setup, rather it must be
617 evaluated on each invocation.
618 */
619 window_list_popup(src, event, vwin_toplevel(vwin));
620 }
621
window_is_package_editor(GtkWidget * w)622 static int window_is_package_editor (GtkWidget *w)
623 {
624 if (w != NULL) {
625 const gchar *wname = gtk_widget_get_name(w);
626
627 if (wname != NULL && strcmp(wname, "pkg-editor") == 0) {
628 return 1;
629 }
630 }
631
632 return 0;
633 }
634
635 /* On exiting, check for any editing windows with unsaved
636 changes: if we find any, give the user a chance to
637 save the changes or cancel the exit.
638 */
639
window_list_exit_check(void)640 gboolean window_list_exit_check (void)
641 {
642 gboolean ret = FALSE;
643
644 if (n_listed_windows > 1) {
645 GList *wlist = gtk_action_group_list_actions(window_group);
646 GList *list = wlist;
647 windata_t *vwin;
648 GtkWidget *w;
649
650 while (list != NULL) {
651 w = window_from_action((GtkAction *) list->data);
652 if (w != NULL) {
653 vwin = g_object_get_data(G_OBJECT(w), "vwin");
654 if (vwin != NULL) {
655 if (vwin_is_editing(vwin) && vwin_content_changed(vwin)) {
656 gtk_window_present(GTK_WINDOW(vwin->main));
657 ret = query_save_text(NULL, NULL, vwin);
658 }
659 } else {
660 /* vwin is NULL */
661 if (g_object_get_data(G_OBJECT(w), "tabwin")) {
662 ret = tabwin_exit_check(w);
663 } else if (window_is_package_editor(w)) {
664 ret = package_editor_exit_check(w);
665 }
666 }
667 }
668 list = list->next;
669 }
670 g_list_free(wlist);
671 }
672
673 return ret;
674 }
675
676 /* windows that should _not_ be automatically closed when
677 closing the current gretl session (e.g. on opening a
678 new data file)
679 */
680
681 #define other_dont_close(r) (r == SCRIPT_OUT || \
682 r == EDIT_PKG_CODE || \
683 r == EDIT_PKG_SAMPLE || \
684 r == VIEW_LOG || \
685 r == VIEW_SCRIPT || \
686 r == VIEW_PKG_SAMPLE || \
687 r == TEXTBOOK_DATA || \
688 r == PS_FILES || \
689 r == NATIVE_DB || \
690 r == REMOTE_DB || \
691 r == NATIVE_SERIES || \
692 r == REMOTE_SERIES || \
693 r == FUNC_FILES || \
694 r == REMOTE_FUNC_FILES || \
695 r == PKG_REGISTRY || \
696 r == CONSOLE)
697
698
keep_window_open(GtkWidget * w,gretlopt opt)699 static int keep_window_open (GtkWidget *w, gretlopt opt)
700 {
701 return window_is_package_editor(w);
702
703 /* FIXME maybe keep plot windows open if opt & OPT_P? */
704 }
705
706 /* called from session.c on switching the session: close all
707 windows that ought to be closed, but be careful not to
708 close ones that need to stay open!
709 */
710
close_session_windows(gretlopt opt)711 void close_session_windows (gretlopt opt)
712 {
713 if (n_listed_windows > 1) {
714 GList *wlist = gtk_action_group_list_actions(window_group);
715 GList *list = wlist;
716 windata_t *vwin;
717 GtkWidget *w;
718
719 while (list) {
720 w = window_from_action((GtkAction *) list->data);
721 if (w != NULL) {
722 vwin = g_object_get_data(G_OBJECT(w), "vwin");
723 if (vwin == mdata) {
724 ; /* main window: no-op! */
725 } else if (vwin != NULL && (vwin_editing_script(vwin->role) ||
726 help_role(vwin->role) ||
727 other_dont_close(vwin->role))) {
728 ; /* no-op */
729 } else if (vwin == NULL && g_object_get_data(G_OBJECT(w), "tabwin")) {
730 /* tabbed script editor stays open, but tabbed model
731 viewer should be closed */
732 tabwin_close_models_viewer(w);
733 } else if (w != NULL && !keep_window_open(w, opt)) {
734 gtk_widget_destroy(w);
735 }
736 }
737 list = list->next;
738 }
739 g_list_free(wlist);
740 }
741 }
742
cascade_session_windows(void)743 void cascade_session_windows (void)
744 {
745 if (n_listed_windows > 1) {
746 GList *wlist = gtk_action_group_list_actions(window_group);
747 GList *list;
748 GtkWidget *w;
749 gint x = 50, y = 50;
750 gint d = 30;
751
752 wlist = g_list_sort(wlist, sort_window_list);
753 list = g_list_first(wlist);
754
755 while (list != NULL) {
756 w = window_from_action((GtkAction *) list->data);
757 if (w != NULL) {
758 gtk_window_move(GTK_WINDOW(w), x, y);
759 gtk_window_present(GTK_WINDOW(w));
760 x += d;
761 y += d;
762 }
763 list = list->next;
764 }
765 g_list_free(wlist);
766 }
767 }
768
select_other_window(gpointer self,int seq)769 static gint select_other_window (gpointer self, int seq)
770 {
771 if (n_listed_windows > 1) {
772 GList *wlist = gtk_action_group_list_actions(window_group);
773 GList *list;
774 GtkWidget *w;
775
776 wlist = g_list_sort(wlist, sort_window_list);
777 list = g_list_first(wlist);
778
779 /* find the window from which the keystroke emanated, @self,
780 and then select the next or previous window in the list,
781 wrapping around at the ends */
782
783 while (list != NULL) {
784 w = window_from_action((GtkAction *) list->data);
785 if (w == (GtkWidget *) self) {
786 if (seq == WINDOW_PREV) {
787 list = list->prev != NULL ? list->prev :
788 g_list_last(wlist);
789 } else {
790 list = list->next != NULL ? list->next :
791 g_list_first(wlist);
792 }
793 gretl_window_raise((GtkAction *) list->data, NULL);
794 break;
795 }
796 list = list->next;
797 }
798 g_list_free(wlist);
799 return TRUE;
800 }
801
802 return FALSE;
803 }
804
get_editor_for_file(const char * filename)805 windata_t *get_editor_for_file (const char *filename)
806 {
807 windata_t *ret = NULL;
808
809 if (n_listed_windows > 1) {
810 GList *wlist = gtk_action_group_list_actions(window_group);
811 GList *list = wlist;
812 windata_t *vwin;
813 GtkWidget *w;
814
815 while (list != NULL && ret == NULL) {
816 w = window_from_action((GtkAction *) list->data);
817 if (w != NULL) {
818 vwin = g_object_get_data(G_OBJECT(w), "vwin");
819 if (vwin != NULL && vwin_is_editing(vwin)) {
820 if (!strcmp(filename, vwin->fname)) {
821 ret = vwin;
822 }
823 }
824 if (vwin == NULL && g_object_get_data(G_OBJECT(w), "tabwin")) {
825 ret = tabwin_get_editor_for_file(filename, w);
826 }
827 }
828 list = list->next;
829 }
830 g_list_free(wlist);
831 }
832
833 return ret;
834 }
835
get_viewer_for_plot(const char * filename)836 GtkWidget *get_viewer_for_plot (const char *filename)
837 {
838 GtkWidget *ret = NULL;
839
840 if (n_listed_windows > 1) {
841 GList *wlist = gtk_action_group_list_actions(window_group);
842 GList *list = wlist;
843 GtkWidget *w;
844
845 while (list != NULL && ret == NULL) {
846 w = window_from_action((GtkAction *) list->data);
847 if (is_shell_for_plotfile(w, filename)) {
848 ret = w;
849 }
850 list = list->next;
851 }
852 g_list_free(wlist);
853 }
854
855 return ret;
856 }
857
db_role_matches(windata_t * vwin,int code)858 static int db_role_matches (windata_t *vwin, int code)
859 {
860 int ret = 0;
861
862 if (code == NATIVE_SERIES) {
863 ret = vwin->role == code;
864 } else {
865 ret = (vwin->role == NATIVE_SERIES ||
866 vwin->role == RATS_SERIES ||
867 vwin->role == PCGIVE_SERIES ||
868 vwin->role == REMOTE_SERIES);
869 }
870
871 if (ret) {
872 ret = *vwin->fname != '\0';
873 }
874
875 return ret;
876 }
877
878 static windata_t *
real_get_browser_for_database(const char * filename,int code)879 real_get_browser_for_database (const char *filename, int code)
880 {
881 windata_t *ret = NULL;
882
883 if (n_listed_windows > 1) {
884 GList *wlist = gtk_action_group_list_actions(window_group);
885 GList *list = wlist;
886 windata_t *vwin;
887
888 while (list != NULL && ret == NULL) {
889 vwin = vwin_from_action((GtkAction *) list->data);
890 if (vwin != NULL && db_role_matches(vwin, code)) {
891 if (!strncmp(filename, vwin->fname,
892 strlen(vwin->fname))) {
893 ret = vwin;
894 }
895 }
896 list = list->next;
897 }
898 g_list_free(wlist);
899 }
900
901 return ret;
902 }
903
get_browser_for_database(const char * filename)904 windata_t *get_browser_for_database (const char *filename)
905 {
906 return real_get_browser_for_database(filename, 0);
907 }
908
get_browser_for_gretl_database(const char * filename)909 windata_t *get_browser_for_gretl_database (const char *filename)
910 {
911 return real_get_browser_for_database(filename, NATIVE_SERIES);
912 }
913
get_viewer_for_data(const gpointer data)914 windata_t *get_viewer_for_data (const gpointer data)
915 {
916 windata_t *ret = NULL;
917
918 if (n_listed_windows > 1) {
919 GList *wlist = gtk_action_group_list_actions(window_group);
920 GList *list = wlist;
921 windata_t *vwin;
922 GtkWidget *w;
923
924 while (list != NULL && ret == NULL) {
925 w = window_from_action((GtkAction *) list->data);
926 if (w != NULL) {
927 vwin = g_object_get_data(G_OBJECT(w), "vwin");
928 if (vwin != NULL) {
929 if (vwin->data == data) {
930 ret = vwin;
931 }
932 } else if (g_object_get_data(G_OBJECT(w), "tabwin")) {
933 ret = get_tab_for_data(data, w);
934 }
935 }
936 list = list->next;
937 }
938 g_list_free(wlist);
939 }
940
941 return ret;
942 }
943
paths_match(const char * path,windata_t * vwin)944 static int paths_match (const char *path, windata_t *vwin)
945 {
946 const char *wstr = NULL;
947
948 if (vwin->role == DBNOMICS_DB) {
949 wstr = g_object_get_data(G_OBJECT(vwin->listbox), "provider");
950 } else {
951 wstr = g_object_get_data(G_OBJECT(vwin->listbox), "path");
952 }
953
954 return wstr != NULL && !strcmp(path, wstr);
955 }
956
get_browser_for_role(int role,const char * path)957 windata_t *get_browser_for_role (int role, const char *path)
958 {
959 windata_t *ret = NULL;
960
961 if (n_listed_windows > 1) {
962 GList *wlist = gtk_action_group_list_actions(window_group);
963 GList *list = wlist;
964 int checkpath = 0;
965 windata_t *vwin;
966
967 if (path != NULL && (role == DBNOMICS_DB || role == DBNOMICS_SERIES)) {
968 checkpath = 1;
969 }
970 while (list != NULL && ret == NULL) {
971 vwin = vwin_from_action((GtkAction *) list->data);
972 if (vwin != NULL && vwin->role == role) {
973 if (checkpath) {
974 /* "path" should match */
975 ret = paths_match(path, vwin) ? vwin : NULL;
976 } else {
977 /* it's sufficient to match on role */
978 ret = vwin;
979 }
980 }
981 list = list->next;
982 }
983 g_list_free(wlist);
984 }
985
986 return ret;
987 }
988
get_script_output_number(void)989 int get_script_output_number (void)
990 {
991 int ret = 0;
992
993 if (n_listed_windows > 1) {
994 GList *wlist = gtk_action_group_list_actions(window_group);
995 GList *list = wlist;
996 windata_t *vwin;
997
998 while (list != NULL) {
999 vwin = vwin_from_action((GtkAction *) list->data);
1000 if (vwin != NULL && vwin->role == SCRIPT_OUT) {
1001 ret++;
1002 }
1003 list = list->next;
1004 }
1005 g_list_free(wlist);
1006 }
1007
1008 return ret;
1009 }
1010
get_unique_output_viewer(void)1011 windata_t *get_unique_output_viewer (void)
1012 {
1013 windata_t *ret = NULL;
1014 int vcount = 0;
1015
1016 if (n_listed_windows > 1) {
1017 GList *wlist = gtk_action_group_list_actions(window_group);
1018 GList *list = wlist;
1019 windata_t *vwin;
1020
1021 while (list != NULL) {
1022 vwin = vwin_from_action((GtkAction *) list->data);
1023 if (vwin != NULL && vwin->role == SCRIPT_OUT) {
1024 vcount++;
1025 if (vcount == 1) {
1026 ret = vwin;
1027 } else {
1028 ret = NULL;
1029 break;
1030 }
1031 }
1032 list = list->next;
1033 }
1034 g_list_free(wlist);
1035 }
1036
1037 return ret;
1038 }
1039
get_window_for_data(const gpointer data)1040 GtkWidget *get_window_for_data (const gpointer data)
1041 {
1042 GtkWidget *ret = NULL;
1043
1044 /* this handles the case where the window in question
1045 is not part of a windata_t "viewer": e.g. a
1046 spreadsheet window editing a matrix
1047 */
1048
1049 if (n_listed_windows > 1) {
1050 GList *wlist = gtk_action_group_list_actions(window_group);
1051 GList *list = wlist;
1052 GtkWidget *w;
1053 gpointer p;
1054
1055 while (list != NULL && ret == NULL) {
1056 w = window_from_action((GtkAction *) list->data);
1057 if (w != NULL) {
1058 p = g_object_get_data(G_OBJECT(w), "object");
1059 if (p == data) {
1060 ret = w;
1061 }
1062 }
1063 list = list->next;
1064 }
1065 g_list_free(wlist);
1066 }
1067
1068 return ret;
1069 }
1070
maybe_close_window_for_user_var(const gpointer data,GretlObjType otype)1071 void maybe_close_window_for_user_var (const gpointer data,
1072 GretlObjType otype)
1073 {
1074 if (otype == GRETL_OBJ_BUNDLE) {
1075 void *ptr = user_var_get_value((user_var *) data);
1076 windata_t *vwin = get_viewer_for_data(ptr);
1077
1078 if (vwin != NULL) {
1079 vwin->data = NULL; /* don't double-free */
1080 gtk_widget_destroy(vwin->main);
1081 }
1082 } else {
1083 GtkWidget *w = get_window_for_data(data);
1084
1085 if (w != NULL) {
1086 if (otype == GRETL_OBJ_MATRIX) {
1087 /* don't double-free */
1088 g_object_set_data(G_OBJECT(w), "object", NULL);
1089 }
1090 gtk_widget_destroy(w);
1091 }
1092 }
1093 }
1094
get_window_for_plot(void * session_plot)1095 GtkWidget *get_window_for_plot (void *session_plot)
1096 {
1097 GtkWidget *ret = NULL;
1098
1099 /* special for plot windows */
1100
1101 if (n_listed_windows > 1) {
1102 GList *wlist = gtk_action_group_list_actions(window_group);
1103 GList *list = wlist;
1104 GtkWidget *w;
1105 void *test;
1106
1107 while (list != NULL && ret == NULL) {
1108 w = window_from_action((GtkAction *) list->data);
1109 if (w != NULL) {
1110 test = g_object_get_data(G_OBJECT(w), "session-ptr");
1111 if (test != NULL && test == session_plot) {
1112 ret = w;
1113 }
1114 }
1115 list = list->next;
1116 }
1117 g_list_free(wlist);
1118 }
1119
1120 return ret;
1121 }
1122
package_being_edited(const char * pkgname,GtkWidget ** pw)1123 gboolean package_being_edited (const char *pkgname, GtkWidget **pw)
1124 {
1125 gboolean ret = FALSE;
1126
1127 if (n_listed_windows > 1) {
1128 GList *wlist = gtk_action_group_list_actions(window_group);
1129 GList *list = wlist;
1130 GtkWidget *w;
1131
1132 while (list != NULL && !ret) {
1133 w = window_from_action((GtkAction *) list->data);
1134 if (window_is_package_editor(w)) {
1135 ret = query_package_editor(w, pkgname);
1136 if (ret && pw != NULL) {
1137 *pw = w;
1138 }
1139 }
1140 list = list->next;
1141 }
1142 g_list_free(wlist);
1143 }
1144
1145 return ret;
1146 }
1147
highest_numbered_variable_in_winstack(void)1148 int highest_numbered_variable_in_winstack (void)
1149 {
1150 int m_vmax, vmax = 0;
1151
1152 if (n_listed_windows > 1) {
1153 GList *wlist = gtk_action_group_list_actions(window_group);
1154 GList *list = wlist;
1155 tabwin_t *tabwin;
1156 windata_t *vwin;
1157 GtkWidget *w;
1158
1159 while (list != NULL) {
1160 vwin = NULL;
1161 w = window_from_action((GtkAction *) list->data);
1162 if (w != NULL) {
1163 tabwin = g_object_get_data(G_OBJECT(w), "tabwin");
1164 if (tabwin == NULL) {
1165 vwin = g_object_get_data(G_OBJECT(w), "vwin");
1166 }
1167 if (tabwin != NULL) {
1168 m_vmax = highest_numbered_var_in_tabwin(tabwin, dataset);
1169 if (m_vmax > vmax) {
1170 vmax = m_vmax;
1171 }
1172 } else if (vwin != NULL && vwin->role == VIEW_MODEL) {
1173 const MODEL *pmod = vwin->data;
1174
1175 m_vmax = highest_numbered_var_in_model(pmod, dataset);
1176 if (m_vmax > vmax) {
1177 vmax = m_vmax;
1178 }
1179 } else if (vwin != NULL && (vwin->role == VAR || vwin->role == VECM)) {
1180 const GRETL_VAR *var = vwin->data;
1181
1182 m_vmax = gretl_VAR_get_highest_variable(var);
1183 if (m_vmax > vmax) {
1184 vmax = m_vmax;
1185 }
1186 }
1187 }
1188 list = list->next;
1189 }
1190 g_list_free(wlist);
1191 }
1192
1193 return vmax;
1194 }
1195
1196 /* compose a GList holding pointers to all models in
1197 individual or tabbed viewer windows */
1198
windowed_model_list(void)1199 GList *windowed_model_list (void)
1200 {
1201 GList *ret = NULL;
1202
1203 if (n_listed_windows > 1) {
1204 GList *wlist = gtk_action_group_list_actions(window_group);
1205 GList *list = wlist;
1206 tabwin_t *tabwin;
1207 windata_t *vwin;
1208 GtkWidget *w;
1209
1210 while (list != NULL) {
1211 vwin = NULL;
1212 w = window_from_action((GtkAction *) list->data);
1213 if (w != NULL) {
1214 tabwin = g_object_get_data(G_OBJECT(w), "tabwin");
1215 if (tabwin == NULL) {
1216 vwin = g_object_get_data(G_OBJECT(w), "vwin");
1217 }
1218 if (tabwin != NULL) {
1219 list_add_tabwin_models(tabwin, &ret);
1220 } else if (vwin != NULL && vwin->role == VIEW_MODEL) {
1221 ret = g_list_append(ret, vwin->data);
1222 }
1223 }
1224 list = list->next;
1225 }
1226 g_list_free(wlist);
1227 }
1228
1229 return ret;
1230 }
1231
1232 /* end of window-list apparatus */
1233
1234 static windata_flags vwin_presets;
1235
1236 /* This is used in a couple of special cases to apply a flag
1237 before the vwin GUI gets built. It's a bit of a hack, but
1238 avoids the alternatives of either (a) proliferating vwin
1239 "roles" or (b) adding another argument to all vwin-creating
1240 functions.
1241 */
1242
preset_viewer_flag(windata_flags f)1243 void preset_viewer_flag (windata_flags f)
1244 {
1245 vwin_presets = f;
1246 }
1247
vwin_new(int role,gpointer data)1248 windata_t *vwin_new (int role, gpointer data)
1249 {
1250 windata_t *vwin = mymalloc(sizeof *vwin);
1251
1252 if (vwin != NULL) {
1253 memset(vwin, 0, sizeof *vwin);
1254 vwin->role = role;
1255 vwin->data = data;
1256 vwin->flags = vwin_presets;
1257 }
1258
1259 vwin_presets = 0;
1260
1261 return vwin;
1262 }
1263
should_swallow_vwin(int role)1264 static int should_swallow_vwin (int role)
1265 {
1266 if (swallow) {
1267 /* can add others here, after a lot of work! */
1268 return role == CONSOLE;
1269 } else {
1270 return 0;
1271 }
1272 }
1273
1274 /* special setup for the case where the gretl main window
1275 will/may contain additional panes besides the dataset
1276 */
1277
1278 #define TWO_ROWS 0 /* not yet! */
1279
1280 #if TWO_ROWS
1281
mainwin_swallow_setup(windata_t * vwin)1282 static void mainwin_swallow_setup (windata_t *vwin)
1283 {
1284 GtkWidget *BigV = gtk_vbox_new(FALSE, 0);
1285 GtkWidget *vp = gtk_vpaned_new();
1286 GtkWidget *topbox = gtk_hbox_new(FALSE, 5);
1287
1288 g_object_set_data(G_OBJECT(vwin->main), "topbox", topbox);
1289 vwin->hpanes1 = gtk_hpaned_new();
1290 vwin->hpanes2 = gtk_hpaned_new();
1291
1292 gtk_box_pack_start(GTK_BOX(BigV), topbox, FALSE, FALSE, 0);
1293 gtk_box_pack_start(GTK_BOX(BigV), vp, TRUE, TRUE, 0);
1294 gtk_paned_add1(GTK_PANED(vp), vwin->hpanes1);
1295 gtk_paned_add2(GTK_PANED(vp), vwin->hpanes2);
1296 gtk_paned_set_position(GTK_PANED(vp), mainwin_height);
1297 gtk_container_add(GTK_CONTAINER(vwin->main), BigV);
1298 gtk_paned_add1(GTK_PANED(vwin->hpanes1), vwin->vbox);
1299 #if GTK_MAJOR_VERSION == 3
1300 gtk_paned_set_wide_handle(GTK_PANED(vwin->hpanes1), TRUE);
1301 gtk_paned_set_wide_handle(GTK_PANED(vwin->hpanes2), TRUE);
1302 #endif
1303 }
1304
1305 #else /* single row, just two panes total */
1306
mainwin_swallow_setup(windata_t * vwin)1307 static void mainwin_swallow_setup (windata_t *vwin)
1308 {
1309 GtkWidget *BigV = gtk_vbox_new(FALSE, 0);
1310 GtkWidget *topbox = gtk_hbox_new(FALSE, 5);
1311
1312 g_object_set_data(G_OBJECT(vwin->main), "topbox", topbox);
1313 vwin->hpanes1 = gtk_hpaned_new();
1314
1315 /* BigV contains a top slot to hold the "global" menubar,
1316 and under this a paned horizontal box to hold the
1317 two major components. At this stage we add the original
1318 main vbox to the left-hand pane; the console will be
1319 added later.
1320 */
1321 gtk_box_pack_start(GTK_BOX(BigV), topbox, FALSE, FALSE, 0);
1322 gtk_box_pack_start(GTK_BOX(BigV), vwin->hpanes1, TRUE, TRUE, 0);
1323 gtk_container_add(GTK_CONTAINER(vwin->main), BigV);
1324 gtk_paned_add1(GTK_PANED(vwin->hpanes1), vwin->vbox);
1325 #if GTK_MAJOR_VERSION == 3
1326 gtk_paned_set_wide_handle(GTK_PANED(vwin->hpanes1), TRUE);
1327 #endif
1328 }
1329
1330 #endif
1331
1332 windata_t *
gretl_viewer_new_with_parent(windata_t * parent,int role,const gchar * title,gpointer data)1333 gretl_viewer_new_with_parent (windata_t *parent, int role,
1334 const gchar *title,
1335 gpointer data)
1336 {
1337 windata_t *vwin = vwin_new(role, data);
1338 int toplevel = 1;
1339
1340 if (vwin == NULL) {
1341 return NULL;
1342 }
1343
1344 if (should_swallow_vwin(role) || (vwin->flags & VWIN_SWALLOW)) {
1345 toplevel = 0;
1346 }
1347
1348 if (toplevel) {
1349 vwin->main = gretl_gtk_window();
1350 if (title != NULL) {
1351 gtk_window_set_title(GTK_WINDOW(vwin->main), title);
1352 }
1353 g_object_set_data(G_OBJECT(vwin->main), "vwin", vwin);
1354 }
1355
1356 vwin->vbox = gtk_vbox_new(FALSE, 4);
1357 gtk_container_set_border_width(GTK_CONTAINER(vwin->vbox), 4);
1358
1359 if (swallow && role == MAINWIN) {
1360 mainwin_swallow_setup(vwin);
1361 } else if (toplevel) {
1362 gtk_container_add(GTK_CONTAINER(vwin->main), vwin->vbox);
1363 } else {
1364 g_object_set_data(G_OBJECT(vwin->vbox), "vwin", vwin);
1365 vwin->main = vwin->vbox;
1366 return vwin; /* we're done here */
1367 }
1368
1369 if (parent != NULL) {
1370 vwin_add_child(parent, vwin);
1371 }
1372
1373 #if 0
1374 fprintf(stderr, "viewer_new: vwin %p, gtk window %p, role %d\n", (void *) vwin,
1375 (void *) vwin->main, role);
1376 #endif
1377
1378 if (role == MAINWIN) {
1379 gtk_window_set_position(GTK_WINDOW(vwin->main),
1380 GTK_WIN_POS_CENTER);
1381 } else {
1382 g_signal_connect(G_OBJECT(vwin->main), "destroy",
1383 G_CALLBACK(free_windata), vwin);
1384 gtk_window_set_position(GTK_WINDOW(vwin->main),
1385 GTK_WIN_POS_MOUSE);
1386 }
1387
1388 if (title != NULL) {
1389 window_list_add(vwin->main, role);
1390 #ifndef G_OS_WIN32
1391 set_wm_icon(vwin->main);
1392 #endif
1393 }
1394
1395 return vwin;
1396 }
1397
gretl_viewer_new(int role,const gchar * title,gpointer data)1398 windata_t *gretl_viewer_new (int role, const gchar *title,
1399 gpointer data)
1400 {
1401 return gretl_viewer_new_with_parent(NULL, role, title,
1402 data);
1403 }
1404
vwin_toplevel(windata_t * vwin)1405 GtkWidget *vwin_toplevel (windata_t *vwin)
1406 {
1407 if (vwin == NULL) {
1408 return NULL;
1409 } else if (vwin->flags & VWIN_SWALLOW) {
1410 /* vwin swallowed by main */
1411 return mdata->main;
1412 } else if (vwin->topmain != NULL) {
1413 /* the tabbed case */
1414 return vwin->topmain;
1415 } else {
1416 return gtk_widget_get_toplevel(vwin->main);
1417 }
1418 }
1419
real_add_winlist(windata_t * vwin,GtkWidget * window,GtkWidget * hbox)1420 static GtkWidget *real_add_winlist (windata_t *vwin,
1421 GtkWidget *window,
1422 GtkWidget *hbox)
1423 {
1424 GtkWidget *button, *img, *tbar;
1425 GtkWidget *sibling = NULL;
1426 GtkToolItem *item;
1427
1428 button = gtk_button_new();
1429 item = gtk_tool_item_new();
1430
1431 if (vwin != NULL && vwin->mbar != NULL &&
1432 GTK_IS_MENU_BAR(vwin->mbar)) {
1433 sibling = vwin->mbar;
1434 }
1435
1436 tbar = gretl_toolbar_new(sibling);
1437
1438 gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Windows"));
1439 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1440 img = gtk_image_new_from_stock(GRETL_STOCK_WINLIST, toolbar_icon_size);
1441 gtk_container_add(GTK_CONTAINER(button), img);
1442 gtk_container_add(GTK_CONTAINER(item), button);
1443
1444 if (vwin != NULL) {
1445 g_signal_connect(G_OBJECT(button), "button-press-event",
1446 G_CALLBACK(vwin_winlist_popup), vwin);
1447 } else {
1448 g_signal_connect(G_OBJECT(button), "button-press-event",
1449 G_CALLBACK(window_list_popup), window);
1450 }
1451
1452 gtk_toolbar_insert(GTK_TOOLBAR(tbar), item, -1);
1453 gtk_widget_show_all(tbar);
1454 gtk_box_pack_end(GTK_BOX(hbox), tbar, FALSE, FALSE, 0);
1455
1456 return tbar;
1457 }
1458
vwin_add_winlist(windata_t * vwin)1459 void vwin_add_winlist (windata_t *vwin)
1460 {
1461 GtkWidget *hbox = gtk_widget_get_parent(vwin->mbar);
1462
1463 if (g_object_get_data(G_OBJECT(hbox), "winlist") == NULL) {
1464 GtkWidget *winlist;
1465
1466 winlist = real_add_winlist(vwin, NULL, hbox);
1467 g_object_set_data(G_OBJECT(hbox), "winlist", winlist);
1468 }
1469 }
1470
window_add_winlist(GtkWidget * window,GtkWidget * hbox)1471 void window_add_winlist (GtkWidget *window, GtkWidget *hbox)
1472 {
1473 if (g_object_get_data(G_OBJECT(hbox), "winlist") == NULL) {
1474 GtkWidget *winlist;
1475
1476 winlist = real_add_winlist(NULL, window, hbox);
1477 g_object_set_data(G_OBJECT(hbox), "winlist", winlist);
1478 }
1479 }
1480
1481 #if 0 /* specific to "swallow" and unused at present */
1482
1483 static void menubar_add_closer (windata_t *vwin)
1484 {
1485 GtkWidget *hbox = gtk_widget_get_parent(vwin->mbar);
1486 GtkWidget *button, *img, *tbar;
1487 GtkWidget *sibling = NULL;
1488 GtkToolItem *item;
1489
1490 button = gtk_button_new();
1491 item = gtk_tool_item_new();
1492
1493 if (vwin != NULL && vwin->mbar != NULL &&
1494 GTK_IS_MENU_BAR(vwin->mbar)) {
1495 sibling = vwin->mbar;
1496 }
1497
1498 tbar = gretl_toolbar_new(sibling);
1499 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1500 img = gtk_image_new_from_stock(GRETL_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
1501 gtk_container_add(GTK_CONTAINER(button), img);
1502 gtk_container_add(GTK_CONTAINER(item), button);
1503
1504 g_signal_connect_swapped(G_OBJECT(button), "button-press-event",
1505 G_CALLBACK(gtk_widget_destroy), vwin->main);
1506
1507 gtk_toolbar_insert(GTK_TOOLBAR(tbar), item, -1);
1508 gtk_widget_show_all(tbar);
1509 gtk_box_pack_end(GTK_BOX(hbox), tbar, FALSE, FALSE, 0);
1510 }
1511
1512 #endif
1513
destroy_hbox_child(GtkWidget * w,gpointer p)1514 static void destroy_hbox_child (GtkWidget *w, gpointer p)
1515 {
1516 if (GTK_IS_SPINNER(w)) {
1517 gtk_spinner_stop(GTK_SPINNER(w));
1518 }
1519 gtk_widget_destroy(w);
1520 }
1521
want_winlist(windata_t * vwin)1522 static int want_winlist (windata_t *vwin)
1523 {
1524 if (vwin->flags & VWIN_SWALLOW) {
1525 return 0;
1526 } else {
1527 GtkWidget *hbox = gtk_widget_get_parent(vwin->mbar);
1528
1529 return g_object_get_data(G_OBJECT(hbox), "winlist") == NULL;
1530 }
1531 }
1532
vwin_pack_toolbar(windata_t * vwin)1533 void vwin_pack_toolbar (windata_t *vwin)
1534 {
1535 if (vwin->topmain != NULL) {
1536 /* @vwin is embedded in a tabbed window */
1537 tabwin_register_toolbar(vwin);
1538 if (want_winlist(vwin)) {
1539 vwin_add_winlist(vwin);
1540 }
1541 } else {
1542 GtkWidget *hbox;
1543
1544 /* check for presence of a temporary "top-hbox" -- as
1545 in a script output window that's waiting for full
1546 output
1547 */
1548 hbox = g_object_get_data(G_OBJECT(vwin->main), "top-hbox");
1549
1550 if (hbox != NULL) {
1551 gtk_container_foreach(GTK_CONTAINER(hbox), destroy_hbox_child, NULL);
1552 gtk_box_pack_start(GTK_BOX(hbox), vwin->mbar, FALSE, FALSE, 0);
1553 } else {
1554 hbox = gtk_hbox_new(FALSE, 0);
1555 gtk_box_set_spacing(GTK_BOX(vwin->vbox), 0);
1556 gtk_box_pack_start(GTK_BOX(vwin->vbox), hbox, FALSE, FALSE, 0);
1557
1558 if (vwin->role == VIEW_MODEL || vwin->role == VAR ||
1559 vwin->role == VECM) {
1560 /* model viewer: the menubar extends full-length */
1561 gtk_box_pack_start(GTK_BOX(hbox), vwin->mbar, TRUE, TRUE, 0);
1562 } else {
1563 gtk_box_pack_start(GTK_BOX(hbox), vwin->mbar, FALSE, FALSE, 0);
1564 if (vwin->role == SCRIPT_OUT) {
1565 /* added 2015-11-16 */
1566 g_object_set_data(G_OBJECT(vwin->main), "top-hbox", hbox);
1567 }
1568 }
1569 if (window_is_tab(vwin)) {
1570 /* here we're re-packing vwin->mbar: move it up top */
1571 gtk_box_reorder_child(GTK_BOX(vwin->vbox), hbox, 0);
1572 }
1573 }
1574 if (want_winlist(vwin)) {
1575 vwin_add_winlist(vwin);
1576 }
1577 if (use_toolbar_search_box(vwin->role)) {
1578 vwin_add_finder(vwin);
1579 }
1580 if (vwin->flags & VWIN_SWALLOW) {
1581 #if 0 /* don't show a close for swallowed console */
1582 menubar_add_closer(vwin);
1583 #endif
1584 if (vwin->role == CONSOLE) {
1585 GtkWidget *lbl = gtk_label_new(_("gretl console"));
1586
1587 gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 5);
1588 gtk_box_reorder_child(GTK_BOX(hbox), lbl, 0);
1589 }
1590 }
1591 gtk_widget_show_all(hbox);
1592 }
1593 }
1594
vwin_reinstate_toolbar(windata_t * vwin)1595 void vwin_reinstate_toolbar (windata_t *vwin)
1596 {
1597 GtkWidget *hbox;
1598
1599 hbox = g_object_get_data(G_OBJECT(vwin->main), "top-hbox");
1600
1601 if (hbox != NULL) {
1602 /* destroy the temporary stuff, put the "real" stuff back,
1603 and drop the extra references
1604 */
1605 GtkWidget *winlist;
1606
1607 gtk_container_foreach(GTK_CONTAINER(hbox), destroy_hbox_child, NULL);
1608 gtk_box_pack_start(GTK_BOX(hbox), vwin->mbar, FALSE, FALSE, 0);
1609 g_object_unref(G_OBJECT(vwin->mbar));
1610 winlist = g_object_get_data(G_OBJECT(hbox), "winlist");
1611 if (winlist != NULL) {
1612 gtk_box_pack_end(GTK_BOX(hbox), winlist, FALSE, FALSE, 0);
1613 g_object_unref(G_OBJECT(winlist));
1614 }
1615 if (vwin->finder != NULL) {
1616 gtk_box_pack_end(GTK_BOX(hbox), vwin->finder, FALSE, FALSE, 5);
1617 g_object_unref(G_OBJECT(vwin->finder));
1618 }
1619 gtk_widget_show_all(hbox);
1620 }
1621 }
1622
gretl_browser_new(int role,const gchar * title)1623 windata_t *gretl_browser_new (int role, const gchar *title)
1624 {
1625 windata_t *vwin = vwin_new(role, NULL);
1626
1627 if (vwin == NULL) {
1628 return NULL;
1629 }
1630
1631 vwin->main = gretl_gtk_window();
1632 gtk_window_set_title(GTK_WINDOW(vwin->main), title);
1633 g_object_set_data(G_OBJECT(vwin->main), "vwin", vwin);
1634
1635 g_signal_connect(G_OBJECT(vwin->main), "destroy",
1636 G_CALLBACK(free_windata), vwin);
1637 gtk_window_set_position(GTK_WINDOW(vwin->main),
1638 GTK_WIN_POS_MOUSE);
1639
1640 #if 0
1641 fprintf(stderr, "browser_new: vwin %p, gtk window %p, role %d\n",
1642 (void *) vwin, (void *) vwin->main, role);
1643 #endif
1644
1645 window_list_add(vwin->main, role);
1646 #ifndef G_OS_WIN32
1647 set_wm_icon(vwin->main);
1648 #endif
1649
1650 return vwin;
1651 }
1652
gretl_viewer_present(windata_t * vwin)1653 void gretl_viewer_present (windata_t *vwin)
1654 {
1655 if (window_is_tab(vwin)) {
1656 tabwin_tab_present(vwin);
1657 } else {
1658 gtk_window_present(GTK_WINDOW(vwin->main));
1659 }
1660 }
1661
gretl_viewer_destroy(windata_t * vwin)1662 void gretl_viewer_destroy (windata_t *vwin)
1663 {
1664 if (window_is_tab(vwin)) {
1665 tabwin_tab_destroy(vwin);
1666 } else {
1667 gtk_widget_destroy(vwin->main);
1668 }
1669 }
1670
gretl_viewer_set_title(windata_t * vwin,const char * title)1671 void gretl_viewer_set_title (windata_t *vwin, const char *title)
1672 {
1673 if (window_is_tab(vwin)) {
1674 if (!strncmp(title, "gretl: ", 7)) {
1675 title += 7;
1676 }
1677 tabwin_tab_set_title(vwin, title);
1678 } else {
1679 gtk_window_set_title(GTK_WINDOW(vwin->main), title);
1680 }
1681 }
1682
1683 /* When we add popup menus as callbacks for buttons on @vwin's
1684 toolbar, we want to record pointers to them so we're
1685 able to destroy them when @vwin is closed, otherwise
1686 we'd be leaking memory.
1687 */
1688
vwin_record_toolbar_popup(windata_t * vwin,GtkWidget * menu)1689 void vwin_record_toolbar_popup (windata_t *vwin, GtkWidget *menu)
1690 {
1691 GList *plist;
1692
1693 plist = g_object_get_data(G_OBJECT(vwin->mbar), "toolbar-popups");
1694 plist = g_list_append(plist, menu);
1695 g_object_set_data(G_OBJECT(vwin->mbar), "toolbar-popups", plist);
1696 }
1697
trash_toolbar_popup(gpointer data,gpointer p)1698 static void trash_toolbar_popup (gpointer data, gpointer p)
1699 {
1700 gtk_widget_destroy(GTK_WIDGET(data));
1701 }
1702
vwin_free_toolbar_popups(windata_t * vwin)1703 void vwin_free_toolbar_popups (windata_t *vwin)
1704 {
1705 if (vwin->mbar != NULL) {
1706 GList *plist;
1707
1708 plist = g_object_get_data(G_OBJECT(vwin->mbar), "toolbar-popups");
1709 if (plist != NULL) {
1710 g_list_foreach(plist, trash_toolbar_popup, NULL);
1711 }
1712 g_list_free(plist);
1713 }
1714 }
1715
vwin_record_action(windata_t * vwin,GtkAction * action)1716 void vwin_record_action (windata_t *vwin, GtkAction *action)
1717 {
1718 const gchar *name = gtk_action_get_name(action);
1719
1720 g_object_set_data(G_OBJECT(vwin->main), name, action);
1721 }
1722
vwin_action_set_sensitive(windata_t * vwin,const char * name,gboolean s)1723 void vwin_action_set_sensitive (windata_t *vwin, const char *name,
1724 gboolean s)
1725 {
1726 GtkAction *action = g_object_get_data(G_OBJECT(vwin->main), name);
1727
1728 if (action != NULL) {
1729 gtk_action_set_sensitive(action, s);
1730 }
1731 }
1732