1 /*
2  * Copyright (C) 2004 2005 2008 2009, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit 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  * mhWaveEdit 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 mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <config.h>
22 
23 #include <math.h>
24 #include <gtk/gtk.h>
25 #include <gdk/gdkkeysyms.h>
26 
27 #include "recorddialog.h"
28 #include "main.h"
29 #include "inifile.h"
30 #include "sound.h"
31 #include "um.h"
32 #include "int_box.h"
33 #include "formatselector.h"
34 #include "gettext.h"
35 #include "mainloop.h"
36 
37 static struct {
38      GtkWindow *wnd;
39      FormatSelector *fs;
40      GtkEntry *name_entry;
41      int old_choice;
42      GtkList *preset_list;
43      GtkLabel *set_button_label;
44      GtkButton *set_button_button;
45 } other_dialog;
46 
47 static gboolean record_dialog_set_format(RecordDialog *rd);
48 
49 static GtkObjectClass *parent_class;
50 static gboolean record_dialog_stopflag = FALSE;
51 static RecordDialog *current_dialog;
52 
53 static ListObject *preset_list = NULL;
54 
build_preset_list(void)55 static void build_preset_list(void)
56 {
57      gchar *s1,*s2,*s3,*s4,*s5,*s6;
58      GList *l2 = NULL;
59      int i;
60      RecordFormat *rf;
61 
62      if (preset_list != NULL) return;
63 
64      /* Build format list */
65      /* Support reading both old and new style formats */
66      if (inifile_get("recordFormat1",NULL) == NULL &&
67 	 inifile_get("recordFormat1_Name",NULL) == NULL) {
68 	  inifile_set("recordFormat1","16/2/44100/S/CD Quality");
69 	  inifile_set("recordFormat2","8/1/8000//Low quality");
70      }
71      for (i=1; ; i++) {
72 	  s1 = g_strdup_printf("recordFormat%d",i);
73 	  s2 = inifile_get(s1,NULL);
74 	  g_free(s1);
75 	  if (s2 == NULL) {
76 	       s1 = g_strdup_printf("recordFormat%d_Name",i);
77 	       s2 = inifile_get(s1,NULL);
78 	       g_free(s1);
79 	       if (s2 == NULL) break;
80 	       rf = g_malloc(sizeof(*rf));
81 	       s3 = g_strdup_printf("recordFormat%d",i);
82 	       if (!dataformat_get_from_inifile(s3,TRUE,&(rf->fmt))) {
83 		    g_free(s3);
84 		    g_free(rf);
85 		    continue;
86 	       }
87 	       g_free(s3);
88 	       rf->num = i;
89 	       rf->name = g_strdup(s2);
90 	       l2 = g_list_append(l2,rf);
91 	  } else {
92 	       s3 = strchr(s2,'/');
93 	       if (s3 == NULL) continue;
94 	       s3 += 1;
95 	       s4 = strchr(s3,'/');
96 	       if (s4 == NULL) continue;
97 	       s4 += 1;
98 	       s5 = strchr(s4,'/');
99 	       if (s5 == NULL) continue;
100 	       s5 += 1;
101 	       s6 = strchr(s5,'/');
102 	       if (s6 == NULL) continue;
103 	       s6 += 1;
104 	       rf = g_malloc(sizeof(*rf));
105 	       rf->num = i;
106 	       rf->fmt.type = DATAFORMAT_PCM;
107 	       rf->fmt.samplesize = ((guint)strtod(s2,NULL)) / 8;
108 	       rf->fmt.channels = ((guint)strtod(s3,NULL));
109 	       rf->fmt.samplebytes = rf->fmt.samplesize * rf->fmt.channels;
110 	       rf->fmt.samplerate = ((guint)strtod(s4,NULL));
111 	       rf->fmt.sign = FALSE;
112 	       rf->fmt.bigendian = IS_BIGENDIAN;
113 	       rf->fmt.packing = 0;
114 	       for (; *s5 != 0; s5++) {
115 		    if (*s5 == 'B') rf->fmt.bigendian = !IS_BIGENDIAN;
116 		    else if (*s5 == 'S') rf->fmt.sign = TRUE;
117 	       }
118 	       if (rf->fmt.samplesize < 1 || rf->fmt.samplesize > 4 ||
119 		   rf->fmt.channels < 1 || rf->fmt.channels > 8 ||
120 		   rf->fmt.samplerate < 1) {
121 		    g_free(rf);
122 		    continue;
123 	       }
124 	       rf->name = g_strdup(s6);
125 	       l2 = g_list_append(l2,rf);
126 	  }
127      }
128 
129      preset_list = list_object_new_from_list(l2,FALSE);
130      gtk_object_ref(GTK_OBJECT(preset_list));
131 }
132 
set_preset(gchar * name,Dataformat * fmt)133 static void set_preset(gchar *name, Dataformat *fmt)
134 {
135      RecordFormat *rf;
136      int i;
137      gchar *c,*d;
138      GList *l;
139 
140      g_assert(name != NULL);
141 
142      /* If there is an old format with the same name, update it.
143       * Otherwise, set the number to one higher than the
144       * currently highest used number. */
145      i = 0;
146      l = preset_list->list;
147      while (l != NULL) {
148 	  rf = (RecordFormat *)(l->data);
149 	  if (!strcmp(rf->name,name)) {
150 	       if (dataformat_equal(&(rf->fmt),fmt)) return;
151 	       memcpy(&(rf->fmt),fmt,sizeof(Dataformat));
152 	       break;;
153 	  }
154 	  if (rf->num > i) i = rf->num;
155 	  l = l->next;
156      }
157 
158      if (l == NULL) {
159 	  rf = g_malloc(sizeof(*rf));
160 	  rf->name = g_strdup(name);
161 	  rf->fmt = *fmt;
162 	  rf->num = i+1;
163 	  list_object_add(preset_list, rf);
164      }
165 
166      c = g_strdup_printf("recordFormat%d",rf->num);
167      d = g_strdup_printf("%s_Name",c);
168      inifile_set(d,rf->name);
169      dataformat_save_to_inifile(c,fmt,TRUE);
170      g_free(d);
171      g_free(c);
172 
173      if (l != NULL)
174 	  list_object_notify(preset_list,rf);
175 }
176 
compare_preset(gchar * name,Dataformat * fmt)177 static gboolean compare_preset(gchar *name, Dataformat *fmt)
178 {
179      GList *l;
180      RecordFormat *rf;
181      l = preset_list->list;
182      while (l != NULL) {
183 	  rf = (RecordFormat *)(l->data);
184 	  if (!strcmp(rf->name,name))
185 	       return dataformat_equal(&(rf->fmt),fmt);
186 	  l = l->next;
187      }
188      return FALSE;
189 }
190 
reset_peaks(GtkButton * button,gpointer user_data)191 static void reset_peaks(GtkButton *button, gpointer user_data)
192 {
193 	int i;
194 	RecordDialog *rd = RECORD_DIALOG(user_data);
195 	for (i=0; i<8; i++) rd->maxpeak_values[i] = 0.0;
196 }
197 
set_limit_label(RecordDialog * rd)198 static void set_limit_label(RecordDialog *rd)
199 {
200      gchar buf[64];
201      if (rd->limit_record) {
202 	  get_time_s(rd->current_format->samplerate,
203 		     (rd->limit_bytes-rd->written_bytes) /
204 		     rd->current_format->samplebytes, 0, buf);
205 	  gtk_label_set_text(rd->limit_label,buf);
206      } else
207 	  gtk_label_set_text(rd->limit_label,_("(no limit)"));
208 }
209 
process_input(RecordDialog * rd)210 static gboolean process_input(RecordDialog *rd)
211 {
212      guint32 x,y;
213      gchar buf[4096];
214      guint c,d,e;
215      sample_t peak,rms,avg,*sp,*sq,s,pmax;
216      guint32 clip_amount,clip_size;
217      int i;
218      gboolean finish_mode = record_dialog_stopflag;
219 
220      if (rd->current_format == NULL) return FALSE;
221      /* Read input */
222      input_store(rd->databuf);
223 
224      x = ringbuf_available(rd->databuf);
225      /* Round to even samples */
226      x -= x % rd->current_format->samplebytes;
227      /* If we have <0.1 s of data, wait for more. */
228      if ((x < rd->analysis_bytes && !finish_mode) || x==0) return FALSE;
229      /* Send data older than 0.1s straight into the tempfile if we have one */
230      if (!finish_mode)
231 	  x -= rd->analysis_bytes;
232      while (x > 0) {
233 	  y = ringbuf_dequeue(rd->databuf,buf,MIN(x,sizeof(buf)));
234 	  if (rd->tf != NULL && !rd->paused) {
235 	       if (tempfile_write(rd->tf,buf,y)) {
236 		    record_dialog_stopflag = TRUE;
237 		    return FALSE;
238 	       }
239 	       rd->written_bytes += y;
240 	       if ( (rd->limit_record) &&
241 		    (rd->written_bytes >= rd->limit_bytes) ) {
242 		    record_dialog_stopflag = TRUE;
243 		    return TRUE;
244 	       }
245 	  }
246 	  x -= y;
247      }
248      if (finish_mode) return TRUE;
249      /* Analyse data */
250      y = ringbuf_dequeue(rd->databuf,rd->analysis_buf,rd->analysis_bytes);
251      g_assert(y == rd->analysis_bytes);
252      /* First write out the raw data to disk */
253      if (rd->tf != NULL && !rd->paused) {
254 	  if (tempfile_write(rd->tf,rd->analysis_buf,y)) {
255 	       record_dialog_stopflag = TRUE;
256 	       return FALSE;
257 	  }
258 	  rd->written_bytes += y;
259 	  if ( (rd->limit_record) && (rd->written_bytes >= rd->limit_bytes) )
260 	       record_dialog_stopflag = TRUE;
261      }
262      convert_array(rd->analysis_buf,rd->current_format,
263 		   rd->analysis_sbuf,&dataformat_sample_t,
264 		   rd->analysis_samples, DITHER_NONE, NULL);
265      /* Calculate statistics */
266      sq = &(rd->analysis_sbuf[rd->analysis_samples]);
267      d = rd->current_format->channels;
268      for (c=0; c<d; c++) {
269 	  peak = rms = avg = 0.0;
270 	  clip_size = clip_amount = 0;
271 	  sp = &(rd->analysis_sbuf[c]);
272 	  for (; sp<sq; sp+=d) {
273 	       s = *sp;
274 	       avg += s;
275 	       s = fabs(s);
276 	       if (s > peak) peak = s;
277 	       rms += s*s;
278 	       *sp = s; /* Save the abs value for clipping calculation */
279 	  }
280 	  avg /= ((sample_t)rd->analysis_samples);
281 	  rms = sqrt((rms)/ ((sample_t)rd->analysis_samples) - avg*avg);
282 	  pmax = maximum_float_value(&(rd->current_format->fmt));
283 	  /* Since the conversion routines were changed for 1.2.9, this
284 	   * algo can give false alarms, but only when you're _very_ near
285 	   * clipping. */
286 	  if (peak >= pmax) {
287 	       /* Calculate clipping amount and size */
288 	       sp = &(rd->analysis_sbuf[c]);
289 	       while (1) {
290 		    for (; sp<sq; sp+=d)
291 			 if (*sp >= pmax) break;
292 		    if (sp >= sq) break;
293 		    for (e=0; sp<sq && *sp>=pmax; e++,sp+=d) { }
294 		    clip_amount ++;
295 		    clip_size += e*e;
296 	       }
297 	  }
298 	  /* Set the labels and VU meters */
299 	  vu_meter_set_value(rd->meters[c],(float)peak);
300 	  g_snprintf(buf,sizeof(buf),"%.5f",(float)peak);
301 	  gtk_label_set_text(rd->peak_labels[c],buf);
302 	  if (((float)peak) > rd->maxpeak_values[c] )
303 	  {
304 	  	rd->maxpeak_values[c] = (float)peak;
305 		gtk_label_set_text(rd->maxpeak_labels[c],buf);
306 	  }
307 	  g_snprintf(buf,sizeof(buf),"%.5f",(float)rms);
308 	  gtk_label_set_text(rd->rms_labels[c],buf);
309 	  /* This probably needs some tweaking but has to do for now. */
310 	  if (clip_amount == 0)
311 	       gtk_label_set_text(rd->clip_labels[c],_("None"));
312 	  else if (((float)clip_size)/((float)clip_amount) < 2.0
313 		   || (clip_size < rd->analysis_samples / (d * 100)))
314 	       gtk_label_set_text(rd->clip_labels[c],_("Mild"));
315 	  else
316 	       gtk_label_set_text(rd->clip_labels[c],_("Heavy"));
317      }
318      if (rd->tf) {
319 	  get_time(rd->current_format->samplerate,
320 		   rd->written_bytes/rd->current_format->samplebytes,
321 		   0,buf,default_time_mode);
322 	  gtk_label_set_text(rd->time_label,buf);
323 	  g_snprintf(buf,200,"%" OFF_T_FORMAT "",
324 		     (OFF_T_FTYPE)rd->written_bytes);
325 	  gtk_label_set_text(rd->bytes_label,buf);
326 	  get_time_s(rd->current_format->samplerate,
327 		     rd->written_bytes/rd->current_format->samplebytes,
328 		     0, buf);
329 	  if ( strcmp(buf, GTK_WINDOW(rd)->title) ) {
330 	       gtk_window_set_title(GTK_WINDOW(rd),buf);
331 	       /* Also update the remaining time here */
332 	       set_limit_label(rd);
333 	  }
334 	  i = input_overrun_count();
335 	  if (i>=0) {
336 	       i -= rd->overruns_before_start;
337 	       while (i > rd->overruns) {
338 		    if (rd->overruns < 10)
339 			 rd->overrun_locs[rd->overruns] = rd->written_bytes;
340 		    rd->overruns++;
341 	       }
342 	       g_snprintf(buf,sizeof(buf),"%d",i);
343 	       gtk_label_set_text(rd->overruns_label,buf);
344 	  }
345 
346      }
347      return TRUE;
348 }
349 
input_ready_func(void)350 void input_ready_func(void)
351 {
352      process_input(current_dialog);
353 }
354 
record_dialog_format_changed(Combo * combo,gpointer user_data)355 static void record_dialog_format_changed(Combo *combo, gpointer user_data)
356 {
357      RECORD_DIALOG(user_data)->format_changed = TRUE;
358 }
359 
other_dialog_get_name(void)360 static gchar *other_dialog_get_name(void)
361 {
362      gchar *c,*d;
363      c = (gchar *)gtk_entry_get_text(other_dialog.name_entry);
364      while (*c == ' ') c++; /* Skip beginning spaces */
365      if (*c == 0) return NULL;
366      c = g_strdup(c);
367      /* Trim ending spaces */
368      d = strchr(c,0);
369      d--;
370      while (*d == ' ') { *d = 0; d--; }
371      return c;
372 }
373 
other_dialog_ok(GtkButton * button,gpointer user_data)374 static void other_dialog_ok(GtkButton *button, gpointer user_data)
375 {
376      RecordDialog *rd = RECORD_DIALOG(user_data);
377      Dataformat df;
378      gchar *c;
379 
380      if (format_selector_check(other_dialog.fs)) return;
381 
382      format_selector_get(other_dialog.fs,&df);
383 
384      c = other_dialog_get_name();
385      if (c != NULL && compare_preset(c,&df))
386 	  record_format_combo_set_named_preset(rd->format_combo,c);
387      else
388 	  record_format_combo_set_format(rd->format_combo,&df);
389      g_free(c);
390 }
391 
other_dialog_addpreset(GtkButton * button,gpointer user_data)392 static void other_dialog_addpreset(GtkButton *button, gpointer user_data)
393 {
394      gchar *name;
395      Dataformat df;
396 
397      if (format_selector_check(other_dialog.fs)) return;
398      format_selector_get(other_dialog.fs,&df);
399 
400      name = other_dialog_get_name();
401      g_assert(name != NULL);
402 
403      set_preset(name,&df);
404      /* b = record_format_combo_set_named_preset(rd->format_combo,name);
405 	g_assert(b); */
406      g_free(name);
407 }
408 
other_dialog_delete(GtkWidget * widget,GdkEvent * event,gpointer user_data)409 static gboolean other_dialog_delete(GtkWidget *widget, GdkEvent *event,
410 				    gpointer user_data)
411 {
412      return FALSE;
413 }
414 
other_dialog_name_changed(GtkEditable * editable,gpointer user_data)415 static void other_dialog_name_changed(GtkEditable *editable,
416 				      gpointer user_data)
417 {
418      gchar *c;
419      GList *l;
420      RecordFormat *rf;
421 
422      c = other_dialog_get_name();
423      for (l=preset_list->list; l!=NULL; l=l->next) {
424 	  rf = (RecordFormat *)(l->data);
425 	  if (rf->name != NULL && c != NULL && !strcmp(rf->name,c))
426 	       break;
427      }
428      if (l != NULL) {
429 	  gtk_label_set_text(other_dialog.set_button_label,
430 			     _("Update preset"));
431 	  gtk_widget_set_sensitive(GTK_WIDGET(other_dialog.set_button_button),
432 				   TRUE);
433      } else if (c != NULL) {
434 	  gtk_label_set_text(other_dialog.set_button_label,
435 			     _("Add preset"));
436 	  gtk_widget_set_sensitive(GTK_WIDGET(other_dialog.set_button_button),
437 				   TRUE);
438      } else {
439 	  gtk_widget_set_sensitive(GTK_WIDGET(other_dialog.set_button_button),
440 				   FALSE);
441      }
442      g_free(c);
443 }
444 
other_dialog_build_preset_list(RecordDialog * rd)445 static GtkWidget *other_dialog_build_preset_list(RecordDialog *rd)
446 {
447      GtkWidget *a,*x=NULL;
448      GList *l;
449      RecordFormat *rf;
450      gchar *n;
451      n = record_format_combo_get_preset_name(rd->format_combo);
452      for (l=preset_list->list; l!=NULL; l=l->next) {
453 	  rf = (RecordFormat *)(l->data);
454 	  if (rf->name == NULL) continue;
455 	  a = gtk_list_item_new_with_label(rf->name);
456 	  gtk_container_add(GTK_CONTAINER(other_dialog.preset_list),a);
457 	  gtk_object_set_data(GTK_OBJECT(a),"fmt",rf);
458 	  if (n != NULL && rf->name != NULL && !strcmp(n,rf->name))
459 	       x = a;
460      }
461      return x;
462 }
463 
other_dialog_select_child(GtkList * list,GtkWidget * widget,gpointer user_data)464 static void other_dialog_select_child(GtkList *list, GtkWidget *widget,
465 				      gpointer user_data)
466 {
467      RecordFormat *rf;
468      rf = gtk_object_get_data(GTK_OBJECT(widget),"fmt");
469      format_selector_set(other_dialog.fs, &(rf->fmt));
470      gtk_entry_set_text(other_dialog.name_entry, rf->name);
471 }
472 
other_dialog_preset_item_added(ListObject * lo,RecordFormat * rf,gpointer user_data)473 static void other_dialog_preset_item_added(ListObject *lo, RecordFormat *rf,
474 					   gpointer user_data)
475 {
476      GtkWidget *a;
477      a = gtk_list_item_new_with_label(rf->name);
478      gtk_container_add(GTK_CONTAINER(other_dialog.preset_list),a);
479      gtk_object_set_data(GTK_OBJECT(a),"fmt",rf);
480      gtk_widget_show(a);
481 }
482 
other_dialog_preset_item_removed(ListObject * lo,gpointer item,gpointer user_data)483 static void other_dialog_preset_item_removed(ListObject *lo, gpointer item,
484 					     gpointer user_data)
485 {
486      GList *l;
487      gpointer p;
488      l = gtk_container_get_children(GTK_CONTAINER(other_dialog.preset_list));
489      for (; l!=NULL; l=l->next) {
490 	  p = gtk_object_get_data(GTK_OBJECT(l->data),"fmt");
491 	  if (p == item) {
492 	       gtk_container_remove(GTK_CONTAINER(other_dialog.preset_list),
493 				    GTK_WIDGET(l->data));
494 	       break;
495 	  }
496      }
497      g_list_free(l);
498 
499 }
500 
other_format_dialog(RecordFormatCombo * rfc,RecordDialog * rd)501 static void other_format_dialog(RecordFormatCombo *rfc, RecordDialog *rd)
502 {
503      GtkWidget *a,*b,*c,*d,*e,*f,*item;
504      GtkAccelGroup* ag;
505      GtkRequisition req;
506 #if GTK_MAJOR_VERSION > 1
507      static GtkWindowGroup *wg = NULL;
508 #endif
509 
510 
511      ag = gtk_accel_group_new();
512 
513      other_dialog.wnd = GTK_WINDOW(gtk_window_new(GTK_WINDOW_DIALOG));
514      gtk_window_set_title(other_dialog.wnd,_("Custom format"));
515 #if GTK_MAJOR_VERSION < 2
516      gtk_window_set_modal(other_dialog.wnd,TRUE);
517 #else
518      if (wg == NULL) wg = gtk_window_group_new();
519      gtk_window_group_add_window(wg,other_dialog.wnd);
520 #endif
521      gtk_window_set_transient_for(other_dialog.wnd,GTK_WINDOW(rd));
522 
523      other_dialog.fs = FORMAT_SELECTOR(format_selector_new(TRUE));
524 
525      other_dialog.name_entry = GTK_ENTRY(gtk_entry_new());
526 
527      other_dialog.preset_list = GTK_LIST(gtk_list_new());
528      item = other_dialog_build_preset_list(rd);
529      gtk_signal_connect_while_alive
530 	  (GTK_OBJECT(preset_list),"item_added",
531 	   GTK_SIGNAL_FUNC(other_dialog_preset_item_added),other_dialog.wnd,
532 	   GTK_OBJECT(other_dialog.wnd));
533      gtk_signal_connect_while_alive
534 	  (GTK_OBJECT(preset_list),"item_removed",
535 	   GTK_SIGNAL_FUNC(other_dialog_preset_item_removed),other_dialog.wnd,
536 	   GTK_OBJECT(other_dialog.wnd));
537 
538      a = GTK_WIDGET(other_dialog.wnd);
539      gtk_container_set_border_width(GTK_CONTAINER(a),10);
540      gtk_signal_connect(GTK_OBJECT(a),"delete_event",
541 			GTK_SIGNAL_FUNC(other_dialog_delete),NULL);
542      b = gtk_vbox_new(FALSE,6);
543      gtk_container_add(GTK_CONTAINER(a),b);
544      c = gtk_hbox_new(FALSE,6);
545      gtk_container_add(GTK_CONTAINER(b),c);
546      d = gtk_vbox_new(FALSE,6);
547      gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
548      e = GTK_WIDGET(other_dialog.fs);
549      gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
550      e = gtk_hseparator_new();
551      gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
552      e = gtk_label_new(_("The sign and endian-ness can usually be left at their "
553 		       "defaults, but should be changed if you're unable to "
554 		       "record or get bad sound."));
555      gtk_label_set_line_wrap(GTK_LABEL(e),TRUE);
556      gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
557 
558      /*
559      c = gtk_label_new(_("To add this format to the presets, enter a name "
560 		       "below. Otherwise, leave it blank."));
561      gtk_label_set_line_wrap(GTK_LABEL(c),TRUE);
562      gtk_container_add(GTK_CONTAINER(b),c);
563      */
564      e = gtk_hbox_new(FALSE,4);
565      gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
566      f = gtk_label_new(_("Name :"));
567      gtk_container_add(GTK_CONTAINER(e),f);
568      f = GTK_WIDGET(other_dialog.name_entry);
569      gtk_container_add(GTK_CONTAINER(e),f);
570      e = gtk_hseparator_new();
571      gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
572      d = gtk_vseparator_new();
573      gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
574 
575      d = gtk_vbox_new(FALSE,6);
576      gtk_container_add(GTK_CONTAINER(c),d);
577 
578      e = gtk_label_new(_("Presets:"));
579      gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
580 
581      e = gtk_scrolled_window_new(NULL,NULL);
582      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(e),GTK_POLICY_NEVER,
583 				    GTK_POLICY_AUTOMATIC);
584      gtk_container_add(GTK_CONTAINER(d),e);
585 
586      f = GTK_WIDGET(other_dialog.preset_list);
587      gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(e),f);
588 
589      c = gtk_hseparator_new();
590      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
591      c = gtk_hbutton_box_new();
592      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
593      d = gtk_button_new_with_label(_("Set format"));
594      gtk_widget_add_accelerator (d, "clicked", ag, GDK_KP_Enter, 0,
595 				 (GtkAccelFlags) 0);
596      gtk_widget_add_accelerator (d, "clicked", ag, GDK_Return, 0,
597 				 (GtkAccelFlags) 0);
598      gtk_container_add(GTK_CONTAINER(c),d);
599      gtk_signal_connect(GTK_OBJECT(d),"clicked",
600 			GTK_SIGNAL_FUNC(other_dialog_ok),rd);
601      d = gtk_button_new_with_label(_("Add/Update preset"));
602      gtk_widget_set_sensitive(d,FALSE);
603      gtk_widget_size_request(d,&req);
604      gtk_widget_set_size_request(d,req.width,req.height);
605      gtk_container_add(GTK_CONTAINER(c),d);
606      gtk_signal_connect(GTK_OBJECT(d),"clicked",
607 			GTK_SIGNAL_FUNC(other_dialog_addpreset),rd);
608      other_dialog.set_button_button = GTK_BUTTON(d);
609      other_dialog.set_button_label = GTK_LABEL(gtk_bin_get_child(GTK_BIN(d)));
610      d = gtk_button_new_with_label(_("Close"));
611      gtk_widget_add_accelerator (d, "clicked", ag, GDK_Escape, 0,
612 				 (GtkAccelFlags) 0);
613      gtk_container_add(GTK_CONTAINER(c),d );
614      gtk_signal_connect_object(GTK_OBJECT(d),"clicked",
615 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
616 			       GTK_OBJECT(a));
617      gtk_widget_show_all(a);
618      gtk_window_add_accel_group(GTK_WINDOW (a), ag);
619 
620      gtk_signal_connect(GTK_OBJECT(other_dialog.wnd),"delete_event",
621 			GTK_SIGNAL_FUNC(other_dialog_delete),NULL);
622      gtk_signal_connect(GTK_OBJECT(other_dialog.preset_list),"select_child",
623 			GTK_SIGNAL_FUNC(other_dialog_select_child),rd);
624      gtk_signal_connect(GTK_OBJECT(other_dialog.name_entry),"changed",
625 			GTK_SIGNAL_FUNC(other_dialog_name_changed),rd);
626 
627      if (item != NULL) gtk_list_select_child(other_dialog.preset_list,item);
628 
629      gtk_signal_connect_object_while_alive(GTK_OBJECT(rd),"destroy",
630 					   GTK_SIGNAL_FUNC(gtk_widget_destroy),
631 					   GTK_OBJECT(other_dialog.wnd));
632 }
633 
update_limit(RecordDialog * rd)634 static void update_limit(RecordDialog *rd)
635 {
636      gdouble d;
637      if (rd->tf == NULL) return;
638      d = (gdouble)rd->limit_seconds;
639      d *= (gdouble)(rd->current_format->samplerate);
640      d *= (gdouble)(rd->current_format->samplebytes);
641      rd->limit_bytes = (off_t)d;
642      set_limit_label(rd);
643 }
644 
set_time_limit(GtkButton * button,gpointer user_data)645 static void set_time_limit(GtkButton *button, gpointer user_data)
646 {
647      gfloat f;
648      gchar buf[64];
649      RecordDialog *rd = RECORD_DIALOG(user_data);
650 
651      f = parse_time((gchar *)gtk_entry_get_text(rd->limit_entry));
652 
653      if (f < 0.0) {
654 	  popup_error(_("Invalid time value. Time must be specified in the form"
655 		      " (HH')MM:SS(.mmmm)"));
656 	  return;
657      }
658 
659      rd->limit_record = TRUE;
660      rd->limit_seconds = f;
661      get_time_l(1000,(off_t)(f*1000.0),(off_t)(f*1000.0),buf);
662      gtk_label_set_text(rd->limit_set_label, buf);
663      gtk_widget_set_sensitive(GTK_WIDGET(rd->disable_limit_button),TRUE);
664      update_limit(rd);
665 }
666 
disable_time_limit(GtkButton * button,gpointer user_data)667 static void disable_time_limit(GtkButton *button, gpointer user_data)
668 {
669      RecordDialog *rd = RECORD_DIALOG(user_data);
670      rd->limit_record = FALSE;
671      gtk_label_set_text(rd->limit_set_label,_("(no limit)"));
672      gtk_widget_set_sensitive(GTK_WIDGET(rd->disable_limit_button),FALSE);
673 }
674 
record_dialog_set_format(RecordDialog * rd)675 static gboolean record_dialog_set_format(RecordDialog *rd)
676 {
677      Dataformat *df;
678      GtkWidget *a,*b;
679      gint i;
680 
681      /* printf("record_dialog_set_format: %s fresh=%d\n",rf->name,
682 	rd->format_combo_fresh); */
683      input_stop();
684      rd->current_format = NULL;
685      if (rd->vu_frame->child != NULL)
686 	  gtk_container_remove(GTK_CONTAINER(rd->vu_frame),
687 			       rd->vu_frame->child);
688      g_free(rd->peak_labels);
689      g_free(rd->maxpeak_labels);
690      g_free(rd->rms_labels);
691      g_free(rd->clip_labels);
692      g_free(rd->meters);
693      rd->peak_labels = NULL;
694      rd->maxpeak_labels = NULL;
695      rd->rms_labels = NULL;
696      rd->clip_labels = NULL;
697      rd->meters = NULL;
698      gtk_label_set_text(rd->status_label,_("Format not selected"));
699      gtk_widget_set_sensitive(rd->record_button,FALSE);
700      gtk_widget_set_sensitive(rd->reset_button,FALSE);
701 
702      df = record_format_combo_get_format(rd->format_combo);
703      i = input_select_format(df,FALSE,input_ready_func);
704      if (i < 0) {
705 	  user_error(_("This format is not supported by the input driver!"));
706 	  return TRUE;
707      } else if (i > 0)
708 	  return TRUE;
709 
710      gtk_label_set_text(rd->status_label,_("Ready for recording"));
711      record_format_combo_store(rd->format_combo);
712      rd->current_format = &(rd->format_combo->stored_selection_format);
713      rd->peak_labels = g_malloc(df->channels*sizeof(GtkLabel *));
714      rd->maxpeak_labels = g_malloc(df->channels*sizeof(GtkLabel *));
715      rd->clip_labels = g_malloc(df->channels*sizeof(GtkLabel *));
716      rd->rms_labels = g_malloc(df->channels*sizeof(GtkLabel *));
717      rd->meters = g_malloc(df->channels*sizeof(VuMeter *));
718      memset(rd->maxpeak_values,0,sizeof(rd->maxpeak_values));
719      a = gtk_table_new(6*((df->channels+1)/2),4,FALSE);
720      gtk_container_set_border_width(GTK_CONTAINER(a),4);
721 
722      for (i=0; i*2<df->channels; i++) {
723 	  attach_label(_("Peak: "),a,i*6+2,0);
724 	  attach_label(_("Peak max: "),a,i*6+3,0);
725 	  attach_label(_("RMS: "),a,i*6+4,0);
726 	  attach_label(_("Clipping: "),a,i*6+5,0);
727      }
728      for (i=0; i<df->channels; i++) {
729 	  b = gtk_label_new(channel_name(i,df->channels));
730 	  gtk_table_attach(GTK_TABLE(a),b,(i&1)+1,(i&1)+2,(i/2)*6+0,(i/2)*6+1,
731 			   0,0,0,0);
732 	  b = vu_meter_new(0.0);
733 	  rd->meters[i] = VU_METER(b);
734 	  gtk_table_attach(GTK_TABLE(a),b,(i&1)+1,(i&1)+2,(i/2)*6+1,(i/2)*6+2,
735 			   0,0,0,0);
736 	  rd->peak_labels[i] = attach_label("",a,(i/2)*6+2,(i&1)+1);
737 	  rd->maxpeak_labels[i] = attach_label("",a,(i/2)*6+3,(i&1)+1);
738 	  rd->rms_labels[i] = attach_label("",a,(i/2)*6+4,(i&1)+1);
739 	  rd->clip_labels[i] = attach_label(_("None"),a,(i/2)*6+5,(i&1)+1);
740      }
741 
742      gtk_table_set_col_spacings(GTK_TABLE(a),5);
743      gtk_table_set_row_spacings(GTK_TABLE(a),3);
744      gtk_container_add(GTK_CONTAINER(rd->vu_frame),a);
745      gtk_widget_show_all(a);
746 
747      gtk_widget_set_sensitive(rd->record_button,TRUE);
748      gtk_widget_set_sensitive(rd->reset_button,TRUE);
749 
750      /* Create a 2 second ring buffer */
751      if (rd->databuf != NULL) {
752 	  ringbuf_free(rd->databuf);
753 	  g_free(rd->analysis_buf);
754 	  g_free(rd->analysis_sbuf);
755      }
756      rd->databuf = ringbuf_new(2*df->samplebytes*df->samplerate);
757      /* Do analysis on 0.1 s parts. */
758      rd->analysis_bytes = df->samplebytes * df->samplerate / 10;
759      rd->analysis_samples = df->channels * df->samplerate / 10;
760      rd->analysis_buf = g_malloc(rd->analysis_bytes);
761      rd->analysis_sbuf = g_malloc(sizeof(sample_t) * rd->analysis_samples);
762 
763      /* Call process_input manually one time here
764       * (required for some sound drivers to start recording) */
765      process_input(rd);
766 
767      return FALSE;
768 }
769 
check_format_change(RecordDialog * rd)770 static void check_format_change(RecordDialog *rd)
771 {
772      if (!rd->format_changed)
773 	  return;
774 
775      rd->format_changed = FALSE;
776      record_dialog_set_format(rd);
777 }
778 
record_dialog_start(GtkButton * button,gpointer user_data)779 static void record_dialog_start(GtkButton *button, gpointer user_data)
780 {
781      RecordDialog *rd = RECORD_DIALOG(user_data);
782      GtkRequisition req;
783      int i;
784      gchar *c;
785 
786      if (rd->tf != NULL) {
787 	  /* This is a hack to prevent the window from resizing when we
788 	   * change the button's caption */
789 	  gtk_widget_size_request(rd->record_button,&req);
790 	  gtk_widget_set_usize(rd->record_button,req.width,req.height);
791 
792 	  /* Toggle pause mode */
793 	  rd->paused = !rd->paused;
794 	  gtk_label_set_text(GTK_LABEL(GTK_BIN(rd->record_button)->child),
795 			     rd->paused?_("Resume recording"):_("Pause recording"));
796 	  gtk_label_set_text(rd->status_label,rd->paused?
797 			     translate_strip(N_("RecordStatus|Paused")):
798 			     translate_strip(N_("RecordStatus|Recording")));
799 	  return;
800      }
801 
802      inifile_set_gboolean("limitRecord",rd->limit_record);
803      inifile_set_gfloat( "limitSecs",rd->limit_seconds);
804 
805      c = record_format_combo_get_preset_name(rd->format_combo);
806      inifile_set("lastRecordFormat",c);
807      if (c == NULL) {
808 	  dataformat_save_to_inifile("lastRecordFormat",
809 				     record_format_combo_get_format
810 				     (rd->format_combo), TRUE);
811      }
812 
813      gtk_widget_set_sensitive(GTK_WIDGET(rd->format_combo),FALSE);
814      gtk_label_set_text(GTK_LABEL(GTK_BIN(rd->record_button)->child),
815 			_("Pause recording"));
816      rd->paused = FALSE;
817      gtk_label_set_text(GTK_LABEL(GTK_BIN(rd->close_button)->child),
818 			_("Finish"));
819      rd->tf = tempfile_init(rd->current_format,TRUE);
820      rd->written_bytes = 0;
821      i = input_overrun_count();
822      gtk_label_set_text(rd->status_label,
823 			translate_strip(N_("RecordStatus|Recording")));
824      if (i>-1) {
825 	  rd->overruns_before_start = i;
826 	  gtk_label_set_text(rd->overruns_title,_("Overruns: "));
827      }
828      rd->overruns = 0;
829      gtk_label_set_text(rd->bytes_text_label,_("Bytes written: "));
830      gtk_label_set_text(rd->limit_text_label,_("Auto stop in: "));
831      update_limit(rd);
832 }
833 
record_dialog_close(GtkButton * button,gpointer user_data)834 static void record_dialog_close(GtkButton *button, gpointer user_data)
835 {
836      record_dialog_stopflag = TRUE;
837 }
838 
record_dialog_delete_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)839 static gboolean record_dialog_delete_event(GtkWidget *widget, GdkEvent *event,
840 					   gpointer user_data)
841 {
842      record_dialog_stopflag = TRUE;
843      return TRUE;
844 }
845 
record_dialog_init(RecordDialog * obj)846 void record_dialog_init(RecordDialog *obj)
847 {
848      GtkWidget *a,*b,*c,*d,*e;
849      GtkAccelGroup* ag;
850      GtkRequisition req;
851      gchar limitbuf[64];
852      gchar *s1;
853      GList *dp;
854      gboolean complete;
855      Dataformat df,*dfp;
856 
857      ag = gtk_accel_group_new();
858 
859      obj->format_changed = FALSE;
860      obj->current_format = NULL;
861      obj->databuf = NULL;
862      obj->meters = NULL;
863      obj->peak_labels = obj->maxpeak_labels = obj->clip_labels = NULL;
864      obj->rms_labels = NULL;
865      obj->tf = NULL;
866      obj->written_bytes = 0;
867      obj->analysis_buf = NULL;
868      obj->analysis_sbuf = NULL;
869      obj->limit_record = inifile_get_gboolean("limitRecord",FALSE);
870      obj->limit_seconds = inifile_get_gfloat("limitSecs",3600.0);
871      if (obj->limit_seconds < 0.0) obj->limit_seconds = 3600.0;
872      get_time_l(1000,(off_t)(obj->limit_seconds*1000.0),0,limitbuf);
873 
874      gtk_window_set_title(GTK_WINDOW(obj),_("Record"));
875      gtk_window_set_modal(GTK_WINDOW(obj),TRUE);
876      gtk_window_set_default_size(GTK_WINDOW(obj),320,400);
877      gtk_window_set_position(GTK_WINDOW(obj),GTK_WIN_POS_CENTER);
878      gtk_container_set_border_width(GTK_CONTAINER(obj),10);
879 
880      gtk_signal_connect(GTK_OBJECT(obj),"delete_event",
881 			GTK_SIGNAL_FUNC(record_dialog_delete_event),NULL);
882 
883 
884 
885      build_preset_list();
886      dp = input_supported_formats(&complete);
887      obj->driver_presets = list_object_new_from_list(dp,FALSE);
888      gtk_object_ref(GTK_OBJECT(obj->driver_presets));
889      gtk_object_sink(GTK_OBJECT(obj->driver_presets));
890 
891      /* Add components */
892      a = gtk_vbox_new(FALSE,10);
893      gtk_container_add(GTK_CONTAINER(obj),a);
894      b = gtk_frame_new(_("Recording settings"));
895      gtk_box_pack_start(GTK_BOX(a),b,FALSE,FALSE,0);
896      c = gtk_vbox_new(FALSE,0);
897      gtk_container_set_border_width(GTK_CONTAINER(c),5);
898      gtk_container_add(GTK_CONTAINER(b),c);
899      d = gtk_hbox_new(FALSE,0);
900      gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
901      e = gtk_label_new(_("Sample format: "));
902      gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
903 
904      e = record_format_combo_new(complete ? list_object_new(FALSE):preset_list,
905 				 obj->driver_presets, !complete);
906      gtk_box_pack_start(GTK_BOX(d),e,TRUE,TRUE,0);
907      obj->format_combo = RECORD_FORMAT_COMBO(e);
908      gtk_signal_connect(GTK_OBJECT(e),"format_changed",
909 			GTK_SIGNAL_FUNC(record_dialog_format_changed),obj);
910      gtk_signal_connect(GTK_OBJECT(e),"format_dialog_request",
911 			GTK_SIGNAL_FUNC(other_format_dialog),obj);
912 
913      d = gtk_hbox_new(FALSE,3);
914      gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,6);
915 
916      e = gtk_label_new(_("Time limit: "));
917      gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
918      e = gtk_label_new(_("(no limit)"));
919      obj->limit_set_label = GTK_LABEL(e);
920      if (obj->limit_record)
921 	  gtk_label_set_text(obj->limit_set_label, limitbuf);
922      gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
923 
924      e = gtk_button_new_with_label(_("Disable"));
925      obj->disable_limit_button = GTK_BUTTON(e);
926      gtk_widget_set_sensitive(GTK_WIDGET(e),obj->limit_record);
927      gtk_signal_connect(GTK_OBJECT(e),"clicked",
928 			GTK_SIGNAL_FUNC(disable_time_limit),obj);
929      gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
930      e = gtk_button_new_with_label(_("Set"));
931      gtk_signal_connect(GTK_OBJECT(e),"clicked",
932 			GTK_SIGNAL_FUNC(set_time_limit),obj);
933      gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
934      e = gtk_entry_new();
935      obj->limit_entry = GTK_ENTRY(e);
936      gtk_entry_set_text(obj->limit_entry, limitbuf );
937      /* Max length = "hhh'mm:ss.mmm" */
938      gtk_entry_set_max_length( obj->limit_entry, 14);
939      gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
940 
941 
942      b = gtk_frame_new(_("Input levels"));
943      obj->vu_frame = GTK_BIN(b);
944      gtk_box_pack_start(GTK_BOX(a),b,TRUE,TRUE,0);
945      b = gtk_table_new(3,4,FALSE);
946      gtk_box_pack_start(GTK_BOX(a),b,FALSE,FALSE,0);
947      attach_label(_("Recording status: "),b,0,0);
948      obj->status_label = GTK_LABEL(gtk_label_new(_("Format not selected")));
949      gtk_table_attach(GTK_TABLE(b),GTK_WIDGET(obj->status_label),1,4,0,1,
950 		      GTK_FILL,0,0,0);
951      gtk_misc_set_alignment(GTK_MISC(obj->status_label),0.0,0.5);
952      attach_label(_("Time recorded: "),b,1,0);
953      obj->time_label = attach_label(_("N/A"),b,1,1);
954      gtk_widget_size_request(GTK_WIDGET(obj->time_label),&req);
955      /* Stops wobble during recording */
956      gtk_widget_set_usize(GTK_WIDGET(obj->time_label),150,req.height);
957 
958      obj->limit_text_label = attach_label("",b,2,0);
959      obj->limit_label = attach_label("",b,2,1);
960      obj->bytes_text_label = attach_label("",b,1,2);
961      obj->bytes_label = attach_label("",b,1,3);
962      obj->overruns_title = attach_label("",b,2,2);
963      obj->overruns_label = attach_label("",b,2,3);
964      b = gtk_hbutton_box_new();
965      gtk_box_pack_start(GTK_BOX(a),b,FALSE,FALSE,0);
966      c = gtk_button_new_with_label(_("Start recording"));
967      gtk_widget_add_accelerator (c, "clicked", ag, GDK_KP_Enter, 0,
968 				 (GtkAccelFlags) 0);
969      gtk_widget_add_accelerator (c, "clicked", ag, GDK_Return, 0,
970 				 (GtkAccelFlags) 0);
971      gtk_widget_set_sensitive(c,FALSE);
972      gtk_signal_connect(GTK_OBJECT(c),"clicked",
973 			GTK_SIGNAL_FUNC(record_dialog_start),obj);
974      obj->record_button = GTK_WIDGET(c);
975      gtk_container_add(GTK_CONTAINER(b),c);
976 
977      c = gtk_button_new_with_label(_("Reset max peaks"));
978      gtk_widget_set_sensitive(c,FALSE);
979      gtk_signal_connect(GTK_OBJECT(c),"clicked", GTK_SIGNAL_FUNC(reset_peaks),obj);
980      obj->reset_button = GTK_WIDGET(c);
981      gtk_container_add(GTK_CONTAINER(b),c);
982 
983      c = gtk_button_new_with_label(_("Launch mixer"));
984      gtk_signal_connect(GTK_OBJECT(c),"clicked",GTK_SIGNAL_FUNC(launch_mixer),
985 			NULL);
986      gtk_container_add(GTK_CONTAINER(b),c);
987      c = gtk_button_new_with_label(_("Close"));
988      gtk_widget_add_accelerator (c, "clicked", ag, GDK_Escape, 0,
989 				 (GtkAccelFlags) 0);
990      gtk_signal_connect(GTK_OBJECT(c),"clicked",
991 			GTK_SIGNAL_FUNC(record_dialog_close),obj);
992      gtk_container_add(GTK_CONTAINER(b),c);
993      obj->close_button = c;
994 
995      gtk_widget_show_all(a);
996      gtk_window_add_accel_group(GTK_WINDOW (obj), ag);
997 
998      /* Special case: Only one format supported. Choose that format and
999       * make the format combo insensitive */
1000      if (complete && list_object_get_size(obj->driver_presets)==1) {
1001 	  dfp = (Dataformat *)list_object_get(obj->driver_presets,0);
1002 	  record_format_combo_set_format(obj->format_combo,dfp);
1003 	  gtk_widget_set_sensitive(GTK_WIDGET(obj->format_combo),FALSE);
1004 	  return;
1005      }
1006 
1007      /* Set the last used format */
1008      s1 = inifile_get("lastRecordFormat",NULL);
1009      if (s1 != NULL) {
1010 	  record_format_combo_set_named_preset(obj->format_combo,s1);
1011      } else {
1012 	  if (dataformat_get_from_inifile("lastRecordFormat",TRUE,&df))
1013 	       record_format_combo_set_format(obj->format_combo,&df);
1014      }
1015 }
1016 
record_dialog_destroy(GtkObject * obj)1017 static void record_dialog_destroy(GtkObject *obj)
1018 {
1019      RecordDialog *rd = RECORD_DIALOG(obj);
1020      if (rd->databuf) ringbuf_free(rd->databuf);
1021      rd->databuf = NULL;
1022      g_free(rd->analysis_buf);
1023      rd->analysis_buf = NULL;
1024      g_free(rd->analysis_sbuf);
1025      rd->analysis_sbuf = NULL;
1026      parent_class->destroy(obj);
1027      if (rd->driver_presets != NULL) {
1028 	  list_object_foreach(rd->driver_presets, (GFunc)g_free, NULL);
1029 	  list_object_clear(rd->driver_presets, FALSE);
1030 	  gtk_object_unref(GTK_OBJECT(rd->driver_presets));
1031 	  rd->driver_presets = NULL;
1032      }
1033 }
1034 
record_dialog_class_init(GtkObjectClass * klass)1035 static void record_dialog_class_init(GtkObjectClass *klass)
1036 {
1037      parent_class = gtk_type_class(gtk_window_get_type());
1038      klass->destroy = record_dialog_destroy;
1039 }
1040 
record_dialog_get_type(void)1041 GtkType record_dialog_get_type(void)
1042 {
1043      static GtkType id = 0;
1044      if (!id) {
1045 	  GtkTypeInfo info = {
1046 	       "RecordDialog",
1047 	       sizeof(RecordDialog),
1048 	       sizeof(RecordDialogClass),
1049 	       (GtkClassInitFunc) record_dialog_class_init,
1050 	       (GtkObjectInitFunc) record_dialog_init
1051 	  };
1052 	  id = gtk_type_unique(gtk_window_get_type(),&info);
1053      }
1054      return id;
1055 }
1056 
record_dialog_execute(int * noverruns,off_t overrun_locs[10])1057 Chunk *record_dialog_execute(int *noverruns, off_t overrun_locs[10])
1058 {
1059      RecordDialog *rd;
1060      Chunk *ds;
1061      int i;
1062 
1063      rd = RECORD_DIALOG(gtk_type_new(record_dialog_get_type()));
1064      record_dialog_stopflag = FALSE;
1065      current_dialog = rd;
1066      gtk_widget_show(GTK_WIDGET(rd));
1067      while (!record_dialog_stopflag) {
1068 	  mainloop();
1069 	  check_format_change(rd);
1070      }
1071      if (rd->tf != NULL) {
1072 	  input_stop_hint();
1073 	  i = 0; /* Just to avoid infinite loops */
1074 	  while (process_input(rd) && i<128) { i++; }
1075 	  input_stop();
1076 	  ds = tempfile_finished(rd->tf);
1077 	  *noverruns = rd->overruns;
1078 	  memcpy(overrun_locs,rd->overrun_locs,10*sizeof(off_t));
1079 	  gtk_widget_destroy(GTK_WIDGET(rd));
1080 	  return ds;
1081      } else {
1082 	  input_stop();
1083 	  gtk_widget_destroy(GTK_WIDGET(rd));
1084 	  return NULL;
1085      }
1086 }
1087