1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <glib.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <gtk/gtk.h>
31 
32 #include <sweep/sweep_i18n.h>
33 #include <sweep/sweep_types.h>
34 #include <sweep/sweep_sample.h>
35 
36 #include "interface.h"
37 
38 #include "../pixmaps/scrubby.xpm"
39 #include "../pixmaps/scrubby_system.xpm"
40 
41 static gboolean up_and_running = FALSE;
42 
43 static void
question_dialog_destroy_cb(GtkWidget * widget,gpointer data)44 question_dialog_destroy_cb (GtkWidget * widget, gpointer data)
45 {
46   GtkWidget * dialog;
47   sw_sample * sample;
48   gboolean quit_if_no_files = FALSE;
49 
50   dialog = gtk_widget_get_toplevel (widget);
51 
52   quit_if_no_files = (gboolean)
53     GPOINTER_TO_INT(g_object_get_data (G_OBJECT(widget), "quit_nofiles"));
54 
55   sample = g_object_get_data (G_OBJECT(dialog), "default");
56   if (sample && sample_bank_contains (sample)) {
57     sample_set_edit_mode (sample, SWEEP_EDIT_MODE_READY);
58   }
59 
60   if (quit_if_no_files || !up_and_running)
61     sample_bank_remove (NULL);
62 }
63 
64 static void
question_dialog_answer_cb(GtkWidget * widget,gpointer data)65 question_dialog_answer_cb (GtkWidget * widget, gpointer data)
66 {
67   GtkWidget * dialog;
68   GCallback(*func) (GtkWidget* widget, gpointer data);
69 
70   up_and_running = TRUE;
71 
72   func = g_object_get_data (G_OBJECT(widget), "default");
73   dialog = gtk_widget_get_toplevel (widget);
74 
75   if (func != NULL)
76     func (widget, data);
77 
78   /* "destroy" will call destroy above */
79 
80   gtk_widget_destroy (dialog);
81 }
82 
83 static void
query_dialog_new(sw_sample * sample,char * title,char * question,gboolean show_cancel,char * ok_answer,char * no_answer,GCallback ok_callback,gpointer ok_callback_data,GCallback no_callback,gpointer no_callback_data,gpointer xpm_data,gboolean quit_if_no_files)84 query_dialog_new (sw_sample * sample, char * title, char * question,
85 		  gboolean show_cancel, char * ok_answer, char * no_answer,
86 		  GCallback ok_callback, gpointer ok_callback_data,
87 		  GCallback no_callback, gpointer no_callback_data,
88 		  gpointer xpm_data, gboolean quit_if_no_files)
89 {
90   gchar * new_title;
91 
92   GtkWidget * window;
93   GtkWidget * button, * ok_button;
94   GtkWidget * vbox;
95   GtkWidget * hbox;
96   GtkWidget * label;
97   GtkWidget * pixmap;
98 
99   window = gtk_dialog_new ();
100   sweep_set_window_icon (GTK_WINDOW(window));
101 
102   new_title = g_strdup_printf ("%s: %s", "Sweep", title);
103   gtk_window_set_title (GTK_WINDOW(window), new_title);
104   g_free (new_title);
105 
106   gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
107   gtk_container_set_border_width  (GTK_CONTAINER(window), 8);
108 
109   g_object_set_data (G_OBJECT(window), "default", sample);
110 
111   g_signal_connect (G_OBJECT(window), "destroy",
112 		      G_CALLBACK(question_dialog_destroy_cb), window);
113 
114   attach_window_close_accel(GTK_WINDOW(window));
115 
116   g_object_set_data (G_OBJECT(window), "quit_nofiles",
117 		       GINT_TO_POINTER((gint)quit_if_no_files));
118 
119   vbox = GTK_DIALOG(window)->vbox;
120 
121   /* Question */
122 
123   hbox = gtk_hbox_new (FALSE, 0);
124   gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, FALSE, 0);
125   gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
126   gtk_widget_show (hbox);
127 
128   if (xpm_data == NULL) xpm_data = scrubby_xpm;
129 
130   pixmap = create_widget_from_xpm (window, xpm_data);
131   gtk_box_pack_start (GTK_BOX(hbox), pixmap, FALSE, FALSE, 12);
132   gtk_widget_show (pixmap);
133 
134   label = gtk_label_new (question);
135   gtk_box_pack_start (GTK_BOX(hbox), label, TRUE, FALSE, 12);
136   gtk_widget_show (label);
137 
138   /* New layout of buttons */
139 
140   gtk_button_box_set_layout (GTK_BUTTON_BOX(GTK_DIALOG(window)->action_area), GTK_BUTTONBOX_SPREAD);
141 
142   /* OK */
143 
144   if (ok_answer == NULL) ok_answer = _("OK");
145   ok_button = gtk_button_new_with_label (ok_answer);
146   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (ok_button), GTK_CAN_DEFAULT);
147   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->action_area),
148 		      ok_button, TRUE, TRUE, 0);
149   g_object_set_data (G_OBJECT(ok_button), "default", ok_callback);
150   gtk_widget_show (ok_button);
151   g_signal_connect (G_OBJECT(ok_button), "clicked",
152 		      G_CALLBACK (question_dialog_answer_cb),
153 		      ok_callback_data);
154 
155   /* Cancel */
156 
157   if (show_cancel) {
158     if (no_answer == NULL) no_answer = _("Cancel");
159     button = gtk_button_new_with_label (no_answer);
160     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
161     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->action_area),
162 			button, TRUE, TRUE, 0);
163     g_object_set_data (G_OBJECT(button), "default", no_callback);
164     gtk_widget_show (button);
165     g_signal_connect (G_OBJECT(button), "clicked",
166 			G_CALLBACK (question_dialog_answer_cb),
167 			no_callback_data);
168   }
169 
170   gtk_widget_grab_default (ok_button);
171 
172   gtk_widget_show (window);
173 }
174 
175 void
question_dialog_new(sw_sample * sample,char * title,char * question,char * yes_answer,char * no_answer,GCallback yes_callback,gpointer yes_callback_data,GCallback no_callback,gpointer no_callback_data,sw_edit_mode edit_mode)176 question_dialog_new (sw_sample * sample, char * title, char * question,
177 		     char * yes_answer, char * no_answer,
178 		     GCallback yes_callback, gpointer yes_callback_data,
179 		     GCallback no_callback, gpointer no_callback_data,
180 		     sw_edit_mode edit_mode)
181 {
182   if (edit_mode != SWEEP_EDIT_MODE_READY)
183     sample_set_edit_mode (sample, edit_mode);
184 
185   query_dialog_new (sample, title, question, TRUE, yes_answer, no_answer,
186 		    yes_callback, yes_callback_data,
187 		    no_callback, no_callback_data, NULL, FALSE);
188 }
189 
190 /* Thread safe info dialogs */
191 
192 typedef struct {
193   char * title;
194   char * message;
195   gpointer xpm_data;
196 } info_dialog_data;
197 
198 static gint
do_info_dialog(gpointer data)199 do_info_dialog (gpointer data)
200 {
201   info_dialog_data * id = (info_dialog_data *)data;
202 
203   query_dialog_new (NULL, id->title, id->message, FALSE,
204 		    _("OK"), NULL, NULL, NULL,
205 		    NULL, NULL, id->xpm_data, TRUE);
206 
207   g_free (id->title);
208   g_free (id->message);
209 
210   return FALSE;
211 }
212 
213 void
info_dialog_new(char * title,gpointer xpm_data,const char * fmt,...)214 info_dialog_new (char * title, gpointer xpm_data, const char * fmt, ...)
215 {
216   info_dialog_data * id;
217   va_list ap;
218 #define BUF_LEN 512
219   char buf[BUF_LEN];
220 
221   va_start (ap, fmt);
222   vsnprintf (buf, BUF_LEN, fmt, ap);
223   va_end (ap);
224 
225   id = g_malloc (sizeof (info_dialog_data));
226   id->title = g_strdup (title);
227   id->message = g_strdup (buf);
228   id->xpm_data = xpm_data;
229 
230   sweep_timeout_add ((guint32)0, (GtkFunction)do_info_dialog, id);
231 }
232 
233 /* Thread safe GUI perror reporting */
234 
235 typedef struct {
236   int thread_errno;
237   char * message;
238 } sweep_perror_data;
239 
240 static gint
syserror_dialog_new(gpointer data)241 syserror_dialog_new (gpointer data)
242 {
243   sweep_perror_data * pd = (sweep_perror_data *)data;
244   gchar * sys_errstr = NULL;
245   char * new_message;
246 
247   sys_errstr = (gchar *) g_strerror (pd->thread_errno);
248 
249   if (sys_errstr != NULL) {
250     new_message = g_strdup_printf ("%s:\n\n%s", pd->message, sys_errstr);
251 
252     query_dialog_new (NULL, sys_errstr, new_message, FALSE,
253 		      _("OK"), NULL, NULL, NULL,
254 		      NULL, NULL, scrubby_system_xpm, TRUE);
255   }
256 
257   g_free (pd->message);
258   g_free (pd);
259 
260   return FALSE;
261 }
262 
263 void
sweep_perror(int thread_errno,const char * fmt,...)264 sweep_perror (int thread_errno, const char * fmt, ...)
265 {
266   sweep_perror_data * pd;
267   va_list ap;
268 #undef BUF_LEN
269 #define BUF_LEN 512
270   char buf[BUF_LEN];
271 
272   va_start (ap, fmt);
273   vsnprintf (buf, BUF_LEN, fmt, ap);
274   va_end (ap);
275 
276   pd = g_malloc (sizeof (sweep_perror_data));
277   pd->thread_errno = thread_errno;
278   pd->message = g_strdup (buf);
279 
280   sweep_timeout_add ((guint32)0, (GtkFunction)syserror_dialog_new, pd);
281 }
282