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 <gtk/gtk.h>
21 #include "focus.h"
22 
23 /* This module added 2021-06-17. The point of wrapping gtk_dialog_new()
24    and gtk_window_new() is to inject common code that supports a
25    record of the currently focused window. Then when functions such
26    as errbox, infobox and warnbox (or variants thereof) are called
27    we can arrange for the resulting message dialogs to be parented
28    by the window from which they were spawned. Hopefully this will
29    improve the placement of the transient windows.
30 
31    The code that utilizes get_focus_window() is to be found in
32    dialogs.c, in the msgbox() function.
33 */
34 
35 #define FOCUS_DEBUG 0
36 
37 /* the window that currently has focus */
38 static GtkWidget *focus_window;
39 
get_focus_window(void)40 GtkWidget *get_focus_window (void)
41 {
42     return focus_window;
43 }
44 
45 /* callback for when a window receives focus */
46 
focus_in_cb(GtkWidget * w,GdkEvent * event,gpointer p)47 static gboolean focus_in_cb (GtkWidget *w, GdkEvent *event,
48 			     gpointer p)
49 {
50 #if FOCUS_DEBUG
51     fprintf(stderr, "focus_in: %p\n", (void *) w);
52 #endif
53     focus_window = w;
54     return FALSE;
55 }
56 
57 /* callback for when a window loses focus */
58 
focus_out_cb(GtkWidget * w,GdkEvent * event,gpointer p)59 static gboolean focus_out_cb (GtkWidget *w, GdkEvent *event,
60 			      gpointer p)
61 {
62 #if FOCUS_DEBUG
63     fprintf(stderr, "focus_out: %p\n", (void *) w);
64 #endif
65     focus_window = NULL;
66     return FALSE;
67 }
68 
69 /* callback for window destroyed */
70 
destroy_cb(GtkWidget * w,gpointer p)71 static void destroy_cb (GtkWidget *w, gpointer p)
72 {
73 #if FOCUS_DEBUG
74     fprintf(stderr, "focus destroy: %p\n", (void *) w);
75 #endif
76     if (focus_window == w) {
77 	focus_window = NULL;
78     }
79 }
80 
real_gretl_gtk_object(int window)81 static GtkWidget *real_gretl_gtk_object (int window)
82 {
83     GtkWidget *ret;
84 
85     if (window) {
86 	ret = gtk_window_new(GTK_WINDOW_TOPLEVEL);
87     } else {
88 	ret = gtk_dialog_new();
89     }
90 
91     /* redundant? */
92     gtk_widget_add_events(ret, GDK_FOCUS_CHANGE_MASK);
93 
94     /* attach our focus-related callbacks */
95     g_signal_connect(G_OBJECT(ret), "focus-in-event",
96 		     G_CALLBACK(focus_in_cb), NULL);
97     g_signal_connect(G_OBJECT(ret), "focus-out-event",
98 		     G_CALLBACK(focus_out_cb), NULL);
99     g_signal_connect(G_OBJECT(ret), "destroy",
100 		     G_CALLBACK(destroy_cb), NULL);
101 
102     return ret;
103 }
104 
105 /* wrapper for gtk_dialog_new() */
106 
gretl_gtk_dialog(void)107 GtkWidget *gretl_gtk_dialog (void)
108 {
109     return real_gretl_gtk_object(0);
110 }
111 
112 /* wrapper for gtk_window_new (toplevel) */
113 
gretl_gtk_window(void)114 GtkWidget *gretl_gtk_window (void)
115 {
116     return real_gretl_gtk_object(1);
117 }
118