1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "gbdfed.h"
24 
25 /*
26  * The shared error dialog and the label for the message.
27  */
28 static GtkWidget *errd;
29 static GtkWidget *errmsg;
30 
31 /*
32  * The shared question dialog, the label for the question, and the
33  * value representing the answer.
34  */
35 static GtkWidget *questd;
36 static GtkWidget *question;
37 static GtkWidget *yes;
38 static GtkWidget *no;
39 
40 void
guiutil_show_dialog_centered(GtkWidget * dialog,GtkWidget * parent)41 guiutil_show_dialog_centered(GtkWidget *dialog, GtkWidget *parent)
42 {
43     if (GTK_WINDOW(parent) != gtk_window_get_transient_for(GTK_WINDOW(dialog)))
44       gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
45     gtk_widget_show(dialog);
46 }
47 
48 void
guiutil_error_message(GtkWidget * parent,gchar * text)49 guiutil_error_message(GtkWidget *parent, gchar *text)
50 {
51     GtkWidget *ok, *hbox, *image;
52     GtkStockItem item;
53 
54     if (errd == 0) {
55         errd = gtk_dialog_new();
56         (void) g_signal_connect(G_OBJECT(errd), "delete_event",
57                                 G_CALLBACK(gtk_widget_hide), 0);
58 
59         hbox = gtk_hbox_new(FALSE, 0);
60 
61         /*
62          * Create the error icon.
63          */
64         if (gtk_stock_lookup(GTK_STOCK_DIALOG_ERROR, &item)) {
65             /*
66              * Set the dialog title.
67              */
68             gtk_window_set_title(GTK_WINDOW(errd), item.label);
69             image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_ERROR,
70                                              GTK_ICON_SIZE_DIALOG);
71             gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2);
72         } else {
73             /*
74              * Probably not necessary, but use some default icon here.
75              */
76         }
77 
78         errmsg = gtk_label_new(text);
79         gtk_box_pack_start(GTK_BOX(hbox), errmsg, TRUE, TRUE, 2);
80         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(errd)->vbox), hbox);
81 
82         ok = gtk_dialog_add_button(GTK_DIALOG(errd), GTK_STOCK_CLOSE,
83                                    GTK_RESPONSE_CLOSE);
84         (void) g_signal_connect_object(G_OBJECT(ok), "clicked",
85                                        G_CALLBACK(gtk_widget_hide),
86                                        (gpointer) errd,
87                                        G_CONNECT_SWAPPED);
88 
89         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(errd)->action_area), ok);
90 
91         gtk_widget_show_all(errd);
92 
93         gtk_window_set_modal(GTK_WINDOW(errd), TRUE);
94     } else
95       gtk_label_set_text(GTK_LABEL(errmsg), text);
96 
97     /*
98      * Center the dialog and display it.
99      */
100     guiutil_show_dialog_centered(errd, parent);
101 
102     /*
103      * Ring the bell.
104      */
105     gdk_beep();
106 }
107 
108 gboolean
guiutil_yes_or_no(GtkWidget * parent,gchar * text,gboolean default_answer)109 guiutil_yes_or_no(GtkWidget *parent, gchar *text, gboolean default_answer)
110 {
111     GtkWidget *hbox, *image;
112     GList *kids;
113     gint ans;
114     GtkStockItem item;
115 
116     if (questd == 0) {
117         questd = gtk_dialog_new();
118         gtk_window_set_resizable(GTK_WINDOW(questd), TRUE);
119 
120         (void) g_signal_connect(G_OBJECT(questd), "delete_event",
121                                 G_CALLBACK(gtk_widget_hide), 0);
122 
123         hbox = gtk_hbox_new(FALSE, 0);
124 
125         /*
126          * Create the question icon.
127          */
128         if (gtk_stock_lookup(GTK_STOCK_DIALOG_QUESTION, &item)) {
129             /*
130              * Set the dialog title.
131              */
132             gtk_window_set_title(GTK_WINDOW(questd), item.label);
133             image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,
134                                              GTK_ICON_SIZE_DIALOG);
135             gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2);
136         } else {
137             /*
138              * Probably not necessary, but use some default icon here.
139              */
140         }
141 
142         question = gtk_label_new(text);
143 
144         gtk_box_pack_start(GTK_BOX(hbox), question, TRUE, TRUE, 2);
145         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(questd)->vbox), hbox);
146 
147         /*
148          * Make sure the buttons are evenly distributed in the button box.
149          */
150         gtk_button_box_set_layout(GTK_BUTTON_BOX(GTK_DIALOG(questd)->action_area), GTK_BUTTONBOX_SPREAD);
151 
152         gtk_dialog_add_buttons(GTK_DIALOG(questd),
153                                GTK_STOCK_YES, GTK_RESPONSE_ACCEPT,
154                                GTK_STOCK_NO, GTK_RESPONSE_CANCEL, NULL);
155 
156         /*
157          * Get the two children buttons out now so focus can be set on either
158          * when needed.
159          */
160         kids = gtk_container_get_children(GTK_CONTAINER(GTK_DIALOG(questd)->action_area));
161         no = GTK_WIDGET(g_list_nth_data(kids, 0));
162         yes = GTK_WIDGET(g_list_nth_data(kids, 1));
163         g_list_free(kids);
164 
165         gtk_widget_show_all(questd);
166 
167         gtk_window_set_modal(GTK_WINDOW(questd), TRUE);
168     } else
169       gtk_label_set_text(GTK_LABEL(question), text);
170 
171     /*
172      * Force the dialog to reset to its minimum size.
173      */
174     if (questd->window != NULL)
175       gtk_window_resize(GTK_WINDOW(questd), 1, 1);
176 
177     /*
178      * Center the dialog and display it.
179      */
180     guiutil_show_dialog_centered(questd, parent);
181 
182     /*
183      * Force the default answer button to have the focus.
184      */
185     if (default_answer)
186       gtk_widget_grab_focus(yes);
187     else
188       gtk_widget_grab_focus(no);
189 
190     ans = gtk_dialog_run(GTK_DIALOG(questd));
191 
192     gtk_widget_hide(questd);
193 
194     return (ans == GTK_RESPONSE_ACCEPT) ? TRUE : FALSE;
195 }
196 
197 void
guiutil_util_set_tooltip(GtkWidget * w,gchar * text)198 guiutil_util_set_tooltip(GtkWidget *w, gchar *text)
199 {
200 #if GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 12
201     gtk_widget_set_tooltip_text(w, text);
202 #else
203     GtkTooltips *tt;
204 
205     tt = gtk_tooltips_new();
206     gtk_tooltips_set_tip(tt, w, text, 0);
207 #endif
208 }
209 
210 static GdkCursor *watch_cursor;
211 
212 void
guiutil_busy_cursor(GtkWidget * w,gboolean on)213 guiutil_busy_cursor(GtkWidget *w, gboolean on)
214 {
215     if (watch_cursor == 0)
216       watch_cursor = gdk_cursor_new(GDK_WATCH);
217 
218     if (on)
219       gdk_window_set_cursor(w->window, watch_cursor);
220     else
221       gdk_window_set_cursor(w->window, 0);
222 }
223 
224 void
guiutil_cursor_cleanup()225 guiutil_cursor_cleanup()
226 {
227     if (watch_cursor != 0)
228       gdk_cursor_unref(watch_cursor);
229     watch_cursor = 0;
230 }
231