1 /*
2  * Copyright (C) 2002 2003 2004 2005 2006 2007 2008 2009 2010, Magnus Hjorth
3  * Copyright (C) 2011 2012 2013 2018, Magnus Hjorth
4  *
5  * This file is part of mhWaveEdit.
6  *
7  * mhWaveEdit is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * mhWaveEdit is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with mhWaveEdit; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 
23 #include <config.h>
24 
25 #include <string.h>
26 #include <math.h>
27 #include <sys/time.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30 #include "gtkfiles.h"
31 #include "filetypes.h"
32 #include "chunkview.h"
33 #include "mainwindow.h"
34 #include "recorddialog.h"
35 #include "configdialog.h"
36 #include "gotodialog.h"
37 #include "chunk.h"
38 #include "um.h"
39 #include "main.h"
40 #include "inifile.h"
41 #include "player.h"
42 #include "sound.h"
43 #include "effectbrowser.h"
44 #include "soxdialog.h"
45 #include "help.h"
46 #include "ladspadialog.h"
47 #include "gettext.h"
48 #include "bitmap.h"
49 
50 #include "button_open.xpm"
51 #include "button_save.xpm"
52 #include "button_undo.xpm"
53 #include "button_redo.xpm"
54 #include "button_cut.xpm"
55 #include "button_copy.xpm"
56 #include "button_paste.xpm"
57 #include "button_pasteover.xpm"
58 #include "button_delete.xpm"
59 #include "button_cursorstart.xpm"
60 #include "button_cursorend.xpm"
61 #include "button_play.xpm"
62 #include "button_playselection.xpm"
63 #include "button_stop.xpm"
64 #include "button_loop.xpm"
65 #include "button_follow.xpm"
66 #include "button_record.xpm"
67 #include "button_mixer.xpm"
68 #include "button_bounce.xpm"
69 #include "icon.xpm"
70 #include "vzoom.xbm"
71 #include "hzoom.xbm"
72 #include "speed.xbm"
73 
74 /* #define SHOW_DEBUG_MENU */
75 
76 #if GTK_MAJOR_VERSION < 2
77 #define INV_SPEED
78 #endif
79 
80 #ifdef FIXED_DATE
81 #define BUILD_DATE FIXED_DATE
82 #else
83 #define BUILD_DATE __DATE__
84 #endif
85 
86 #ifdef FIXED_TIME
87 #define BUILD_TIME FIXED_TIME
88 #else
89 #define BUILD_TIME __TIME__
90 #endif
91 
92 ListObject *mainwindow_objects = NULL;
93 
94 static gboolean window_geometry_stack_inited = FALSE;
95 static GSList *window_geometry_stack = NULL;
96 static GList *recent_filenames = NULL;
97 static GtkObjectClass *parent_class;
98 static Chunk *clipboard = NULL;
99 gboolean autoplay_mark_flag = FALSE;
100 gboolean varispeed_reset_flag = FALSE;
101 
102 static Mainwindow *mainwindow_set_document(Mainwindow *w, Document *doc,
103 					   gchar *filename);
104 static void mainwindow_view_changed(Document *d, gpointer user_data);
105 static void mainwindow_selection_changed(Document *d, gpointer user_data);
106 static void mainwindow_cursor_changed(Document *d, gboolean rolling,
107 				      gpointer user_data);
108 static void mainwindow_state_changed(Document *d, gpointer user_data);
109 
110 
111 
load_recent(void)112 static void load_recent(void)
113 {
114      guint i;
115      gchar *c,*d;
116      g_assert(recent_filenames == NULL);
117      for (i=1; ; i++) {
118 	  c = g_strdup_printf("recentFile%d",i);
119 	  d = inifile_get(c,NULL);
120 	  g_free(c);
121 	  if (d == NULL) break;
122 	  recent_filenames = g_list_append(recent_filenames, g_strdup(d));
123      }
124 }
125 
save_recent(void)126 static void save_recent(void)
127 {
128      guint i,j;
129      GList *l;
130      gchar *c;
131      j = inifile_get_guint32("recentFiles",4);
132      if (j > MAINWINDOW_RECENT_MAX) j=4;
133      for (i=1,l=recent_filenames; i<=j && l!=NULL; i++,l=l->next) {
134 	  c = g_strdup_printf("recentFile%d",i);
135 	  inifile_set(c,l->data);
136 	  g_free(c);
137      }
138 }
139 
update_file_recent(Mainwindow * w)140 static void update_file_recent(Mainwindow *w)
141 {
142      guint i = 1;
143      GList *l = recent_filenames;
144      GList *m = w->recent;
145      gchar *c,*d;
146      for (; m!=NULL && l!=NULL; m=m->next,l=l->next,i++) {
147 	  d = namepart((gchar *)l->data);
148 	  c = g_strdup_printf("%d. %s",i,d);
149 	  gtk_label_set_text(GTK_LABEL(GTK_BIN(m->data)->child),c);
150 	  gtk_widget_set_sensitive(GTK_WIDGET(m->data),TRUE);
151 	  g_free(c);
152      }
153      for (; m!=NULL; m=m->next,i++) {
154 	  c = g_strdup_printf("%d.",i);
155 	  gtk_label_set_text(GTK_LABEL(GTK_BIN(m->data)->child),c);
156 	  gtk_widget_set_sensitive(GTK_WIDGET(m->data),FALSE);
157 	  g_free(c);
158      }
159 }
160 
recent_file(gchar * filename)161 static void recent_file(gchar *filename)
162 {
163      GList *l = recent_filenames;
164      /* Remove other reference to this file, if it exists */
165      while (l!=NULL) {
166 	  if (!strcmp((gchar *)l->data,filename)) {
167 	       recent_filenames = g_list_remove_link(recent_filenames,l);
168 	       g_free(l->data);
169 	       g_list_free_1(l);
170 	       break;
171 	  } else
172 	       l = l->next;
173      }
174      /* Put file at top */
175      recent_filenames = g_list_prepend(recent_filenames,g_strdup(filename));
176      list_object_foreach(mainwindow_objects,(GFunc)update_file_recent,NULL);
177      save_recent();
178 }
179 
180 static void update_desc(Mainwindow *w);
181 
set_sensitive(GList * l,gboolean s)182 static void set_sensitive(GList *l, gboolean s)
183 {
184      while (l != NULL) {
185 	  gtk_widget_set_sensitive(GTK_WIDGET(l->data),s);
186 	  l = l->next;
187      }
188 }
189 
190 /* This function makes the window un-sensitive and brings it to front.*/
procstart(StatusBar * bar,gpointer user_data)191 static void procstart(StatusBar *bar, gpointer user_data)
192 {
193      Mainwindow *w = MAINWINDOW(user_data);
194      mainwindow_set_sensitive(w,FALSE);
195      w->esc_pressed_flag = FALSE;
196 #if GTK_MAJOR_VERSION > 1
197      gtk_window_present(GTK_WINDOW(w));
198 #else
199      if (GTK_WIDGET(w)->window)
200 	  gdk_window_raise(GTK_WIDGET(w)->window);
201 #endif
202      gtk_grab_add(GTK_WIDGET(w));
203 }
204 
procend(StatusBar * bar,gpointer user_data)205 static void procend(StatusBar *bar, gpointer user_data)
206 {
207      Mainwindow *w = MAINWINDOW(user_data);
208      mainwindow_set_sensitive(w,TRUE);
209      mainwindow_update_texts();
210      gtk_grab_remove(GTK_WIDGET(w));
211 }
212 
fix_title(Mainwindow * wnd)213 static void fix_title(Mainwindow *wnd)
214 {
215      gchar *c;
216      if (wnd->doc != NULL) {
217 	  c = g_strdup_printf ( _("mhWaveEdit: %s (%s): %d Hz, %s"),
218 				wnd->doc->titlename,
219 				chunk_get_time(wnd->doc->chunk,
220 					       wnd->doc->chunk->length,
221 					       NULL),
222 				wnd->doc->chunk->format.samplerate,
223 				sampletype_name(&(wnd->doc->chunk->format)));
224      } else
225 	  c = g_strdup(PROGRAM_VERSION_STRING);
226      gtk_window_set_title ( GTK_WINDOW ( wnd ), c );
227      g_free ( c );
228 }
229 
update_desc(Mainwindow * w)230 static void update_desc(Mainwindow *w)
231 {
232      if (w->doc != NULL)
233 	  status_bar_set_info(w->statusbar,w->doc->cursorpos,
234 			      (playing_document==w->doc),w->doc->viewstart,
235 			      w->doc->viewend,w->doc->selstart,
236 			      w->doc->selend,
237 			      w->doc->chunk->format.samplerate,
238 			      w->doc->chunk->length);
239      else
240 	  status_bar_reset(w->statusbar);
241 
242 }
243 
typesel_changed(Combo * obj,GtkWidget * user_data)244 static void typesel_changed(Combo *obj, GtkWidget *user_data)
245 {
246      int i;
247      gchar *c;
248      i = combo_selected_index(obj);
249      if (i == 0) {
250 	  gtk_widget_set_sensitive(user_data,TRUE);
251      } else {
252 	  c = fileformat_extension(i-1);
253 	  get_filename_modify_extension(c);
254 	  if (fileformat_has_options(i-1)) {
255 	       gtk_widget_set_sensitive(user_data,TRUE);
256 	  } else {
257 	       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(user_data),TRUE);
258 	       gtk_widget_set_sensitive(user_data,FALSE);
259 	  }
260      }
261 }
262 
mainwindow_open(Mainwindow * w,gchar * filename)263 static void mainwindow_open(Mainwindow *w, gchar *filename)
264 {
265      Document *doc;
266      doc = document_new_with_file ( filename, w->statusbar );
267      if (doc == NULL) return;
268      mainwindow_set_document ( w, doc, filename );
269      inifile_set("lastOpenFile",filename);
270      recent_file(filename);
271 }
272 
get_save_filename(gchar * old_filename,gchar * title_text,gint * type_id,gboolean * use_defaults)273 static gchar *get_save_filename(gchar *old_filename, gchar *title_text,
274 				gint *type_id, gboolean *use_defaults)
275 {
276      gchar *lsf,*lsd,*filename;
277      gchar *c,*d,*e;
278      GtkBox *b1,*b2;
279      GtkWidget *w,*usedef,*typesel;
280      GList *l;
281      gint i;
282 
283      /* Get the lastSaveFile entry */
284      lsf = inifile_get("lastSaveFile",NULL);
285      /* If we didn't have a lastSaveFile entry, assume we want to
286 	save into the same directory as we loaded from. */
287      if (lsf == NULL) lsf = inifile_get("lastOpenFile",NULL);
288      /* Get the directory part and copy into lsd */
289      if (lsf != NULL) {
290 	  lsd = g_strdup(lsf);
291 	  c = strrchr(lsd,'/');
292 	  if (c != NULL) c[1]=0;
293 	  else {
294 	       g_free(lsd);
295 	       lsd = NULL;
296 	  }
297      } else lsd = NULL;
298 
299      /* Create the custom widget */
300      usedef = gtk_check_button_new_with_label(_("Use default settings"));
301      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(usedef),TRUE);
302      typesel = combo_new();
303 
304      l = g_list_append(NULL,g_strdup(_("Auto-detect from extension")));
305      for (i=0; ; i++) {
306 	  c = fileformat_name(i);
307 	  if (c == NULL) break;
308 	  d = fileformat_extension(i);
309 	  e = g_strdup_printf("%s (%s)",c,d);
310 	  l = g_list_append(l,e);
311      }
312      combo_set_items(COMBO(typesel),l,0);
313      gtk_signal_connect(GTK_OBJECT(typesel),"selection-changed",
314 			GTK_SIGNAL_FUNC(typesel_changed),usedef);
315      g_list_foreach(l,(GFunc)g_free,NULL);
316      g_list_free(l);
317 
318      b1 = GTK_BOX(gtk_hbox_new(FALSE,0));
319      w = gtk_label_new(_("File type: "));
320      gtk_box_pack_start(b1,w,FALSE,FALSE,0);
321      gtk_box_pack_start(b1,typesel,TRUE,TRUE,0);
322      gtk_box_pack_start(b1,usedef,FALSE,FALSE,6);
323      b2 = GTK_BOX(gtk_vbox_new(FALSE,8));
324      gtk_box_pack_start(b2,GTK_WIDGET(b1),FALSE,FALSE,0);
325 
326      gtk_object_ref(GTK_OBJECT(usedef));
327      gtk_object_ref(GTK_OBJECT(typesel));
328 
329      gtk_widget_show_all(GTK_WIDGET(b2));
330 
331      if (lsd == NULL)
332 	  filename = get_filename ( old_filename, "*.wav", title_text,
333 				    TRUE, GTK_WIDGET(b2));
334      else if (old_filename == NULL)
335 	  filename = get_filename (lsd, "*.wav", title_text, TRUE,
336 				   GTK_WIDGET(b2));
337      else {
338 	  c = strrchr(old_filename, '/');
339 	  if (!c) c=old_filename;
340 	  else c = c+1;
341 	  d = g_strjoin("/",lsd,c,NULL);
342 	  filename = get_filename(d, "*.wav", title_text, TRUE,
343 				  GTK_WIDGET(b2));
344 	  g_free(d);
345      }
346 
347      *use_defaults = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(usedef));
348      *type_id = combo_selected_index(COMBO(typesel)) - 1;
349 
350      g_free(lsd);
351      gtk_object_unref(GTK_OBJECT(typesel));
352      gtk_object_unref(GTK_OBJECT(usedef));
353      return filename;
354 
355 }
356 
mainwindow_save(Mainwindow * w,gchar * filename)357 static gboolean mainwindow_save ( Mainwindow *w, gchar *filename )
358 {
359      int type_id = -1;
360      gboolean use_defs = TRUE;
361      gboolean r;
362      gboolean fmal = FALSE; /* TRUE if filename should be g_free:d */
363 
364      if (!document_can_undo(w->doc) && w->doc->filename != NULL)
365 	  if (user_message(_("The file has not changed since last save. Press OK"
366 			   " if you want to save it anyway?"),UM_OKCANCEL) ==
367 	      MR_CANCEL)
368 	       return FALSE;
369 
370      /* If there is no filename provided, get a filename from a dialog
371       * box. Also set the fmal flag so we remember to free the
372       * filename later. */
373      if (filename == NULL) {
374 	  filename = get_save_filename(w->doc->filename,_("Save File"),
375 				       &type_id,&use_defs);
376 	  if (filename == NULL) return TRUE;
377 	  fmal = TRUE;
378      }
379 
380      g_assert(filename != NULL);
381      /* Save the file */
382      r = document_save(w->doc, filename, type_id, use_defs);
383      if (r) { if (fmal) g_free(filename); return TRUE; }
384 
385      inifile_set("lastSaveFile",filename);
386      recent_file(filename);
387      if (fmal) g_free(filename);
388 
389      return FALSE;
390 }
391 
change_check(Mainwindow * w)392 static gboolean change_check ( Mainwindow *w )
393 {
394      gint i;
395      gchar *c;
396      if (w->doc == NULL ||
397 	 (w->doc->filename != NULL && !document_can_undo(w->doc)))
398 	  return FALSE;
399      c = g_strdup_printf( _("Save changes to %s?"),
400 			  w->doc->titlename );
401      i = user_message ( c, UM_YESNOCANCEL );
402      switch (i) {
403      case MR_YES:
404 	  return mainwindow_save ( w, w->doc->filename );
405      case MR_NO:
406 	  return FALSE;
407      case MR_CANCEL:
408 	  return TRUE;
409      }
410      g_assert_not_reached();
411      return TRUE;
412 }
413 
mainwindow_destroy(GtkObject * obj)414 static void mainwindow_destroy(GtkObject *obj)
415 {
416      Mainwindow *w = MAINWINDOW(obj);
417 
418      list_object_remove(mainwindow_objects, obj);
419 
420      if ( w->doc != NULL ) {
421 	  gtk_signal_disconnect_by_data(GTK_OBJECT(w->doc),obj);
422 	  gtk_object_unref(GTK_OBJECT(w->doc));
423 	  w->doc = NULL;
424      }
425 
426      if (list_object_get_size(mainwindow_objects) == 0) {
427 	  if (clipboard) gtk_object_unref ( GTK_OBJECT(clipboard) );
428 	  clipboard = NULL;
429 	  quitflag = TRUE;
430 	  geometry_stack_save_to_inifile("windowGeometry",
431 					 window_geometry_stack);
432      }
433 
434      parent_class->destroy(obj);
435 }
436 
mainwindow_delete_event(GtkWidget * widget,GdkEventAny * event)437 static gint mainwindow_delete_event(GtkWidget *widget, GdkEventAny *event)
438 {
439      Mainwindow *w = MAINWINDOW ( widget );
440      GtkWidgetClass *pcw = GTK_WIDGET_CLASS(parent_class);
441      if (change_check(w)) return TRUE;
442      if (playing_document == w->doc) player_stop();
443      geometry_stack_push(GTK_WINDOW(w),NULL,&window_geometry_stack);
444      if (pcw->delete_event) return pcw->delete_event(widget,event);
445      else return FALSE;
446 }
447 
mainwindow_realize(GtkWidget * widget)448 static void mainwindow_realize(GtkWidget *widget)
449 {
450      if (GTK_WIDGET_CLASS(parent_class)->realize)
451 	  GTK_WIDGET_CLASS(parent_class)->realize(widget);
452      if (!icon) icon = gdk_pixmap_create_from_xpm_d(widget->window,NULL,NULL,
453 						    icon_xpm);
454      gdk_window_set_icon(widget->window,NULL,icon,NULL);
455 
456 }
457 
mainwindow_toggle_mark(Mainwindow * w,gchar * label)458 static void mainwindow_toggle_mark(Mainwindow *w, gchar *label)
459 {
460      off_t u;
461      u = document_get_mark(w->doc,label);
462      if (u == w->doc->cursorpos)
463 	  document_set_mark(w->doc,label,DOCUMENT_BAD_MARK);
464      else
465 	  document_set_mark(w->doc,label,w->doc->cursorpos);
466 }
467 
do_play(Mainwindow * w,off_t start,off_t end,gboolean loop)468 static void do_play(Mainwindow *w, off_t start, off_t end, gboolean loop)
469 {
470      gboolean speed_reset = FALSE;
471      if (varispeed_reset_flag &&
472 	 !(player_playing() && playing_document == w->doc))
473 	  speed_reset = TRUE;
474      if (speed_reset) document_stop(w->doc,FALSE);
475 #ifdef INV_SPEED
476      if (speed_reset) gtk_adjustment_set_value(w->speed_adj,-1.0);
477      document_play(w->doc, start, end, loop, -w->speed_adj->value);
478 #else
479      if (speed_reset) gtk_adjustment_set_value(w->speed_adj,1.0);
480      document_play(w->doc, start, end, loop, w->speed_adj->value);
481 #endif
482      update_desc(w);
483 }
484 
485 
mainwindow_goto_mark(Mainwindow * w,gchar * label)486 static void mainwindow_goto_mark(Mainwindow *w, gchar *label)
487 {
488      off_t u;
489      u = document_get_mark(w->doc,label);
490      if (u != DOCUMENT_BAD_MARK) {
491 	  if (autoplay_mark_flag)
492 	       do_play(w,u,w->doc->chunk->length,w->loopmode);
493 	  else
494 	       document_set_cursor(w->doc, u);
495      }
496 }
497 
498 static void view_zoomin(GtkMenuItem *menu_item, gpointer user_data);
499 static void view_zoomout(GtkMenuItem *menu_item, gpointer user_data);
500 static void view_zoomtoselection(GtkMenuItem *menu_item, gpointer user_data);
501 static void view_zoomall(GtkMenuItem *menu_item, gpointer user_data);
502 static void edit_play(GtkMenuItem *menu_item, gpointer user_data);
503 static void edit_playselection(GtkMenuItem *menu_item, gpointer user_data);
504 static void edit_stop(GtkMenuItem *menu_item, gpointer user_data);
505 
mainwindow_keypress(GtkWidget * widget,GdkEventKey * event)506 static gint mainwindow_keypress(GtkWidget *widget, GdkEventKey *event)
507 {
508      Mainwindow *w = MAINWINDOW(widget);
509      off_t o;
510      /* printf("%d\n",event->keyval); */
511      if (!w->sensitive) {
512 	  if (event->keyval == GDK_Escape)
513 	       status_bar_break_progress(w->statusbar);
514 	  return TRUE;
515      }
516      if (w->doc == NULL)
517           return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget,event);
518      if ((event->state & GDK_CONTROL_MASK))
519 	  switch (event->keyval) {
520 	  case GDK_0: mainwindow_toggle_mark(w,"0"); return TRUE;
521 	  case GDK_1: mainwindow_toggle_mark(w,"1"); return TRUE;
522 	  case GDK_2: mainwindow_toggle_mark(w,"2"); return TRUE;
523 	  case GDK_3: mainwindow_toggle_mark(w,"3"); return TRUE;
524 	  case GDK_4: mainwindow_toggle_mark(w,"4"); return TRUE;
525 	  case GDK_5: mainwindow_toggle_mark(w,"5"); return TRUE;
526 	  case GDK_6: mainwindow_toggle_mark(w,"6"); return TRUE;
527 	  case GDK_7: mainwindow_toggle_mark(w,"7"); return TRUE;
528 	  case GDK_8: mainwindow_toggle_mark(w,"8"); return TRUE;
529 	  case GDK_9: mainwindow_toggle_mark(w,"9"); return TRUE;
530 	  case GDK_Left:
531 	  case GDK_KP_Left:
532 	       if (playing_document == w->doc)
533 		    player_nudge(-0.5);
534 	       else {
535 		    o = w->doc->cursorpos - w->doc->chunk->format.samplerate/2;
536 		    if (o < 0) o = 0;
537 		    document_set_cursor(w->doc,o);
538 	       }
539 	       return TRUE;
540 	  case GDK_Right:
541 	  case GDK_KP_Right:
542 	       if (playing_document == w->doc)
543 		    player_nudge(0.5);
544 	       else {
545 		    o = w->doc->cursorpos + w->doc->chunk->format.samplerate/2;
546 		    if (o > w->doc->chunk->length) o = w->doc->chunk->length;
547 		    document_set_cursor(w->doc,o);
548 	       }
549 	       return TRUE;
550 	  case GDK_Tab:
551 	       o = (w->doc->viewstart + w->doc->viewend) / 2;
552 	       document_set_cursor(w->doc,o);
553 	  }
554      else
555 	  switch (event->keyval) {
556 	  case GDK_0: mainwindow_goto_mark(w,"0"); return TRUE;
557 	  case GDK_1: mainwindow_goto_mark(w,"1"); return TRUE;
558 	  case GDK_2: mainwindow_goto_mark(w,"2"); return TRUE;
559 	  case GDK_3: mainwindow_goto_mark(w,"3"); return TRUE;
560 	  case GDK_4: mainwindow_goto_mark(w,"4"); return TRUE;
561 	  case GDK_5: mainwindow_goto_mark(w,"5"); return TRUE;
562 	  case GDK_6: mainwindow_goto_mark(w,"6"); return TRUE;
563 	  case GDK_7: mainwindow_goto_mark(w,"7"); return TRUE;
564 	  case GDK_8: mainwindow_goto_mark(w,"8"); return TRUE;
565 	  case GDK_9: mainwindow_goto_mark(w,"9"); return TRUE;
566 	  case GDK_plus:
567 	  case GDK_KP_Add:
568 	  case GDK_equal:
569 	       view_zoomin(NULL,widget); return TRUE;
570 	  case GDK_Down:
571 	  case GDK_KP_Down:
572 	       document_zoom(w->doc,2.0,FALSE); return TRUE;
573 	  case GDK_minus:
574 	  case GDK_KP_Subtract:
575 	       view_zoomout(NULL,widget); return TRUE;
576 	  case GDK_Up:
577 	  case GDK_KP_Up:
578 	       document_zoom(w->doc,0.5,FALSE); return TRUE;
579 	  case GDK_greater: view_zoomtoselection(NULL,widget); return TRUE;
580 	  case GDK_less: view_zoomall(NULL,widget); return TRUE;
581 	  case GDK_comma: edit_play(NULL,widget); return TRUE;
582 	  case GDK_period: edit_stop(NULL,widget); return TRUE;
583 	  case GDK_slash: edit_playselection(NULL, widget); return TRUE;
584 	  case GDK_space:
585 	       if ((event->state & GDK_SHIFT_MASK) != 0)
586 		    do_play(w,0,w->doc->chunk->length,w->loopmode);
587 	       else if (playing_document == w->doc)
588 		    document_stop(w->doc,w->bouncemode);
589 	       else if (w->doc != NULL)
590 		    do_play(w,w->doc->cursorpos,w->doc->chunk->length,
591 			    w->loopmode);
592 	       return TRUE;
593 	  case GDK_Left:
594 	  case GDK_KP_Left:
595 	       if (playing_document==w->doc && w->doc->followmode)
596 		    player_nudge(-0.5);
597 	       else
598 		    document_scroll(w->doc,
599 				    -(w->doc->viewend - w->doc->viewstart)/MAINWINDOW_SCROLL_DELTA_RATIO);
600 	       return TRUE;
601 	  case GDK_Right:
602 	  case GDK_KP_Right:
603 	       if (playing_document==w->doc && w->doc->followmode)
604 		    player_nudge(+0.5);
605 	       else
606 		    document_scroll(w->doc,
607 				    (w->doc->viewend - w->doc->viewstart)/MAINWINDOW_SCROLL_DELTA_RATIO);
608 	       return TRUE;
609 	  case GDK_parenleft:
610 	       o = 3*w->doc->chunk->format.samplerate;
611 	       if (w->doc->selstart == w->doc->selend) {
612 		    if (w->doc->chunk->length < o)
613 			 do_play(w,0,w->doc->chunk->length,FALSE);
614 		    else
615 			 do_play(w,0,o,FALSE);
616 	       } else if (w->doc->selstart+o > w->doc->selend)
617 		    do_play(w,w->doc->selstart,w->doc->selend,FALSE);
618 	       else
619 		    do_play(w,w->doc->selstart,w->doc->selstart+o,FALSE);
620 	       return TRUE;
621 	  case GDK_parenright:
622 	       o = 3*w->doc->chunk->format.samplerate;
623 	       if (w->doc->selstart == w->doc->selend) {
624 		    if (w->doc->chunk->length < o)
625 			 do_play(w,0,w->doc->chunk->length,FALSE);
626 		    else
627 			 do_play(w,w->doc->chunk->length-o,
628 				 w->doc->chunk->length,FALSE);
629 	       } else if (w->doc->selstart+o > w->doc->selend)
630 		    do_play(w,w->doc->selstart,w->doc->selend,FALSE);
631 	       else
632 		    do_play(w,w->doc->selend-o,w->doc->selend,FALSE);
633 	       return TRUE;
634 	  case GDK_Home:
635 	       document_set_view(w->doc,0,w->doc->viewend-w->doc->viewstart);
636 	       if (playing_document != w->doc || w->doc->followmode)
637 		    document_set_cursor(w->doc,0);
638 	       return TRUE;
639 	  case GDK_End:
640 	       /* Stop playback to prevent cursor jumping back to start point */
641 	       document_stop(w->doc,FALSE);
642 	       document_scroll(w->doc,w->doc->chunk->length);
643 	       if (playing_document != w->doc || w->doc->followmode)
644 		    document_set_cursor(w->doc,w->doc->chunk->length);
645 	       return TRUE;
646 	  case GDK_Tab:
647 	       document_scroll(w->doc,
648 			       w->doc->cursorpos-
649 			       (w->doc->viewend+w->doc->viewstart)/2);
650 	       return TRUE;
651 	  }
652      return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget,event);
653 }
654 
urldecode(char * str)655 static void urldecode(char *str)
656 {
657      char *s,*d;
658      int i,j;
659      s = d = str;
660      while (*s != 0) {
661 	  if (*s != '%' || s[1] == 0 || s[2] == 0) {
662 	       *d = *s;
663 	       d ++;
664 	       s ++;
665 	  } else {
666 	       i = hexval(s[1]);
667 	       j = hexval(s[2]);
668 	       if (i < 0 || j < 0) {
669 		    *d = *s;
670 		    d ++;
671 		    s ++;
672 		    continue;
673 	       }
674 	       *d = (char)(i*16+j);
675 	       d ++;
676 	       s += 3;
677 	  }
678 
679      }
680      *d = 0;
681 }
682 
mainwindow_drag_data_received(GtkWidget * widget,GdkDragContext * dc,gint x,gint y,GtkSelectionData * selection_data,guint info,guint t)683 static void mainwindow_drag_data_received(GtkWidget *widget,
684 					  GdkDragContext *dc, gint x, gint y,
685 					  GtkSelectionData *selection_data,
686 					  guint info, guint t)
687 {
688      gchar *c,*d,*e,*f;
689      if (selection_data->length > 0) {
690 
691 	  /* Copy and add extra null for safety */
692 	  c = g_malloc(selection_data->length+1);
693 	  memcpy(c,selection_data->data,selection_data->length);
694 	  c[selection_data->length] = 0;
695 
696 	  gtk_drag_finish(dc, TRUE, FALSE, t);
697 
698 	  /* Split into files */
699 	  for (d=strtok(c,"\n\r"); d!=NULL; d=strtok(NULL,"\n\r")) {
700 	       e = strchr(d,':');
701 	       if (e == NULL) continue;
702 	       *e = 0;
703 	       if (strcmp(d,"file")) continue;
704 	       while (e[1] == '/') e++;
705 
706 	       urldecode(e);
707 
708 	       if (!file_exists(e)) {
709 		    f = g_strdup_printf("Silently ignoring non-esisting "
710 					"file: %s\n",e);
711 		    console_message(f);
712 		    g_free(f);
713 		    continue;
714 	       }
715 
716 	       mainwindow_open(MAINWINDOW(widget),e);
717 	       /* printf("Dropped: %s\n",e); */
718 
719 	  }
720 
721 	  g_free(c);
722 
723      } else
724 
725 	  gtk_drag_finish(dc, FALSE, FALSE, t);
726 }
727 
mainwindow_class_init(GtkObjectClass * klass)728 static void mainwindow_class_init(GtkObjectClass *klass)
729 {
730      parent_class = gtk_type_class(gtk_window_get_type());
731      klass->destroy = mainwindow_destroy;
732      GTK_WIDGET_CLASS(klass)->delete_event = mainwindow_delete_event;
733      GTK_WIDGET_CLASS(klass)->realize = mainwindow_realize;
734      GTK_WIDGET_CLASS(klass)->key_press_event = mainwindow_keypress;
735      GTK_WIDGET_CLASS(klass)->drag_data_received =
736 	  mainwindow_drag_data_received;
737 }
738 
mainwindow_set_document(Mainwindow * w,Document * d,gchar * filename)739 static Mainwindow *mainwindow_set_document(Mainwindow *w, Document *d,
740 				    gchar *filename)
741 {
742      if (w->doc != NULL) {
743 	  w = MAINWINDOW ( mainwindow_new() );
744 	  gtk_widget_show ( GTK_WIDGET ( w ) );
745      }
746      w->doc = d;
747      document_set_followmode(d,w->followmode);
748      gtk_object_ref(GTK_OBJECT(w->doc));
749      gtk_object_sink(GTK_OBJECT(w->doc));
750      gtk_signal_connect(GTK_OBJECT(d),"view_changed",
751 			GTK_SIGNAL_FUNC(mainwindow_view_changed),w);
752      gtk_signal_connect(GTK_OBJECT(d),"selection_changed",
753 			GTK_SIGNAL_FUNC(mainwindow_selection_changed),w);
754      gtk_signal_connect(GTK_OBJECT(d),"cursor_changed",
755 			GTK_SIGNAL_FUNC(mainwindow_cursor_changed),w);
756      gtk_signal_connect(GTK_OBJECT(d),"state_changed",
757 			GTK_SIGNAL_FUNC(mainwindow_state_changed),w);
758      chunk_view_set_document ( w->view, d );
759      document_set_status_bar(d, w->statusbar);
760      fix_title(w);
761      update_desc(w);
762      set_sensitive(w->need_chunk_items,TRUE);
763      if (!inifile_get_gboolean("varispeed",TRUE))
764 	  gtk_widget_set_sensitive(w->speed_slider,FALSE);
765      list_object_add(mainwindow_objects,w);
766      mainwindow_view_changed(w->doc,w);
767      return w;
768 }
769 
mainwindow_set_chunk(Mainwindow * w,Chunk * c,gchar * filename)770 static Mainwindow *mainwindow_set_chunk(Mainwindow *w, Chunk *c, gchar *filename)
771 {
772      Document *d;
773      d = document_new_with_chunk(c,filename,w->statusbar);
774      return mainwindow_set_document(w,d,filename);
775 }
776 
mainwindow_set_speed_sensitive(gboolean sensitive)777 void mainwindow_set_speed_sensitive(gboolean sensitive)
778 {
779      GList *l;
780      Mainwindow *w;
781      for (l=mainwindow_objects->list;l!=NULL;l=l->next) {
782 	  w = MAINWINDOW(l->data);
783 	  gtk_widget_set_sensitive(w->speed_slider,sensitive);
784      }
785 }
786 
file_open(GtkMenuItem * menuitem,gpointer user_data)787 static void file_open(GtkMenuItem *menuitem, gpointer user_data)
788 {
789      gchar *c;
790      Mainwindow *w = MAINWINDOW ( user_data );
791      if (w->doc != NULL && w->doc->filename != NULL)
792 	  c = get_filename(w->doc->filename,"*.wav",_("Load File"),FALSE,NULL);
793      else {
794 	  c = inifile_get("lastOpenFile",NULL);
795 	  if (c == NULL) c = inifile_get("lastSaveFile",NULL);
796 	  c = get_filename(c,"*.wav", _("Load File"), FALSE, NULL);
797      }
798      if (!c) return;
799      mainwindow_open(w,c);
800      g_free(c);
801 }
802 
file_save(GtkMenuItem * menuitem,gpointer user_data)803 static void file_save(GtkMenuItem *menuitem, gpointer user_data)
804 {
805      Mainwindow *w = MAINWINDOW ( user_data );
806      mainwindow_save ( w, w->doc->filename );
807 }
808 
file_saveas(GtkMenuItem * menuitem,gpointer user_data)809 static void file_saveas(GtkMenuItem *menuitem, gpointer user_data)
810 {
811      mainwindow_save ( MAINWINDOW(user_data), NULL );
812 }
813 
file_saveselection(GtkMenuItem * menuitem,gpointer user_data)814 static void file_saveselection(GtkMenuItem *menuitem, gpointer user_data)
815 {
816      gint type_id;
817      gboolean use_defs;
818      gchar *fn;
819      Chunk *c;
820      Mainwindow *w = MAINWINDOW(user_data);
821      fn = get_save_filename(NULL,_("Save selection as ..."),
822 			    &type_id,&use_defs);
823      if (!fn) return;
824      c = chunk_get_part(w->doc->chunk,w->doc->selstart,
825 			w->doc->selend-w->doc->selstart);
826      if (!chunk_save(c,fn,type_id,use_defs,dither_editing,w->statusbar))
827 	  inifile_set("lastSaveFile",fn);
828      gtk_object_sink(GTK_OBJECT(c));
829      g_free(fn);
830 }
831 
832 
file_close(GtkMenuItem * menuitem,gpointer user_data)833 static void file_close(GtkMenuItem *menuitem, gpointer user_data)
834 {
835      Mainwindow *w = MAINWINDOW(user_data);
836      if (change_check(w)) return;
837      if (playing_document == w->doc) player_stop();
838      if (list_object_get_size(mainwindow_objects)==1 &&
839 	 w->doc != NULL) {
840 	  chunk_view_set_document(w->view, NULL);
841 	  gtk_signal_disconnect_by_data(GTK_OBJECT(w->doc),w);
842 	  gtk_object_unref(GTK_OBJECT(w->doc));
843 	  w->doc = NULL;
844 	  fix_title(w);
845 	  set_sensitive(w->need_chunk_items,FALSE);
846 	  set_sensitive(w->need_undo_items,FALSE);
847 	  set_sensitive(w->need_selection_items,FALSE);
848 	  list_object_remove(mainwindow_objects,w);
849      } else {
850 	  geometry_stack_push(GTK_WINDOW(w),NULL,&window_geometry_stack);
851 	  gtk_widget_destroy(GTK_WIDGET(w));
852      }
853 }
854 
try_close(Mainwindow * w,gboolean * user_data)855 static void try_close(Mainwindow *w, gboolean *user_data)
856 {
857      if (*user_data) return;
858      *user_data = change_check(w);
859 }
860 
file_exit(GtkMenuItem * menuitem,gpointer user_data)861 static void file_exit(GtkMenuItem *menuitem, gpointer user_data)
862 {
863      gboolean b = FALSE;
864      guint i;
865      GtkWidget *wid;
866      if (list_object_get_size(mainwindow_objects) == 0)
867 	  file_close(menuitem,user_data);
868      list_object_foreach(mainwindow_objects,(GFunc)try_close,&b);
869      if (b) return;
870      player_stop();
871      /* Reverse the list so we get the oldest windows on the top of the
872       * geometry stack */
873      i = list_object_get_size(mainwindow_objects);
874      for (; i>0; i--) {
875 	  wid = GTK_WIDGET(list_object_get(mainwindow_objects,i-1));
876 	  geometry_stack_push(GTK_WINDOW(wid),NULL,&window_geometry_stack);
877 	  gtk_widget_destroy(wid);
878      }
879 }
880 
edit_undo(GtkMenuItem * menuitem,gpointer user_data)881 static void edit_undo(GtkMenuItem *menuitem, gpointer user_data)
882 {
883      Mainwindow *w = MAINWINDOW (user_data);
884      document_undo(w->doc);
885 }
886 
edit_redo(GtkMenuItem * menuitem,gpointer user_data)887 static void edit_redo(GtkMenuItem *menuitem, gpointer user_data)
888 {
889      Mainwindow *w = MAINWINDOW (user_data);
890      document_redo(w->doc);
891 }
892 
update_clipboard_items(Mainwindow * w,gpointer user_data)893 static void update_clipboard_items(Mainwindow *w, gpointer user_data)
894 {
895      set_sensitive(w->need_clipboard_items,user_data != NULL);
896 }
897 
edit_cut(GtkMenuItem * menuitem,gpointer user_data)898 static void edit_cut(GtkMenuItem *menuitem, gpointer user_data)
899 {
900      Chunk *chunk, *part;
901      Mainwindow *w = MAINWINDOW(user_data);
902      g_assert (w->doc->selend != w->doc->selstart);
903      if (clipboard) gtk_object_unref(GTK_OBJECT(clipboard));
904      part = chunk_get_part( w->doc->chunk, w->doc->selstart,
905 			    w->doc->selend - w->doc->selstart);
906      chunk = chunk_remove_part( w->doc->chunk, w->doc->selstart,
907 				w->doc->selend - w->doc->selstart);
908      clipboard = part;
909      gtk_object_ref(GTK_OBJECT(clipboard));
910      gtk_object_sink(GTK_OBJECT(clipboard));
911 
912      document_update(w->doc, chunk, w->doc->selstart, -(clipboard->length));
913      list_object_foreach(mainwindow_objects, (GFunc)update_clipboard_items,
914 			 (gpointer)w);
915 }
916 
edit_crop(GtkMenuItem * menu_item,gpointer user_data)917 static void edit_crop(GtkMenuItem *menu_item, gpointer user_data)
918 {
919      Mainwindow *w = MAINWINDOW(user_data);
920      Chunk *c;
921      c = chunk_get_part( w->doc->chunk, w->doc->selstart,
922 			 w->doc->selend - w->doc->selstart);
923      document_update(w->doc, c, 0, -(w->doc->selstart));
924 }
925 
edit_copy(GtkMenuItem * menu_item,gpointer user_data)926 static void edit_copy(GtkMenuItem *menu_item, gpointer user_data)
927 {
928      Mainwindow *w = MAINWINDOW(user_data);
929      g_assert (w->doc->selend != w->doc->selstart);
930      if (clipboard) gtk_object_unref(GTK_OBJECT(clipboard));
931      clipboard = chunk_get_part(w->doc->chunk, w->doc->selstart,
932 				w->doc->selend - w->doc->selstart);
933      gtk_object_ref(GTK_OBJECT(clipboard));
934      gtk_object_sink(GTK_OBJECT(clipboard));
935 
936      list_object_foreach(mainwindow_objects, (GFunc)update_clipboard_items,
937 			 (gpointer)w);
938 }
939 
edit_paste(GtkMenuItem * menu_item,gpointer user_data)940 static void edit_paste(GtkMenuItem *menu_item, gpointer user_data)
941 {
942      Chunk *c = clipboard, *nc;
943      Mainwindow *w = MAINWINDOW(user_data);
944      off_t cp,cl;
945      if (w->doc == NULL) {
946 	  mainwindow_set_chunk(w,clipboard,NULL);
947 	  return;
948      }
949 
950      if (!dataformat_equal(&(w->doc->chunk->format),&(c->format))) {
951 	  c = chunk_convert(c,&(w->doc->chunk->format),dither_editing,
952 			    w->statusbar);
953 	  if (c == NULL) return;
954      }
955      cl = c->length;
956      nc = chunk_insert(w->doc->chunk,c,w->doc->cursorpos);
957      gtk_object_sink(GTK_OBJECT(c));
958 
959      cp = w->doc->cursorpos;
960      document_update(w->doc, nc, cp, cl);
961      document_set_selection( w->doc, cp, cp + cl );
962 }
963 
edit_pasteover(GtkMenuItem * menuitem,gpointer user_data)964 static void edit_pasteover(GtkMenuItem *menuitem, gpointer user_data)
965 {
966      Mainwindow *w = MAINWINDOW(user_data);
967      Chunk *c,*d=clipboard;
968      off_t orig_len,dl;
969      if (w->doc == NULL) {
970 	  mainwindow_set_chunk(w,clipboard,NULL);
971 	  return;
972      }
973 
974      if (!dataformat_equal(&(w->doc->chunk->format),&(d->format))) {
975 	  d = chunk_convert(d,&(w->doc->chunk->format),dither_editing,
976 			    w->statusbar);
977 	  if (d == NULL) return;
978      }
979      dl = d->length;
980 
981      orig_len = MIN(w->doc->chunk->length-w->doc->cursorpos, dl);
982      c = chunk_replace_part(w->doc->chunk, w->doc->cursorpos,
983 			    orig_len, d);
984      gtk_object_sink(GTK_OBJECT(d));
985 
986      document_update(w->doc, c, 0, 0);
987      document_set_selection( w->doc, w->doc->cursorpos,
988 			     w->doc->cursorpos + dl );
989 }
990 
edit_mixpaste(GtkMenuItem * menuitem,gpointer user_data)991 static void edit_mixpaste(GtkMenuItem *menuitem, gpointer user_data)
992 {
993      Mainwindow *w = MAINWINDOW(user_data);
994      Chunk *c,*p,*y,*d=clipboard;
995      off_t partlen;
996      if (w->doc == NULL) {
997 	  mainwindow_set_chunk(w,clipboard,NULL);
998 	  return;
999      }
1000 
1001      if (!dataformat_equal(&(w->doc->chunk->format),&(d->format))) {
1002 	  d = chunk_convert(d,&(w->doc->chunk->format),dither_editing,
1003 			    w->statusbar);
1004 	  if (d == NULL) return;
1005      }
1006 
1007      p = chunk_get_part(w->doc->chunk,w->doc->cursorpos,d->length);
1008      partlen = p->length;
1009      y = chunk_mix(p,d,dither_editing,w->statusbar);
1010      gtk_object_sink(GTK_OBJECT(p));
1011      if (!y) return;
1012      c = chunk_replace_part(w->doc->chunk,w->doc->cursorpos,partlen,y);
1013      gtk_object_sink(GTK_OBJECT(y));
1014      document_update(w->doc, c, 0, 0);
1015      document_set_selection( w->doc, w->doc->cursorpos,
1016 			     w->doc->cursorpos + d->length );
1017      gtk_object_sink(GTK_OBJECT(d));
1018 }
1019 
edit_pastetonew(GtkMenuItem * menuitem,gpointer user_data)1020 static void edit_pastetonew(GtkMenuItem *menuitem, gpointer user_data)
1021 {
1022      Mainwindow *w = MAINWINDOW (user_data);
1023      mainwindow_set_chunk(w,clipboard,NULL);
1024 }
1025 
edit_delete(GtkMenuItem * menuitem,gpointer user_data)1026 static void edit_delete(GtkMenuItem *menuitem, gpointer user_data)
1027 {
1028      Mainwindow *w = MAINWINDOW(user_data);
1029      Chunk *chunk;
1030      gint32 slen;
1031      slen = w->doc->selend - w->doc->selstart;
1032      chunk = chunk_remove_part(w->doc->chunk, w->doc->selstart, slen);
1033      document_update( w->doc, chunk, w->doc->selstart, -slen);
1034 }
1035 
interp(Chunk * chunk,StatusBar * bar,gpointer user_data)1036 static Chunk *interp(Chunk *chunk, StatusBar *bar, gpointer user_data)
1037 {
1038   return chunk_interpolate_endpoints(chunk,TRUE,dither_editing,bar);
1039 }
1040 
edit_silence(GtkMenuItem * menuitem,gpointer user_data)1041 static void edit_silence(GtkMenuItem *menuitem, gpointer user_data)
1042 {
1043      Mainwindow *w = MAINWINDOW(user_data);
1044      document_apply_cb(w->doc,interp,TRUE,NULL);
1045 }
1046 
edit_selectall(GtkMenuItem * menuitem,gpointer user_data)1047 static void edit_selectall(GtkMenuItem *menuitem, gpointer user_data)
1048 {
1049      Mainwindow *w = MAINWINDOW(user_data);
1050      if (w->doc->selstart != 0 || w->doc->selend != w->doc->chunk->length)
1051 	  document_set_selection(w->doc,0,w->doc->chunk->length);
1052      else
1053 	  document_set_selection(w->doc,0,0);
1054 }
1055 
edit_selectnone(GtkMenuItem * menuitem,gpointer user_data)1056 static void edit_selectnone(GtkMenuItem *menuitem, gpointer user_data)
1057 {
1058      Mainwindow *w = MAINWINDOW(user_data);
1059      document_set_selection(w->doc,0,0);
1060 }
1061 
view_zoomin(GtkMenuItem * menuitem,gpointer user_data)1062 static void view_zoomin(GtkMenuItem *menuitem, gpointer user_data)
1063 {
1064      Mainwindow *w = MAINWINDOW ( user_data );
1065      document_zoom(w->doc,2.0,TRUE);
1066 }
1067 
view_zoomout(GtkMenuItem * item,gpointer user_data)1068 static void view_zoomout(GtkMenuItem *item, gpointer user_data)
1069 {
1070      Mainwindow *w = MAINWINDOW ( user_data );
1071      document_zoom(w->doc,0.5,TRUE);
1072 }
1073 
view_zoomtoselection(GtkMenuItem * menuitem,gpointer user_data)1074 static void view_zoomtoselection(GtkMenuItem *menuitem, gpointer user_data)
1075 {
1076      Document *d;
1077      d = MAINWINDOW(user_data)->doc;
1078      document_set_view(d,d->selstart,d->selend);
1079 }
1080 
view_zoomall(GtkMenuItem * menuitem,gpointer user_data)1081 static void view_zoomall(GtkMenuItem *menuitem, gpointer user_data)
1082 {
1083      Document *d;
1084      d = MAINWINDOW(user_data)->doc;
1085      document_set_view(d,0,d->chunk->length);
1086 }
1087 
1088 #ifdef SHOW_DEBUG_MENU
debug_mark(GtkMenuItem * menuitem,gpointer user_data)1089 static void debug_mark(GtkMenuItem *menuitem, gpointer user_data)
1090 {
1091      /* MAINWINDOW(user_data)->changed = TRUE; */
1092 }
1093 
dummy_proc(void * in,guint sample_size,chunk_writeout_func out_func,WriteoutID id,Dataformat * format)1094 static gboolean dummy_proc(void *in, guint sample_size,
1095 			   chunk_writeout_func out_func, WriteoutID id,
1096 			   Dataformat *format)
1097 {
1098      return out_func(id,in,sample_size);
1099 }
1100 
debug_dummy(GtkMenuItem * menuitem,gpointer user_data)1101 static void debug_dummy(GtkMenuItem *menuitem, gpointer user_data)
1102 {
1103      Mainwindow *w = MAINWINDOW(user_data);
1104      document_apply(w->doc,dummy_proc,NULL,CHUNK_FILTER_MANY,FALSE,"DUMMY");
1105 }
1106 
debug_dummy2(GtkMenuItem * menuitem,gpointer user_data)1107 static void debug_dummy2(GtkMenuItem *menuitem, gpointer user_data)
1108 {
1109      Mainwindow *w = MAINWINDOW(user_data);
1110      document_apply(w->doc,dummy_proc,NULL,CHUNK_FILTER_MANY,TRUE,"DUMMY");
1111 }
1112 
checkoc_proc(Chunk * chunk,gpointer user_data)1113 static void checkoc_proc(Chunk *chunk, gpointer user_data)
1114 {
1115      if (chunk->opencount > 0)
1116 	  printf(_("Chunk %p has opencount=%d\n"),chunk,chunk->opencount);
1117 }
1118 
debug_checkoc(GtkMenuItem * menuitem,gpointer user_data)1119 static void debug_checkoc(GtkMenuItem *menuitem, gpointer user_data)
1120 {
1121      puts("--------");
1122      chunk_foreach((GFunc)checkoc_proc,NULL);
1123 }
1124 
dump_format(Dataformat * df)1125 static void dump_format(Dataformat *df)
1126 {
1127      printf("%d Channels @ %dHz ",df->channels,df->samplerate);
1128      if (df->type == DATAFORMAT_FLOAT) {
1129 	  if (df->samplesize <= sizeof(float)) {
1130 	       puts("float");
1131 	  } else
1132 	       puts("double");
1133      } else {
1134 	  printf("%d%c%c\n",df->samplesize,df->sign?'S':'U',
1135 		 df->bigendian?'B':'L');
1136      }
1137 }
1138 
dump_dp(DataPart * dp)1139 static void dump_dp(DataPart *dp)
1140 {
1141      printf("        Datasource@%p, L/S=%Ld/%Ld Format: ",dp->ds,
1142 	    dp->ds->length,dp->ds->bytes);
1143      dump_format(&(dp->ds->format));
1144      printf("        Usage: %Ld + %Ld\n",dp->position,dp->length);
1145      switch (dp->ds->type) {
1146      case DATASOURCE_REAL:
1147 	  printf("        REAL @ %p\n",dp->ds->data.real);
1148 	  break;
1149      case DATASOURCE_VIRTUAL:
1150 	  printf("        VIRTUAL @ %s:%Ld\n",dp->ds->data.virtual.filename,
1151 		 dp->ds->data.virtual.offset);
1152 	  break;
1153      case DATASOURCE_TEMPFILE:
1154 	  printf("        TEMPFILE @ %s:%Ld\n",dp->ds->data.virtual.filename,
1155 		 dp->ds->data.virtual.offset);
1156 	  break;
1157      case DATASOURCE_SILENCE:
1158 	  puts("        SILENCE");
1159 	  break;
1160      case DATASOURCE_SNDFILE:
1161 	  printf("        SNDFILE @ %s:%Ld <rr:%c>\n",
1162 		 dp->ds->data.sndfile.filename, dp->ds->data.sndfile.pos,
1163 		 dp->ds->data.sndfile.raw_readable?'T':'F');
1164 	  break;
1165      case DATASOURCE_SNDFILE_TEMPORARY:
1166 	  printf("        SNDFILE @ %s:%Ld <rr:%c>\n",
1167 		 dp->ds->data.sndfile.filename, dp->ds->data.sndfile.pos,
1168 		 dp->ds->data.sndfile.raw_readable?'T':'F');
1169 	  break;
1170      case DATASOURCE_REF:
1171 	  printf("        REF --> %p\n",dp->ds->data.clone);
1172 	  break;
1173      case DATASOURCE_CLONE:
1174 	  printf("        CLONE --> %p\n",dp->ds->data.clone);
1175 	  break;
1176      case DATASOURCE_BYTESWAP:
1177 	  printf("        BYTESWAP --> %p\n",dp->ds->data.clone);
1178 	  break;
1179      }
1180 }
1181 
dump_chunk(Chunk * c)1182 static void dump_chunk(Chunk *c)
1183 {
1184      printf("    Chunk@%p, L/S=%Ld/%Ld, Format: ",c,c->length,c->size);
1185      dump_format(&(c->format));
1186      puts("      Used datasources:");
1187      g_list_foreach(c->parts,(GFunc)dump_dp,NULL);
1188 }
1189 
indirect_dump_chunk(Chunk ** cp)1190 static void indirect_dump_chunk(Chunk **cp)
1191 {
1192 	dump_chunk(*cp);
1193 }
1194 
windowinfo_proc(gpointer item,gpointer user_data)1195 static void windowinfo_proc(gpointer item, gpointer user_data)
1196 {
1197      struct HistoryEntry *he;
1198      Mainwindow *w = MAINWINDOW(item);
1199      printf(_("\nWindow '%s'\n"),w->doc->filename);
1200      puts(_("  Current chunk:"));
1201      dump_chunk(w->view->doc->chunk);
1202      puts(_("  History:"));
1203      he = w->doc->history_pos;
1204      if (he == NULL) {
1205 	  puts("    (empty)");
1206      } else {
1207 	  while (he->prev != NULL) he=he->prev;
1208 	  while (he != NULL) {
1209 	       dump_chunk(he->chunk);
1210 	       he=he->next;
1211 	  }
1212      }
1213 }
1214 
debug_chunkinfo(GtkMenuItem * menuitem,gpointer user_data)1215 static void debug_chunkinfo(GtkMenuItem *menuitem, gpointer user_data)
1216 {
1217      list_object_foreach(mainwindow_objects,windowinfo_proc,NULL);
1218 }
1219 
1220 #endif
1221 
mainwindow_show_effect_dialog(Mainwindow * mw,gchar * effect_name)1222 static void mainwindow_show_effect_dialog(Mainwindow *mw, gchar *effect_name)
1223 {
1224      EffectBrowser *eb;
1225      eb = EFFECT_BROWSER(effect_browser_new_with_effect(mw->doc,effect_name,
1226 							'B',
1227 							(effect_name!=NULL)));
1228      gtk_widget_show(GTK_WIDGET(eb));
1229 }
1230 
effects_volume(GtkMenuItem * menuitem,gpointer user_data)1231 static void effects_volume(GtkMenuItem *menuitem, gpointer user_data)
1232 {
1233      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"volume");
1234 }
1235 
effects_speed(GtkMenuItem * menuitem,gpointer user_data)1236 static void effects_speed(GtkMenuItem *menuitem, gpointer user_data)
1237 {
1238      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"speed");
1239 }
1240 
effects_samplerate(GtkMenuItem * menuitem,gpointer user_data)1241 static void effects_samplerate(GtkMenuItem *menuitem, gpointer user_data)
1242 {
1243      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"srate");
1244 }
1245 
effects_samplesize(GtkMenuItem * menuitem,gpointer user_data)1246 static void effects_samplesize(GtkMenuItem *menuitem, gpointer user_data)
1247 {
1248      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"ssize");
1249 }
1250 
effects_mixchannels(GtkMenuItem * menuitem,gpointer user_data)1251 static void effects_mixchannels(GtkMenuItem *menuitem, gpointer user_data)
1252 {
1253      Chunk *c;
1254      Mainwindow *w = MAINWINDOW(user_data);
1255      player_stop();
1256      if (w->doc->chunk->format.channels == 1)
1257 	  user_info(_("There already is only one channel!"));
1258      else {
1259 	  c = chunk_onechannel(w->doc->chunk,dither_editing,w->statusbar);
1260 	  if (c) document_update(w->doc,c,0,0);
1261      }
1262 }
1263 
effects_splitchannel(GtkMenuItem * menuitem,gpointer user_data)1264 static void effects_splitchannel(GtkMenuItem *menuitem, gpointer user_data)
1265 {
1266      Mainwindow *w = MAINWINDOW (user_data);
1267      Chunk *c;
1268      c = chunk_copy_channel(w->doc->chunk,0,dither_editing,w->statusbar);
1269      if (c == NULL) return;
1270      player_stop();
1271      document_update(w->doc, c, 0, 0);
1272 }
1273 
effects_mapchannels(GtkMenuItem * menuitem,gpointer user_data)1274 static void effects_mapchannels(GtkMenuItem *menuitem, gpointer user_data)
1275 {
1276      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"mapchannels");
1277 }
1278 
edit_stop(GtkMenuItem * menu_item,gpointer user_data)1279 static void edit_stop(GtkMenuItem *menu_item, gpointer user_data)
1280 {
1281      Mainwindow *w = MAINWINDOW(user_data);
1282      if (playing_document == NULL) {
1283 	  if (w->doc->cursorpos != 0 || w->doc->chunk->length == 0)
1284 	       document_set_cursor(w->doc,0);
1285 	  else
1286 	       document_set_cursor(w->doc,w->doc->chunk->length);
1287      } else
1288 	  document_stop(w->doc, w->bouncemode);
1289 }
1290 
1291 
mainwindow_update_caches(void)1292 gboolean mainwindow_update_caches(void)
1293 {
1294      static guint last = 0;
1295      guint i,s;
1296      Mainwindow *wnd;
1297 
1298      s = list_object_get_size(mainwindow_objects);
1299      if (s == 0) return FALSE;
1300      if (last >= s) last=0;
1301      i = last+1;
1302      while (1) {
1303 	  if (i >= s) i = 0;
1304 	  wnd = MAINWINDOW(list_object_get(mainwindow_objects, i));
1305 	  if (chunk_view_update_cache(wnd->view)) { last = i; return TRUE; }
1306 	  if (i == last) return FALSE;
1307 	  i++;
1308      }
1309 }
1310 
edit_playselection(GtkMenuItem * menuitem,gpointer user_data)1311 static void edit_playselection(GtkMenuItem *menuitem, gpointer user_data)
1312 {
1313      Mainwindow *w = MAINWINDOW (user_data);
1314      document_play_selection(w->doc,w->loopmode,
1315 			     varispeed_reset_flag ? 1.0 : player_get_speed());
1316 }
1317 
edit_playall(GtkMenuItem * menuitem,gpointer user_data)1318 static void edit_playall(GtkMenuItem *menuitem, gpointer user_data)
1319 {
1320      Mainwindow *w = MAINWINDOW (user_data);
1321      do_play(w,0,w->doc->chunk->length,w->loopmode);
1322 }
1323 
get_help_page_contents(int page)1324 static gchar *get_help_page_contents(int page)
1325 {
1326      const char **c;
1327      char *ts[128];
1328      int i,j,k,l,x;
1329      gchar *r;
1330      c = help_page_contents[page];
1331      l = 0;
1332      for (i=0; c[i]!=NULL && i<128; i++) {
1333 	  ts[i] = gettext(c[i]);
1334 	  l += strlen(ts[i]);
1335      }
1336      r = g_malloc(l+1);
1337      k = 0;
1338      for (j=0; j<i; j++) {
1339 	  x = strlen(ts[j]);
1340 	  memcpy(r+k, ts[j], x);
1341 	  k += x;
1342      }
1343      r[k] = 0;
1344      g_assert(k==l);
1345      return r;
1346 }
1347 
help_readme(GtkMenuItem * menuitem,gpointer user_data)1348 static void help_readme(GtkMenuItem *menuitem, gpointer user_data)
1349 {
1350      GtkAccelGroup* ag;
1351      GtkWidget *window,*table,*notebook,*frame,*label,*button,*box1,*box2;
1352      int i;
1353      GtkWidget *scrolledwindow1, *viewport1, *label2;
1354      gchar *c;
1355 #if GTK_MAJOR_VERSION == 2
1356      Mainwindow *mw = MAINWINDOW(user_data);
1357      PangoFontDescription *pfd;
1358 #endif
1359      ag = gtk_accel_group_new();
1360 
1361      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1362 
1363      gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1364      gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);	// Centre the window
1365      gtk_window_set_default_size (GTK_WINDOW (window), -1, 400);	// Make readable
1366      gtk_window_set_title (GTK_WINDOW (window), _("mhWaveEdit Help"));
1367 
1368      box1 = gtk_vbox_new (FALSE, 0);
1369      gtk_container_add (GTK_CONTAINER (window), box1);
1370      gtk_widget_show (box1);
1371 
1372      box2 = gtk_vbox_new (FALSE, 10);
1373      gtk_container_set_border_width (GTK_CONTAINER (box2), 1);
1374      gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
1375      gtk_widget_show (box2);
1376 
1377      table = gtk_table_new (4, 6, FALSE);
1378      gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
1379 
1380      notebook = gtk_notebook_new ();
1381      gtk_table_attach_defaults (GTK_TABLE (table), notebook, 0, 6, 0, 1);
1382      gtk_widget_show (notebook);
1383 
1384      for (i=0; i<help_page_count; i++)
1385      {
1386 	frame = gtk_frame_new (NULL);
1387 	gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
1388 	gtk_widget_show (frame);
1389 
1390 	scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
1391 	gtk_widget_show (scrolledwindow1);
1392 	gtk_container_add (GTK_CONTAINER (frame), scrolledwindow1);
1393 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
1394 					GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1395 
1396 	viewport1 = gtk_viewport_new (NULL, NULL);
1397 	gtk_widget_show (viewport1);
1398 	gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1);
1399 
1400 	c = get_help_page_contents(i);
1401 	label2 = gtk_label_new (c);
1402 	g_free(c);
1403 #if GTK_MAJOR_VERSION == 2
1404 if (i==HELP_PAGE_SHORTCUTS)	// Keyboard tab only
1405 {
1406      pfd = pango_font_description_copy_static(GTK_WIDGET(mw)->style->font_desc);
1407      pango_font_description_set_family_static(pfd, "Monospace");
1408      gtk_widget_modify_font(label2, pfd);
1409      pango_font_description_free(pfd);
1410 }
1411 #endif
1412 	gtk_container_add (GTK_CONTAINER (viewport1), label2);
1413 	GTK_WIDGET_SET_FLAGS (label2, GTK_CAN_FOCUS);
1414 	gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
1415 	gtk_label_set_line_wrap (GTK_LABEL (label2), TRUE);
1416 	gtk_misc_set_alignment (GTK_MISC (label2), 0, 0);
1417 	gtk_misc_set_padding (GTK_MISC (label2), 5, 5);
1418 	gtk_widget_show (label2);
1419 
1420 
1421 	label = gtk_label_new (_(help_page_titles[i]));
1422 	gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
1423      }
1424 
1425      /* Show default page (defined in help.h) */
1426 #if GTK_MAJOR_VERSION == 1
1427      gtk_notebook_set_page (GTK_NOTEBOOK (notebook), HELP_PAGE_DEFAULT);
1428 #else
1429      gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook),HELP_PAGE_DEFAULT);
1430 #endif
1431      gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
1432 
1433      box2 = gtk_vbox_new (FALSE, 10);
1434      gtk_container_set_border_width (GTK_CONTAINER (box2), 1);
1435      gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
1436      gtk_widget_show (box2);
1437 
1438      button = gtk_button_new_with_label (_("Close"));
1439      gtk_widget_add_accelerator (button, "clicked", ag, GDK_KP_Enter, 0,
1440 				 (GtkAccelFlags) 0);
1441      gtk_widget_add_accelerator (button, "clicked", ag, GDK_Return, 0,
1442 				 (GtkAccelFlags) 0);
1443      gtk_widget_add_accelerator (button, "clicked", ag, GDK_Escape, 0,
1444 				 (GtkAccelFlags) 0);
1445      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1446      gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
1447 			       (GtkSignalFunc)gtk_widget_destroy,
1448 			       GTK_OBJECT(window));
1449      gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1450      gtk_widget_show (button);
1451 
1452      gtk_widget_show (table);
1453      gtk_widget_show (window);
1454      gtk_window_add_accel_group(GTK_WINDOW (window), ag);
1455 }
1456 
help_about(void)1457 static void help_about(void)
1458 {
1459      GtkAccelGroup* ag;
1460      gchar *p;
1461      GtkWidget *a,*b,*c;
1462      ag = gtk_accel_group_new();
1463      a = gtk_window_new(GTK_WINDOW_DIALOG);
1464 gtk_window_set_modal(GTK_WINDOW(a),TRUE);
1465      gtk_window_set_title(GTK_WINDOW(a),_("About mhWaveEdit"));
1466      gtk_container_set_border_width(GTK_CONTAINER(a),5);
1467      gtk_window_set_position (GTK_WINDOW (a), GTK_WIN_POS_CENTER);	// Centre the window
1468      b = gtk_vbox_new(FALSE,10);
1469      gtk_container_add(GTK_CONTAINER(a),b);
1470      gtk_widget_show(b);
1471      c = gtk_label_new(PROGRAM_VERSION_STRING);
1472      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1473      gtk_widget_show(c);
1474      c = gtk_hseparator_new();
1475      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1476      gtk_widget_show(c);
1477      c = gtk_label_new(_("Created by Magnus Hjorth (magnus.hjorth@home.se)\n"
1478 	  "Copyright 2002-2018, Magnus Hjorth"));
1479      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1480      gtk_widget_show(c);
1481      c = gtk_hseparator_new();
1482      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1483      gtk_widget_show(c);
1484      p = g_strdup_printf(_("Current sound driver: %s"),sound_driver_name());
1485      c = gtk_label_new(p);
1486      g_free(p);
1487      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1488      gtk_widget_show(c);
1489      c = gtk_hseparator_new();
1490      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1491      gtk_widget_show(c);
1492      p = g_strdup_printf(_("Compiled %s %s"), BUILD_DATE, BUILD_TIME);
1493      c = gtk_label_new(p);
1494      g_free(p);
1495      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1496      gtk_widget_show(c);
1497 #ifdef USE_DOUBLE_SAMPLES
1498      c = gtk_label_new(_("Uses double-precision math"));
1499      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1500      gtk_widget_show(c);
1501 #endif
1502      c = gtk_hseparator_new();
1503      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1504      gtk_widget_show(c);
1505      c = gtk_label_new(_("Distributed under GNU General Public License.\n"
1506 		       "For information, see the file COPYING"));
1507      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1508      gtk_widget_show(c);
1509      c = gtk_button_new_with_label(_("OK"));
1510      gtk_widget_add_accelerator (c, "clicked", ag, GDK_KP_Enter, 0, (GtkAccelFlags) 0);
1511      gtk_widget_add_accelerator (c, "clicked", ag, GDK_Return, 0, (GtkAccelFlags) 0);
1512      gtk_widget_add_accelerator (c, "clicked", ag, GDK_Escape, 0, (GtkAccelFlags) 0);
1513      gtk_signal_connect_object(GTK_OBJECT(c),"clicked",
1514 			       (GtkSignalFunc)gtk_widget_destroy,GTK_OBJECT(a));
1515      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1516      gtk_widget_show(c);
1517 
1518      gtk_widget_show(a);
1519      gtk_window_add_accel_group(GTK_WINDOW (a), ag);
1520 }
1521 
edit_play(GtkMenuItem * menuitem,gpointer user_data)1522 static void edit_play(GtkMenuItem *menuitem, gpointer user_data)
1523 {
1524      Mainwindow *w = MAINWINDOW (user_data);
1525      do_play(w,w->doc->cursorpos,w->doc->chunk->length,w->loopmode);
1526 }
1527 
edit_selstartcursor(GtkMenuItem * menuitem,gpointer user_data)1528 static void edit_selstartcursor(GtkMenuItem *menuitem, gpointer user_data)
1529 {
1530      Mainwindow *w = MAINWINDOW(user_data);
1531      if (w->doc->selstart == w->doc->selend)
1532 	  document_set_selection(w->doc,w->doc->cursorpos,
1533 				 w->doc->chunk->length);
1534      else
1535 	  document_set_selection(w->doc,w->doc->cursorpos,w->doc->selend);
1536 }
1537 
edit_selendcursor(GtkMenuItem * menuitem,gpointer user_data)1538 static void edit_selendcursor(GtkMenuItem *menuitem, gpointer user_data)
1539 {
1540      Mainwindow *w = MAINWINDOW(user_data);
1541      if (w->doc->selstart == w->doc->selend)
1542 	  document_set_selection(w->doc,0,w->doc->cursorpos+1);
1543      else
1544 	  document_set_selection(w->doc,w->doc->selstart,w->doc->cursorpos);
1545 }
1546 
edit_record(GtkMenuItem * menuitem,gpointer user_data)1547 static void edit_record(GtkMenuItem *menuitem, gpointer user_data)
1548 {
1549      Mainwindow *wnd = MAINWINDOW (user_data);
1550      Chunk *c;
1551      int noverruns, i;
1552      off_t overrun_locs[10];
1553      gchar s[2], *str;
1554      player_stop();
1555      c = record_dialog_execute(&noverruns, overrun_locs);
1556      if (c) {
1557 	  wnd = mainwindow_set_chunk(wnd,c,NULL);
1558 	  if (noverruns > 0) {
1559 	       for (i=0; i<noverruns && i<10; i++) {
1560 		    s[0] = '0'+i;
1561 		    s[1] = 0;
1562 		    document_set_mark(wnd->doc, s,
1563 				      overrun_locs[i]/c->format.samplebytes);
1564 	       }
1565 	       str = g_strdup_printf
1566 		    ("%d overruns where detected while recording. "
1567 		     "This means the recording may be damaged. The "
1568 		     "locations where the overruns happened have been "
1569 		     "indicated with markers.",noverruns);
1570 	       user_warning(str);
1571 	       g_free(str);
1572 	  }
1573      }
1574 }
1575 
edit_preferences(GtkMenuItem * menuitem,gpointer user_data)1576 static void edit_preferences(GtkMenuItem *menuitem, gpointer user_data)
1577 {
1578     gtk_widget_show(config_dialog_new());
1579 }
1580 
effects_combinechannels(GtkMenuItem * menuitem,gpointer user_data)1581 static void effects_combinechannels(GtkMenuItem *menuitem, gpointer user_data)
1582 {
1583      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"combine");
1584 }
1585 
effects_sandwich(GtkMenuItem * menuitem,gpointer user_data)1586 static void effects_sandwich(GtkMenuItem *menuitem, gpointer user_data)
1587 {
1588      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"sandwich");
1589 }
1590 
view_timescale(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1591 static void view_timescale(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1592 {
1593      Mainwindow *w = MAINWINDOW ( user_data );
1594      chunk_view_set_timescale(w->view, checkmenuitem->active);
1595 }
1596 
view_horizoom(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1597 static void view_horizoom(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1598 {
1599      Mainwindow *w = MAINWINDOW ( user_data );
1600      if (w->hzoom_icon == NULL) return;
1601      if (checkmenuitem->active) {
1602 	  gtk_widget_show(w->hzoom_icon);
1603 	  gtk_widget_show(w->hzoom_slider);
1604      } else {
1605 	  gtk_widget_hide(w->hzoom_icon);
1606 	  gtk_widget_hide(w->hzoom_slider);
1607      }
1608 }
1609 
view_vertzoom(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1610 static void view_vertzoom(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1611 {
1612      Mainwindow *w = MAINWINDOW ( user_data );
1613      if (w->vzoom_icon == NULL) return;
1614      if (checkmenuitem->active) {
1615 	  gtk_widget_show(w->vzoom_icon);
1616 	  gtk_widget_show(w->vzoom_slider);
1617 	  gtk_widget_show(GTK_WIDGET(w->vzoom_label));
1618      } else {
1619 	  gtk_widget_hide(w->vzoom_icon);
1620 	  gtk_widget_hide(w->vzoom_slider);
1621 	  gtk_widget_hide(GTK_WIDGET(w->vzoom_label));
1622      }
1623 }
1624 
view_speed(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1625 static void view_speed(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1626 {
1627      Mainwindow *w = MAINWINDOW(user_data);
1628      if (w->speed_icon == NULL) return;
1629      if (checkmenuitem->active) {
1630 	  gtk_widget_show(w->speed_icon);
1631 	  gtk_widget_show(w->speed_slider);
1632 	  if (w->show_labels) gtk_widget_show(GTK_WIDGET(w->speed_label));
1633      } else {
1634 	  gtk_widget_hide(w->speed_icon);
1635 	  gtk_widget_hide(w->speed_slider);
1636 	  gtk_widget_hide(GTK_WIDGET(w->speed_label));
1637      }
1638 }
1639 
view_sliderlabels(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1640 static void view_sliderlabels(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1641 {
1642      Mainwindow *w = MAINWINDOW(user_data);
1643      w->show_labels = checkmenuitem->active;
1644      if (w->vzoom_slider == NULL) return;
1645      if (w->show_labels) {
1646 	  if (GTK_WIDGET_VISIBLE(w->vzoom_slider))
1647 	       gtk_widget_show(GTK_WIDGET(w->vzoom_label));
1648 	  if (GTK_WIDGET_VISIBLE(w->speed_slider))
1649 	       gtk_widget_show(GTK_WIDGET(w->speed_label));
1650      } else {
1651 	  gtk_widget_hide(GTK_WIDGET(w->vzoom_label));
1652 	  gtk_widget_hide(GTK_WIDGET(w->speed_label));
1653      }
1654 }
1655 
view_bufpos(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1656 static void view_bufpos(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1657 {
1658      Mainwindow *w = MAINWINDOW(user_data);
1659      w->view->show_bufpos = checkmenuitem->active;
1660      gtk_widget_queue_draw(GTK_WIDGET(w->view));
1661 }
1662 
edit_insertsilence(GtkMenuItem * menuitem,gpointer user_data)1663 static void edit_insertsilence(GtkMenuItem *menuitem, gpointer user_data)
1664 {
1665      Mainwindow *w = MAINWINDOW ( user_data );
1666      gfloat f;
1667      off_t cp;
1668      Chunk *c,*nc;
1669      if (user_input_float(_("Seconds of silence: "),_("Insert Silence"),0.0,
1670 			  GTK_WINDOW(w),&f))
1671 	  return;
1672      if (f<=0.0) return;
1673      c = chunk_new_silent(&(w->doc->chunk->format),f);
1674      nc = chunk_insert(w->doc->chunk, c, w->doc->cursorpos);
1675      cp = w->doc->cursorpos;
1676      document_update(w->doc,nc,cp,c->length);
1677      document_set_selection( w->doc, cp, cp + c->length );
1678      gtk_object_sink(GTK_OBJECT(c));
1679 }
1680 
edit_clearclipboard(GtkMenuItem * menuitem,gpointer user_data)1681 static void edit_clearclipboard(GtkMenuItem *menuitem, gpointer user_data)
1682 {
1683      gtk_object_unref(GTK_OBJECT(clipboard));
1684      clipboard = NULL;
1685      list_object_foreach(mainwindow_objects,
1686 			 (GFunc)update_clipboard_items, NULL);
1687 }
1688 
edit_positioncursor(GtkMenuItem * menuitem,gpointer user_data)1689 static void edit_positioncursor(GtkMenuItem *menuitem, gpointer user_data)
1690 {
1691      gtk_widget_show(goto_dialog_new(MAINWINDOW(user_data)));
1692 }
1693 
effects_normalize_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1694 static Chunk *effects_normalize_proc(Chunk *chunk, StatusBar *bar,
1695 				     gpointer user_data)
1696 {
1697      sample_t s;
1698      Chunk *c;
1699      gfloat *lp = (gfloat *)user_data;
1700      sample_t level = (lp == NULL) ? 1.0 : *lp;
1701      s = chunk_peak_level(chunk,bar);
1702      if (s < 0.0) return NULL;
1703      c = chunk_amplify(chunk,level/s,dither_editing,bar);
1704      return c;
1705 }
1706 
effects_normalize(GtkMenuItem * menuitem,gpointer user_data)1707 static void effects_normalize(GtkMenuItem *menuitem, gpointer user_data)
1708 {
1709      document_apply_cb(MAINWINDOW(user_data)->doc,effects_normalize_proc,
1710 		       TRUE,NULL);
1711 }
1712 
effects_normalizeto(GtkMenuItem * menuitem,gpointer user_data)1713 static void effects_normalizeto(GtkMenuItem *menuitem, gpointer user_data)
1714 {
1715      gboolean b;
1716      gfloat val;
1717      val = inifile_get_gfloat("lastNormLevel",1.0);
1718      b = user_input_float(_("Level: "),_("Normalize to..."),val,
1719 			  GTK_WINDOW(user_data),&val);
1720      if (b) return;
1721      b = document_apply_cb(MAINWINDOW(user_data)->doc,effects_normalize_proc,
1722 			   TRUE,&val);
1723      if (b) return;
1724      inifile_set_gfloat("lastNormLevel",val);
1725 }
1726 
1727 
effects_pipe(GtkMenuItem * menuitem,gpointer user_data)1728 static void effects_pipe(GtkMenuItem *menuitem, gpointer user_data)
1729 {
1730      mainwindow_show_effect_dialog(MAINWINDOW(user_data),"pipe");
1731 }
1732 
cursor_moveto_beginning(GtkMenuItem * menuitem,gpointer user_data)1733 static void cursor_moveto_beginning(GtkMenuItem *menuitem, gpointer user_data)
1734 {
1735      document_set_cursor(MAINWINDOW(user_data)->doc,0);
1736 }
1737 
cursor_moveto_end(GtkMenuItem * menuitem,gpointer user_data)1738 static void cursor_moveto_end(GtkMenuItem *menuitem, gpointer user_data)
1739 {
1740      Mainwindow *w = MAINWINDOW(user_data);
1741      document_set_cursor(w->doc,w->doc->chunk->length);
1742 }
1743 
cursor_moveto_selstart(GtkMenuItem * menuitem,gpointer user_data)1744 static void cursor_moveto_selstart(GtkMenuItem *menuitem, gpointer user_data)
1745 {
1746      Mainwindow *w = MAINWINDOW(user_data);
1747      document_set_cursor(w->doc,w->doc->selstart);
1748 }
1749 
cursor_moveto_selend(GtkMenuItem * menuitem,gpointer user_data)1750 static void cursor_moveto_selend(GtkMenuItem *menuitem, gpointer user_data)
1751 {
1752      Mainwindow *w = MAINWINDOW(user_data);
1753      document_set_cursor(w->doc,w->doc->selend);
1754 }
1755 
cursor_move_left(GtkMenuItem * menuitem,gpointer user_data)1756 static void cursor_move_left(GtkMenuItem *menuitem, gpointer user_data)
1757 {
1758      off_t delta;
1759      Mainwindow *w = MAINWINDOW(user_data);
1760 
1761      delta =
1762       - ((w->doc->viewend - w->doc->viewstart)/MAINWINDOW_NUDGE_DELTA_RATIO);
1763 
1764      if(delta > -1) {
1765           delta = -1;
1766      }
1767 
1768      document_nudge_cursor(w->doc,delta);
1769 }
1770 
cursor_move_right(GtkMenuItem * menuitem,gpointer user_data)1771 static void cursor_move_right(GtkMenuItem *menuitem, gpointer user_data)
1772 {
1773      off_t delta;
1774      Mainwindow *w = MAINWINDOW(user_data);
1775 
1776      delta =
1777       ((w->doc->viewend - w->doc->viewstart)/MAINWINDOW_NUDGE_DELTA_RATIO);
1778 
1779      if(delta < 1) {
1780           delta = 1;
1781      }
1782 
1783      document_nudge_cursor(w->doc,delta);
1784 }
1785 
cursor_move_leftsample(GtkMenuItem * menuitem,gpointer user_data)1786 static void cursor_move_leftsample(GtkMenuItem *menuitem, gpointer user_data)
1787 {
1788      Mainwindow *w = MAINWINDOW(user_data);
1789      document_nudge_cursor(w->doc,-1);
1790 }
1791 
cursor_move_rightsample(GtkMenuItem * menuitem,gpointer user_data)1792 static void cursor_move_rightsample(GtkMenuItem *menuitem, gpointer user_data)
1793 {
1794      Mainwindow *w = MAINWINDOW(user_data);
1795      document_nudge_cursor(w->doc,1);
1796 }
1797 
cursor_findzerocrossing_leftall(GtkMenuItem * menuitem,gpointer user_data)1798 static void cursor_findzerocrossing_leftall(GtkMenuItem *menuitem,
1799  gpointer user_data)
1800 {
1801      Mainwindow *w = MAINWINDOW(user_data);
1802      off_t newpos;
1803 
1804      newpos = chunk_zero_crossing_all_reverse(
1805       w->doc->chunk,w->statusbar,w->doc->cursorpos);
1806 
1807      if(newpos >= 0) {
1808          document_set_cursor(w->doc,newpos);
1809      }
1810 }
1811 
cursor_findzerocrossing_rightall(GtkMenuItem * menuitem,gpointer user_data)1812 static void cursor_findzerocrossing_rightall(GtkMenuItem *menuitem,
1813  gpointer user_data)
1814 {
1815      Mainwindow *w = MAINWINDOW(user_data);
1816      off_t newpos;
1817 
1818      newpos = chunk_zero_crossing_all_forward(
1819       w->doc->chunk,w->statusbar,w->doc->cursorpos);
1820 
1821      if(newpos >= 0) {
1822          document_set_cursor(w->doc,newpos);
1823      }
1824 }
1825 
cursor_findzerocrossing_leftany(GtkMenuItem * menuitem,gpointer user_data)1826 static void cursor_findzerocrossing_leftany(GtkMenuItem *menuitem,
1827  gpointer user_data)
1828 {
1829      Mainwindow *w = MAINWINDOW(user_data);
1830      off_t newpos;
1831 
1832      newpos = chunk_zero_crossing_any_reverse(
1833       w->doc->chunk,w->statusbar,w->doc->cursorpos);
1834 
1835      if(newpos >= 0) {
1836           document_set_cursor(w->doc,newpos);
1837      }
1838 }
1839 
cursor_findzerocrossing_rightany(GtkMenuItem * menuitem,gpointer user_data)1840 static void cursor_findzerocrossing_rightany(GtkMenuItem *menuitem,
1841  gpointer user_data)
1842 {
1843      Mainwindow *w = MAINWINDOW(user_data);
1844      off_t newpos;
1845 
1846      newpos = chunk_zero_crossing_any_forward(
1847       w->doc->chunk,w->statusbar,w->doc->cursorpos);
1848 
1849      if(newpos >= 0) {
1850           document_set_cursor(w->doc,newpos);
1851      }
1852 }
1853 
byteswap_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1854 static Chunk *byteswap_proc(Chunk *chunk, StatusBar *bar,
1855 			    gpointer user_data)
1856 {
1857      return chunk_byteswap(chunk);
1858 }
1859 
effects_byteswap(GtkMenuItem * menuitem,gpointer user_data)1860 static void effects_byteswap(GtkMenuItem *menuitem, gpointer user_data)
1861 {
1862      document_apply_cb(MAINWINDOW(user_data)->doc,byteswap_proc,TRUE,NULL);
1863 }
1864 
fadein_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1865 static Chunk *fadein_proc(Chunk *chunk, StatusBar *bar, gpointer user_data)
1866 {
1867      return chunk_volume_ramp(chunk,0.0,1.0,dither_editing,bar);
1868 }
1869 
fadeout_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1870 static Chunk *fadeout_proc(Chunk *chunk, StatusBar *bar, gpointer user_data)
1871 {
1872      return chunk_volume_ramp(chunk,1.0,0.0,dither_editing,bar);
1873 }
1874 
effects_fadein(GtkMenuItem * menuitem,gpointer user_data)1875 static void effects_fadein(GtkMenuItem *menuitem, gpointer user_data)
1876 {
1877      document_apply_cb(MAINWINDOW(user_data)->doc,fadein_proc,TRUE,NULL);
1878 }
1879 
effects_fadeout(GtkMenuItem * menuitem,gpointer user_data)1880 static void effects_fadeout(GtkMenuItem *menuitem, gpointer user_data)
1881 {
1882      document_apply_cb(MAINWINDOW(user_data)->doc,fadeout_proc,TRUE,NULL);
1883 }
1884 
effects_dialog(GtkMenuItem * menuitem,gpointer user_data)1885 static void effects_dialog(GtkMenuItem *menuitem, gpointer user_data)
1886 {
1887      mainwindow_show_effect_dialog(MAINWINDOW(user_data),NULL);
1888 }
1889 
file_recent(GtkMenuItem * menuitem,gpointer user_data)1890 static void file_recent(GtkMenuItem *menuitem, gpointer user_data)
1891 {
1892      Mainwindow *w = MAINWINDOW(user_data);
1893      Document *doc;
1894      gchar *fn;
1895      GList *l = w->recent;
1896      GList *m = recent_filenames;
1897      while (l->data != menuitem) { l=l->next; m=m->next; }
1898      fn = g_strdup((gchar *)m->data);
1899      doc = document_new_with_file(fn, w->statusbar);
1900      if (doc == NULL) { g_free(fn); return; }
1901      mainwindow_set_document(w, doc, fn);
1902      inifile_set("lastOpenFile",fn);
1903      recent_file(fn);
1904      g_free(fn);
1905 }
1906 
translate_menu_path(const gchar * path,gpointer func_data)1907 static gchar *translate_menu_path(const gchar *path, gpointer func_data)
1908 {
1909     return _(path);
1910 }
1911 
xgtk_item_factory_get_item(GtkItemFactory * itemf,gchar * caption)1912 static GtkWidget *xgtk_item_factory_get_item(GtkItemFactory *itemf,
1913 					     gchar *caption)
1914 {
1915      GtkWidget *w;
1916      w = gtk_item_factory_get_item(itemf,caption);
1917      g_assert(w != NULL);
1918      return w;
1919 }
1920 
create_menu(Mainwindow * w)1921 static GtkWidget *create_menu(Mainwindow *w)
1922 {
1923      guint i,j;
1924      GtkWidget *item;
1925      GtkItemFactoryEntry entry = {};
1926 
1927      GtkItemFactoryEntry menu_items1[] = {
1928 	  { N_("/_File"),         NULL,         NULL,           0, "<Branch>"    },
1929 	  { N_("/File/_Open..."), "<control>O", file_open,      0, NULL          },
1930 	  { N_("/File/_Save"),    "<control>S", file_save,      0, NULL          },
1931 	  { N_("/File/Save _as..."),NULL,       file_saveas,    0, NULL          },
1932 	  {N_("/File/Save selection as..."),"<control>U",file_saveselection,0,NULL},
1933 	  { N_("/_Edit"),         NULL,         NULL,           0, "<Branch>"    },
1934 	  { N_("/Edit/_Undo"),    "<control>Z", edit_undo,      0, NULL          },
1935 	  { N_("/Edit/_Redo"), "<shift><control>Z", edit_redo,  0, NULL },
1936 	  { N_("/Edit/sep1"),     NULL,         NULL,           0, "<Separator>" },
1937 	  { N_("/Edit/Cu_t"),     "<control>X", edit_cut,       0, NULL          },
1938 	  { N_("/Edit/_Copy"),    "<control>C", edit_copy,      0, NULL          },
1939 	  { N_("/Edit/_Paste"),   "<control>V", edit_paste,     0, NULL          },
1940 	  { N_("/Edit/Paste _over"),NULL,       edit_pasteover, 0, NULL          },
1941 	  { N_("/Edit/_Mix paste"),NULL,        edit_mixpaste,  0, NULL          },
1942 	  { N_("/Edit/Insert _silence"),NULL,   edit_insertsilence,0,NULL        },
1943 	  { N_("/Edit/Paste to _new"),NULL,     edit_pastetonew,0, NULL          },
1944 	  { N_("/Edit/Cr_op"),    NULL,         edit_crop,      0, NULL          },
1945 	  { N_("/Edit/_Delete"),  "<control>D", edit_delete,    0, NULL          },
1946 	  { N_("/Edit/Silence selection"),NULL,edit_silence,   0, NULL           },
1947 	  { N_("/Edit/sep2"),     NULL,         NULL,           0, "<Separator>" },
1948 	  { N_("/Edit/Select _all"),"<control>A",edit_selectall,0, NULL          },
1949 	  { N_("/Edit/Select none"),NULL,edit_selectnone,0, NULL                 },
1950 	  { N_("/Edit/sep3"),     NULL,         NULL,           0, "<Separator>" },
1951 	  { N_("/Edit/Clear clipboard"),NULL,   edit_clearclipboard,0,NULL       },
1952 	  { N_("/Edit/sep4"),     NULL,         NULL,           0, "<Separator>" },
1953 	  { N_("/Edit/Preferences"),"<control>P",      edit_preferences,0,NULL          },
1954 	  { N_("/_View"),         NULL,         NULL,           0, "<Branch>"    },
1955 	  { N_("/View/Zoom _in"), NULL,         view_zoomin,    0, NULL          },
1956 	  { N_("/View/Zoom _out"),NULL,         view_zoomout,   0, NULL          },
1957 	  { N_("/View/Zoom to _selection"),NULL,view_zoomtoselection,0,NULL      },
1958 	  { N_("/View/sep1"),     NULL,         NULL,           0, "<Separator>" },
1959 	  { N_("/View/Zoom _all"),NULL,         view_zoomall,   0, NULL          },
1960 	  { N_("/View/sep2"),     NULL,         NULL,           0, "<Separator>" },
1961 	  { N_("/View/_Time scale"),NULL,       view_timescale, 0, "<CheckItem>" },
1962 	  { N_("/View/_Horizontal zoom"),NULL,  view_horizoom,  0, "<CheckItem>" },
1963 	  { N_("/View/_Vertical zoom"),NULL,    view_vertzoom,  0, "<CheckItem>" },
1964 	  { N_("/View/Sp_eed slider"),NULL,     view_speed,     0, "<CheckItem>" },
1965 	  { N_("/View/Slider labels"),NULL,     view_sliderlabels,0,"<CheckItem>"},
1966 	  { N_("/View/Buffer position"),NULL,   view_bufpos,    0, "<CheckItem>" },
1967 	  { N_("/_Cursor"),       NULL,         NULL,           0, "<Branch>"    },
1968 	  {N_("/Cursor/Set selection start"),"<control>Q",edit_selstartcursor,0,
1969 	   NULL},
1970 	  { N_("/Cursor/Set selection end"),"<control>W",edit_selendcursor,0,NULL},
1971 	  { N_("/Cursor/sep1"),   NULL,         NULL,           0, "<Separator>" },
1972       { N_("/Cursor/Move to"),   NULL,         NULL,           0, "<Branch>" },
1973 	  { N_("/Cursor/Move to/Beginning"),"<control>H",cursor_moveto_beginning,0,
1974 	   NULL},
1975 	  { N_("/Cursor/Move to/End"),"<control>J",cursor_moveto_end, 0, NULL   },
1976 	  { N_("/Cursor/Move to/Selection start"),"<control>K",
1977        cursor_moveto_selstart,0,NULL},
1978 	  { N_("/Cursor/Move to/Selection end"),"<control>L",
1979        cursor_moveto_selend,0,NULL},
1980       { N_("/Cursor/Move"),   NULL,         NULL,           0, "<Branch>" },
1981 	  { N_("/Cursor/Move/Left"),"H",cursor_move_left,0,NULL},
1982 	  { N_("/Cursor/Move/Right"),"J",cursor_move_right,0,NULL},
1983 	  { N_("/Cursor/Move/Left sample"),"K",cursor_move_leftsample,0,NULL},
1984 	  { N_("/Cursor/Move/Right sample"),"L",cursor_move_rightsample,0,NULL},
1985       { N_("/Cursor/Find zero-crossing"),NULL,NULL,0,"<Branch>"},
1986 	  { N_("/Cursor/Find zero-crossing/Left (all channels)"),"Y",
1987        cursor_findzerocrossing_leftall,0,NULL},
1988 	  { N_("/Cursor/Find zero-crossing/Right (all channels)"),"U",
1989        cursor_findzerocrossing_rightall,0,NULL},
1990 	  { N_("/Cursor/Find zero-crossing/Left (any channel)"),"I",
1991        cursor_findzerocrossing_leftany,0,NULL},
1992 	  { N_("/Cursor/Find zero-crossing/Right (any channel)"),"O",
1993        cursor_findzerocrossing_rightany,0,NULL},
1994 	  { N_("/Cursor/sep2"),   NULL,         NULL,           0, "<Separator>" },
1995 	  { N_("/Cursor/Position cursor..."),"<control>G",edit_positioncursor,0,
1996 	   NULL},
1997 	  { N_("/_Play"),         NULL,         NULL,           0, "<Branch>"    },
1998 	  { N_("/Play/_Play from cursor"),NULL, edit_play,      0, NULL          },
1999 	  { N_("/Play/Play _all"),NULL,         edit_playall,   0, NULL          },
2000 	  { N_("/Play/Play se_lection"),NULL,   edit_playselection,0,NULL        },
2001 	  { N_("/Play/_Stop"),    NULL,         edit_stop,      0, NULL          },
2002 	  { N_("/Play/sep1"),     NULL,         NULL,           0, "<Separator>" },
2003 	  { N_("/Play/_Record..."),  "F12",        edit_record,    0, NULL       },
2004 	  { N_("/Effec_ts"),      NULL,         NULL,           0, "<Branch>"    },
2005 	  { N_("/Effects/Fade _in"),NULL,       effects_fadein, 0, NULL          },
2006 	  { N_("/Effects/Fade o_ut"),NULL,      effects_fadeout,0, NULL          },
2007 	  { N_("/Effects/_Normalize"),"<control>N",effects_normalize,0, NULL     },
2008 	  { N_("/Effects/Normali_ze to..."),NULL,effects_normalizeto,0,NULL },
2009 	  { N_("/Effects/_Volume adjust (fade)..."),NULL,effects_volume,0,NULL   },
2010 	  { N_("/Effects/sep1"),  NULL,         NULL,           0, "<Separator>" },
2011 	  { N_("/Effects/Convert sample_rate..."),NULL,effects_samplerate,0,NULL },
2012 	  { N_("/Effects/Convert sample _format..."),NULL,effects_samplesize,0,
2013 	    NULL},
2014 	  { N_("/Effects/B_yte swap"),NULL,      effects_byteswap,0,NULL         },
2015 	  { N_("/Effects/sep2"),  NULL,         NULL,           0, "<Separator>" },
2016 	  { N_("/Effects/_Mix to mono"),NULL,effects_mixchannels,0,NULL      },
2017 	  { N_("/Effects/Add channe_l"),NULL,effects_splitchannel,0,NULL    },
2018 	  { N_("/Effects/Ma_p channels..."),NULL,effects_mapchannels,0,NULL },
2019 	  {N_("/Effects/_Combine channels..."),NULL,effects_combinechannels,0,NULL},
2020 	  { N_("/Effects/Add channels from other file..."),NULL,effects_sandwich,0,NULL},
2021 	  { N_("/Effects/sep3"),  NULL,         NULL,           0, "<Separator>" },
2022 	  { N_("/Effects/_Speed adjustment..."),NULL,effects_speed, 0, NULL      },
2023 	  { N_("/Effects/Pipe through program..."),NULL,effects_pipe,0,NULL      },
2024 	  { N_("/Effects/sep4"),  NULL,         NULL,           0, "<Separator>" },
2025 	  { N_("/Effects/Effects dialog..."),"<control>E",effects_dialog,0,NULL  },
2026 #ifdef SHOW_DEBUG_MENU
2027 	  { N_("/Debug"),         NULL,         NULL,           0, "<Branch>"    },
2028 	  /*	  { N_("/Debug/Mark as modified"),NULL, debug_mark,     0, NULL          }, */
2029 	  { N_("/Debug/Dummy effect"),NULL,     debug_dummy,    0, NULL          },
2030 	  { N_("/Debug/Dummy effect FP"),NULL,  debug_dummy2,   0, NULL          },
2031 	  { N_("/Debug/Check opencount"),NULL,  debug_checkoc,  0, NULL          },
2032 	  { N_("/Debug/Dump chunk info"),NULL,  debug_chunkinfo,0, NULL          },
2033 #endif
2034 	  { N_("/_Help"),         NULL,         NULL,           0, "<LastBranch>"},
2035 	  { N_("/Help/_Documentation"),"F1",    help_readme,    0, NULL          },
2036 	  { N_("/Help/_About"),   NULL,         help_about,     0, NULL          }
2037      };
2038 
2039      GtkItemFactoryEntry menu_items2[] = {
2040 	  { N_("/File/sep1"),     NULL,         NULL,           0, "<Separator>" },
2041 	  { N_("/File/_Close"),   NULL,         file_close,     0, NULL          },
2042 	  { N_("/File/sep2"),     NULL,         NULL,           0, "<Separator>" },
2043 	  { N_("/File/_Exit"),    NULL,         file_exit,      0, NULL          }
2044      };
2045 
2046      gchar *need_chunk_names[] = {
2047 	  "/File/Save", "/File/Save as...",
2048 	  "/Edit/Insert silence",
2049 	  "/Edit/Select all", "/Cursor", "/View", "/Play/Play from cursor",
2050 	  "/Play/Play all", "/Play/Stop", "/Effects",
2051 	  "/Effects/Normalize",
2052 	  "/Effects/Effects dialog...",
2053 	  "/Edit/Select none"
2054      };
2055 
2056      gchar *need_selection_names[] = {
2057 	  "/Edit/Cut", "/Edit/Copy", "/Edit/Delete", "/Edit/Crop",
2058 	  "/Edit/Silence selection",
2059 	  "/View/Zoom to selection", "/File/Save selection as...",
2060 	  "/Play/Play selection"
2061      };
2062 
2063      gchar *need_clipboard_names[] = {
2064 	  "/Edit/Paste", "/Edit/Paste over", "/Edit/Mix paste",
2065 	  "/Edit/Paste to new", "/Edit/Clear clipboard"
2066      };
2067 
2068      GtkAccelGroup *accel_group;
2069      GtkItemFactory *item_factory;
2070 
2071      accel_group = gtk_accel_group_new();
2072      item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR,"<main>",
2073 					 accel_group);
2074 
2075 #ifdef ENABLE_NLS
2076      gtk_item_factory_set_translate_func(item_factory,
2077 	     translate_menu_path, NULL, NULL);
2078 #endif
2079 
2080      gtk_item_factory_create_items_ac(item_factory,ARRAY_LENGTH(menu_items1),
2081 				      menu_items1,w,2);
2082      w->recent = NULL;
2083      j = inifile_get_guint32("recentFiles",4);
2084      if (j > MAINWINDOW_RECENT_MAX) j=4;
2085      if (j > 0) {
2086 	  entry.path = "/File/sep3";
2087 	  entry.item_type = "<Separator>";
2088 	  entry.callback = NULL;
2089 	  gtk_item_factory_create_item(item_factory,&entry,w,2);
2090 	  item = gtk_item_factory_get_item(item_factory,entry.path);
2091      }
2092      for (i=1; i<=j; i++) {
2093 	  entry.item_type = NULL;
2094 	  entry.path = g_strdup_printf("/File/Last%d",i);
2095 	  entry.callback = (GtkItemFactoryCallback)file_recent;
2096 	  gtk_item_factory_create_item(item_factory,&entry,w,2);
2097 	  item = gtk_item_factory_get_item(item_factory,entry.path);
2098 	  w->recent = g_list_append(w->recent, item);
2099 	  gtk_widget_set_sensitive(item,FALSE);
2100 	  g_free(entry.path);
2101      }
2102      gtk_item_factory_create_items_ac(item_factory,ARRAY_LENGTH(menu_items2),
2103 				      menu_items2,w,2);
2104      gtk_window_add_accel_group(GTK_WINDOW(w),accel_group);
2105 
2106      for (i=0; i<ARRAY_LENGTH(need_chunk_names); i++)
2107 	  w->need_chunk_items =
2108 	       g_list_append(w->need_chunk_items,xgtk_item_factory_get_item(
2109 				  item_factory,need_chunk_names[i]));
2110 
2111      for (i=0; i<ARRAY_LENGTH(need_selection_names); i++)
2112 	  w->need_selection_items =
2113 	       g_list_append(w->need_selection_items,
2114 			     xgtk_item_factory_get_item(
2115 				 item_factory,need_selection_names[i]));
2116 
2117      for (i=0; i<ARRAY_LENGTH(need_clipboard_names); i++)
2118 	  w->need_clipboard_items =
2119 	       g_list_append(w->need_clipboard_items,
2120 			     xgtk_item_factory_get_item(
2121 				  item_factory,need_clipboard_names[i]));
2122 
2123      w->need_undo_items =
2124 	  g_list_append(w->need_undo_items,gtk_item_factory_get_item
2125 			(item_factory,"/Edit/Undo") );
2126      w->need_redo_items =
2127 	  g_list_append(w->need_redo_items,
2128 			xgtk_item_factory_get_item(item_factory,"/Edit/Redo"));
2129 
2130      update_file_recent(w);
2131 
2132      item = gtk_item_factory_get_item(item_factory,"/View/Zoom in");
2133      w->zoom_items = g_list_append(w->zoom_items,item);
2134      item = gtk_item_factory_get_item(item_factory,"/View/Zoom out");
2135      w->zoom_items = g_list_append(w->zoom_items,item);
2136 
2137      item = gtk_item_factory_get_item(item_factory,"/View/Time scale");
2138      gtk_check_menu_item_set_active(
2139 	  GTK_CHECK_MENU_ITEM(item),
2140 	  inifile_get_gboolean(INI_SETTING_TIMESCALE,
2141 			       INI_SETTING_TIMESCALE_DEFAULT));
2142 
2143      item = gtk_item_factory_get_item(item_factory,"/View/Horizontal zoom");
2144      gtk_check_menu_item_set_active
2145 	  (GTK_CHECK_MENU_ITEM(item),
2146 	   inifile_get_gboolean(INI_SETTING_HZOOM,INI_SETTING_HZOOM_DEFAULT));
2147 
2148      item = gtk_item_factory_get_item(item_factory,"/View/Vertical zoom");
2149      gtk_check_menu_item_set_active
2150 	  (GTK_CHECK_MENU_ITEM(item),
2151 	   inifile_get_gboolean(INI_SETTING_VZOOM,INI_SETTING_VZOOM_DEFAULT));
2152 
2153      item = gtk_item_factory_get_item(item_factory,"/View/Speed slider");
2154      gtk_check_menu_item_set_active
2155 	  (GTK_CHECK_MENU_ITEM(item),
2156 	   inifile_get_gboolean(INI_SETTING_SPEED,INI_SETTING_SPEED_DEFAULT));
2157 
2158      item = gtk_item_factory_get_item(item_factory,"/View/Slider labels");
2159      gtk_check_menu_item_set_active
2160 	  (GTK_CHECK_MENU_ITEM(item),
2161 	   inifile_get_gboolean(INI_SETTING_SLABELS,INI_SETTING_SLABELS_DEFAULT));
2162 
2163      item = gtk_item_factory_get_item(item_factory,"/View/Buffer position");
2164      gtk_check_menu_item_set_active
2165 	  (GTK_CHECK_MENU_ITEM(item),
2166 	   inifile_get_gboolean(INI_SETTING_BUFPOS,INI_SETTING_BUFPOS_DEFAULT));
2167 
2168      item = gtk_item_factory_get_item(item_factory,"/Play/Record...");
2169      gtk_widget_set_sensitive(item,input_supported());
2170 
2171      item = gtk_item_factory_get_item(item_factory,"/Edit/Delete");
2172      gtk_widget_add_accelerator(item, "activate", accel_group, GDK_Delete, 0, 0);
2173 
2174      return gtk_item_factory_get_widget(item_factory,"<main>");
2175 }
2176 
loopmode_toggle(GtkToggleButton * button,gboolean * user_data)2177 static void loopmode_toggle(GtkToggleButton *button, gboolean *user_data)
2178 {
2179      *user_data = gtk_toggle_button_get_active(button);
2180      inifile_set_gboolean("loopMode", *user_data);
2181 }
2182 
followmode_toggle(GtkToggleButton * button,gboolean * user_data)2183 static void followmode_toggle(GtkToggleButton *button, gboolean *user_data)
2184 {
2185      Mainwindow *w = MAINWINDOW(user_data);
2186      w->followmode = gtk_toggle_button_get_active(button);
2187      if (w->doc != NULL)
2188 	  document_set_followmode(w->doc, w->followmode);
2189      inifile_set_gboolean("followMode", w->followmode);
2190 }
2191 
bouncemode_toggle(GtkToggleButton * button,gboolean * user_data)2192 static void bouncemode_toggle(GtkToggleButton *button, gboolean *user_data)
2193 {
2194      Mainwindow *w = MAINWINDOW(user_data);
2195      w->bouncemode = gtk_toggle_button_get_active(button);
2196      inifile_set_gboolean("bounceMode", gtk_toggle_button_get_active(button));
2197 }
2198 
create_toolbar(Mainwindow * w)2199 static GtkWidget *create_toolbar(Mainwindow *w)
2200 {
2201      GtkWidget *t,*b,*r;
2202      GdkPixmap *p;
2203      GdkBitmap *bmp;
2204 #if GTK_MAJOR_VERSION == 2
2205      t = gtk_toolbar_new();
2206 #else
2207      t = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS);
2208 #endif
2209      p = gdk_pixmap_colormap_create_from_xpm_d(
2210 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2211 	  button_open_xpm);
2212      b = gtk_pixmap_new(p, bmp);
2213      r = gtk_toolbar_append_element(
2214 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2215 	  _("Load a file from disk"),"X",b,GTK_SIGNAL_FUNC(file_open),w);
2216      p = gdk_pixmap_colormap_create_from_xpm_d(
2217 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2218 	  button_save_xpm);
2219      b = gtk_pixmap_new(p, bmp);
2220      r = gtk_toolbar_append_element(
2221 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2222 	  _("Save the current file to disk"),"X",b,GTK_SIGNAL_FUNC(file_save),w);
2223      w->need_chunk_items = g_list_append(w->need_chunk_items,r);
2224      gtk_toolbar_append_space(GTK_TOOLBAR(t));
2225      p = gdk_pixmap_colormap_create_from_xpm_d(
2226 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2227 	  button_undo_xpm);
2228      b = gtk_pixmap_new(p, bmp);
2229      r = gtk_toolbar_append_element(
2230 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2231 	  _("Undo the last change"),"X",b,GTK_SIGNAL_FUNC(edit_undo),w);
2232      w->need_undo_items = g_list_append(w->need_undo_items, r);
2233      p = gdk_pixmap_colormap_create_from_xpm_d(
2234 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2235 	  button_redo_xpm);
2236      b = gtk_pixmap_new(p, bmp);
2237      r = gtk_toolbar_append_element(
2238 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2239 	  _("Redo the last undo operation"),"X",b,GTK_SIGNAL_FUNC(edit_redo),
2240 	  w);
2241      w->need_redo_items = g_list_append(w->need_redo_items, r);
2242      gtk_toolbar_append_space(GTK_TOOLBAR(t));
2243      p = gdk_pixmap_colormap_create_from_xpm_d(
2244 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2245 	  button_cut_xpm);
2246      b = gtk_pixmap_new(p, bmp);
2247      r = gtk_toolbar_append_element(
2248 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2249 	  _("Cut out the current selection"),"X",b,GTK_SIGNAL_FUNC(edit_cut),w);
2250      w->need_selection_items = g_list_append(w->need_selection_items, r);
2251      p = gdk_pixmap_colormap_create_from_xpm_d(
2252 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2253 	  button_copy_xpm);
2254      b = gtk_pixmap_new(p, bmp);
2255      r = gtk_toolbar_append_element(
2256 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2257 	  _("Copy the current selection"),"X",b,GTK_SIGNAL_FUNC(edit_copy),w);
2258      w->need_selection_items = g_list_append(w->need_selection_items, r);
2259      p = gdk_pixmap_colormap_create_from_xpm_d(
2260 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2261 	  button_paste_xpm);
2262      b = gtk_pixmap_new(p, bmp);
2263      r = gtk_toolbar_append_element(
2264 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2265 	  _("Paste at cursor position"),"X",b,GTK_SIGNAL_FUNC(edit_paste),w);
2266      w->need_clipboard_items = g_list_append(w->need_clipboard_items, r);
2267      p = gdk_pixmap_colormap_create_from_xpm_d(
2268 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2269 	  button_pasteover_xpm);
2270      b = gtk_pixmap_new(p, bmp);
2271      r = gtk_toolbar_append_element(
2272 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2273 	  _("Paste, overwriting the data after the cursor position"),"X",b,
2274 	  GTK_SIGNAL_FUNC(edit_pasteover),w);
2275      w->need_clipboard_items = g_list_append(w->need_clipboard_items, r);
2276      gtk_widget_set_sensitive(r,FALSE);
2277      p = gdk_pixmap_colormap_create_from_xpm_d(
2278 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2279 	  button_delete_xpm);
2280      b = gtk_pixmap_new(p, bmp);
2281      r = gtk_toolbar_append_element(
2282 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2283 	  _("Delete the selection"),"X",b,GTK_SIGNAL_FUNC(edit_delete),w);
2284      w->need_selection_items = g_list_append(w->need_selection_items, r);
2285      gtk_toolbar_append_space(GTK_TOOLBAR(t));
2286      p = gdk_pixmap_colormap_create_from_xpm_d(
2287 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2288 	  button_cursorstart_xpm);
2289      b = gtk_pixmap_new(p, bmp);
2290      r = gtk_toolbar_append_element(
2291 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2292 	  _("Set selection start to cursor position"),"X",b,
2293 	  GTK_SIGNAL_FUNC(edit_selstartcursor),w);
2294      w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2295      p = gdk_pixmap_colormap_create_from_xpm_d(
2296 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2297 	  button_cursorend_xpm);
2298      b = gtk_pixmap_new(p, bmp);
2299      r = gtk_toolbar_append_element(
2300 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2301 	  _("Set selection end to cursor position"),"X",b,
2302 	  GTK_SIGNAL_FUNC(edit_selendcursor),w);
2303      w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2304      gtk_toolbar_append_space(GTK_TOOLBAR(t));
2305      p = gdk_pixmap_colormap_create_from_xpm_d(
2306 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2307 	  button_play_xpm);
2308      b = gtk_pixmap_new(p, bmp);
2309      r = gtk_toolbar_append_element(
2310 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2311 	  _("Play from cursor position"),"X",b,
2312 	  GTK_SIGNAL_FUNC(edit_play),w);
2313      w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2314      p = gdk_pixmap_colormap_create_from_xpm_d
2315        (NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2316 	button_playselection_xpm);
2317      b = gtk_pixmap_new(p, bmp);
2318      r = gtk_toolbar_append_element(
2319 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2320 	  _("Play selected area"),"X",b,
2321 	  GTK_SIGNAL_FUNC(edit_playselection),w);
2322      w->need_chunk_items = g_list_append(w->need_chunk_items,r);
2323      p = gdk_pixmap_colormap_create_from_xpm_d(
2324 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2325 	  button_stop_xpm);
2326      b = gtk_pixmap_new(p, bmp);
2327      r = gtk_toolbar_append_element(
2328 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2329 	  _("Stop playing"),"X",b,
2330 	  GTK_SIGNAL_FUNC(edit_stop),w);
2331      w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2332      gtk_toolbar_append_space(GTK_TOOLBAR(t));
2333      p = gdk_pixmap_colormap_create_from_xpm_d(
2334 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2335 	  button_loop_xpm);
2336      b = gtk_pixmap_new(p, bmp);
2337      r = gtk_toolbar_append_element(
2338 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_TOGGLEBUTTON,NULL,NULL,
2339 	  _("Loop mode (play over and over)"),"X",b,
2340 	  GTK_SIGNAL_FUNC(loopmode_toggle),&(w->loopmode));
2341      if ( inifile_get_gboolean("loopMode",FALSE) )
2342 	  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(r), TRUE);
2343      p = gdk_pixmap_colormap_create_from_xpm_d(
2344 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2345 	  button_follow_xpm);
2346      b = gtk_pixmap_new(p, bmp);
2347      r = gtk_toolbar_append_element(
2348 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_TOGGLEBUTTON,NULL,NULL,
2349 	  _("Keep view and playback together"),"X",b,
2350 	  GTK_SIGNAL_FUNC(followmode_toggle),w);
2351      if ( inifile_get_gboolean("followMode",FALSE) ) {
2352 	  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(r), TRUE);
2353 	  w->followmode = TRUE;
2354      } else
2355 	  w->followmode = FALSE;
2356      p = gdk_pixmap_colormap_create_from_xpm_d(
2357 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2358 	  button_bounce_xpm);
2359      b = gtk_pixmap_new(p, bmp);
2360      r = gtk_toolbar_append_element(
2361 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_TOGGLEBUTTON,NULL,NULL,
2362 	  _("Auto return to playback start"),"X",b,
2363 	  GTK_SIGNAL_FUNC(bouncemode_toggle),w);
2364      if ( inifile_get_gboolean("bounceMode",FALSE) ) {
2365 	  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(r), TRUE);
2366 	  w->bouncemode = TRUE;
2367      }
2368 
2369      gtk_toolbar_append_space(GTK_TOOLBAR(t));
2370      p = gdk_pixmap_colormap_create_from_xpm_d(
2371 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2372 	  button_record_xpm);
2373      b = gtk_pixmap_new(p, bmp);
2374      r = gtk_toolbar_append_element(
2375 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2376 	  _("Record"),"X",b,GTK_SIGNAL_FUNC(edit_record),w);
2377      gtk_widget_set_sensitive(r,input_supported());
2378      gtk_toolbar_append_space(GTK_TOOLBAR(t));
2379      p = gdk_pixmap_colormap_create_from_xpm_d(
2380 	  NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2381 	  button_mixer_xpm);
2382      b = gtk_pixmap_new(p, bmp);
2383      r = gtk_toolbar_append_element(
2384 	  GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2385 	  _("Launch mixer"),"X",b,GTK_SIGNAL_FUNC(launch_mixer),w);
2386      return t;
2387 }
2388 
2389 static gboolean setting_zoom_flag = FALSE;
2390 
mainwindow_view_changed(Document * d,gpointer user_data)2391 static void mainwindow_view_changed(Document *d, gpointer user_data)
2392 {
2393      float max_samp,min_samp,current_samp;
2394      Mainwindow *w = MAINWINDOW(user_data);
2395      w->view_adj->page_size = (d->viewend - d->viewstart);
2396      w->view_adj->upper = d->chunk->length;
2397      w->view_adj->value = d->viewstart;
2398      w->view_adj->step_increment = 16;
2399      w->view_adj->page_increment = w->view_adj->page_size / 2;
2400      gtk_adjustment_changed ( w->view_adj );
2401      setting_zoom_flag = TRUE;
2402      max_samp = w->doc->chunk->length;
2403      min_samp = GTK_WIDGET(w->view)->allocation.width;
2404      current_samp = w->doc->viewend - w->doc->viewstart;
2405      if (current_samp < min_samp) {
2406 	  if (current_samp < w->doc->chunk->length) {
2407 	       /* We are zoomed in longer than the slider allows, so set it
2408 		* to max */
2409 	       w->zoom_adj->value = 1.0;
2410 	       w->zoom_adj->page_size = 0.2;
2411 	       set_sensitive(w->zoom_items,TRUE);
2412 	  } else {
2413 	       /* We're viewing the whole chunk and can't zoom in or out */
2414 	       w->zoom_adj->value = 0.0;
2415 	       w->zoom_adj->page_size = 1.2;
2416 	       set_sensitive(w->zoom_items,FALSE);
2417 	  }
2418      } else {
2419 	  w->zoom_adj->value =
2420 	       log(current_samp/max_samp)/log(min_samp/max_samp);
2421 	  w->zoom_adj->page_size = 0.2;
2422 	  set_sensitive(w->zoom_items,TRUE);
2423      }
2424      gtk_adjustment_changed ( w->zoom_adj );
2425      setting_zoom_flag = FALSE;
2426      update_desc(w);
2427 }
2428 
mainwindow_selection_changed(Document * d,gpointer user_data)2429 static void mainwindow_selection_changed(Document *d, gpointer user_data)
2430 {
2431      Mainwindow *w = MAINWINDOW ( user_data );
2432      update_desc ( w );
2433      set_sensitive(w->need_selection_items, (d->selstart != d->selend));
2434 }
2435 
mainwindow_cursor_changed(Document * d,gboolean rolling,gpointer user_data)2436 static void mainwindow_cursor_changed(Document *d, gboolean rolling,
2437 				      gpointer user_data)
2438 {
2439      Mainwindow *w;
2440      w = MAINWINDOW ( user_data );
2441      if (!rolling || status_bar_roll_cursor) update_desc(w);
2442 }
2443 
mainwindow_state_changed(Document * d,gpointer user_data)2444 static void mainwindow_state_changed(Document *d, gpointer user_data)
2445 {
2446      Mainwindow *w = MAINWINDOW(user_data);
2447      fix_title(w);
2448      update_desc(w);
2449      set_sensitive(w->need_undo_items,document_can_undo(d));
2450      set_sensitive(w->need_redo_items,document_can_redo(d));
2451      set_sensitive(w->need_selection_items,(d->selstart != d->selend));
2452      mainwindow_view_changed(d,user_data);
2453 }
2454 
mainwindow_value_changed(GtkAdjustment * adjustment,gpointer user_data)2455 static void mainwindow_value_changed(GtkAdjustment *adjustment,
2456 				     gpointer user_data)
2457 {
2458      Document *d = MAINWINDOW(user_data)->doc;
2459      off_t s,e;
2460      s = (off_t)adjustment->value;
2461      e = (off_t)(adjustment->value + adjustment->page_size);
2462      /* Due to rounding, these can become out of range.
2463       * Especially for GTK1 where value and page_size are gfloats */
2464      if (s < 0) s = 0;
2465      if (e <= s) e = s+1; else if (e > d->chunk->length) e = d->chunk->length;
2466      document_set_view(d, s, e);
2467 }
2468 
mainwindow_zoom_changed(GtkAdjustment * adjustment,gpointer user_data)2469 static void mainwindow_zoom_changed(GtkAdjustment *adjustment,
2470 				    gpointer user_data)
2471 {
2472      gboolean follow_cursor;
2473      float max_samp,min_samp,target_samp,current_samp;
2474      Mainwindow *w = MAINWINDOW(user_data);
2475 
2476      /* puts("mainwindow_zoom_changed"); */
2477      if (setting_zoom_flag) return;
2478      current_samp = w->doc->viewend - w->doc->viewstart;
2479      min_samp = GTK_WIDGET(w->view)->allocation.width;
2480      max_samp = w->doc->chunk->length;
2481      target_samp = max_samp * pow(min_samp/max_samp,adjustment->value);
2482      follow_cursor = target_samp <= current_samp;
2483      document_zoom(w->doc,current_samp/target_samp,follow_cursor);
2484 }
2485 
mainwindow_vertical_zoom_changed(GtkAdjustment * adjustment,gpointer user_data)2486 static void mainwindow_vertical_zoom_changed(GtkAdjustment *adjustment,
2487 					     gpointer user_data)
2488 {
2489      gfloat s;
2490      Mainwindow *w = MAINWINDOW(user_data);
2491      gchar c[32],d[32];
2492      int ndec;
2493      s = pow(100.0, adjustment->value);
2494      chunk_view_set_scale(w->view, s);
2495      ndec = 3-(int)(adjustment->value*2.0);
2496      if (ndec > 0) {
2497 	  g_snprintf(d,sizeof(d),"V: %%.0%df",ndec);
2498 	  g_snprintf(c,sizeof(c),d,(float) s);
2499      } else {
2500 	  g_snprintf(c,sizeof(c),"V: %d",(int)s);
2501      }
2502      gtk_label_set_text(w->vzoom_label,c);
2503 }
2504 
mainwindow_speed_changed(GtkAdjustment * adjustment,gpointer user_data)2505 static void mainwindow_speed_changed(GtkAdjustment *adjustment,
2506 				     gpointer user_data)
2507 {
2508      Mainwindow *w = MAINWINDOW(user_data);
2509      gchar c[32];
2510      gfloat f;
2511      f = adjustment->value;
2512 #ifdef INV_SPEED
2513      f = -f;
2514 #endif
2515      if (w->doc == playing_document)
2516 	  player_set_speed(f);
2517     g_snprintf(c,sizeof(c),"S: %d%%",(int)(f*100.0+0.5));
2518      gtk_label_set_text(w->speed_label,c);
2519 }
2520 
dc_func(gchar * label,off_t pos,gpointer fud)2521 static void dc_func(gchar *label, off_t pos, gpointer fud)
2522 {
2523      off_t *ud = (off_t *)fud;
2524      if (pos < ud[0] && pos > ud[1]) ud[1] = pos;
2525      else if (pos > ud[0] && pos < ud[2]) ud[2] = pos;
2526 }
2527 
mainwindow_view_double_click(ChunkView * view,off_t * sample,Mainwindow * wnd)2528 static void mainwindow_view_double_click(ChunkView *view,
2529 					 off_t *sample, Mainwindow *wnd)
2530 {
2531      off_t o[3] = { *sample, 0, wnd->doc->chunk->length };
2532      document_foreach_mark(wnd->doc,dc_func,o);
2533      document_set_selection(wnd->doc,o[1],o[2]);
2534 }
2535 
hzoom_scale_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2536 static gint hzoom_scale_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
2537 {
2538      Mainwindow *mw = MAINWINDOW(user_data);
2539      if (event->button == 3) {
2540 	  gtk_adjustment_set_value(mw->zoom_adj, 0);
2541 	  return TRUE;
2542      }
2543      return FALSE;
2544 }
2545 
vzoom_scale_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2546 static gint vzoom_scale_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
2547 {
2548      Mainwindow *mw = MAINWINDOW(user_data);
2549      if (event->button == 3) {
2550 	  gtk_adjustment_set_value(mw->vertical_zoom_adj, 0);
2551 	  return TRUE;
2552      }
2553      return FALSE;
2554 }
2555 
speed_scale_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2556 static gint speed_scale_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
2557 {
2558      Mainwindow *mw = MAINWINDOW(user_data);
2559      if (event->button == 3) {
2560 #ifdef INV_SPEED
2561 	  gtk_adjustment_set_value(mw->speed_adj, -1.0);
2562 #else
2563 	  gtk_adjustment_set_value(mw->speed_adj, 1.0);
2564 #endif
2565 	  return TRUE;
2566      }
2567      return FALSE;
2568 }
2569 
mainwindow_init(Mainwindow * obj)2570 static void mainwindow_init(Mainwindow *obj)
2571 {
2572      GtkWidget *a,*b,*c;
2573      GtkRequisition req;
2574      GtkTargetEntry gte;
2575 
2576      if (!window_geometry_stack_inited) {
2577 	  if (inifile_get_gboolean("useGeometry",FALSE))
2578 	       window_geometry_stack =
2579 		    geometry_stack_from_inifile("windowGeometry");
2580 	  window_geometry_stack_inited = TRUE;
2581 	  load_recent();
2582      }
2583 
2584      /* St�ll in datastrukturen */
2585      obj->view = CHUNKVIEW(chunk_view_new());
2586 
2587      chunk_view_set_timescale(
2588 	  obj->view, inifile_get_gboolean(INI_SETTING_TIMESCALE,
2589 					  INI_SETTING_TIMESCALE_DEFAULT));
2590      obj->view->show_bufpos = inifile_get_gboolean
2591 	  (INI_SETTING_BUFPOS,INI_SETTING_BUFPOS_DEFAULT);
2592      gtk_signal_connect( GTK_OBJECT(obj->view), "double-click",
2593 			 GTK_SIGNAL_FUNC(mainwindow_view_double_click), obj);
2594      obj->view_adj = GTK_ADJUSTMENT( gtk_adjustment_new ( 0,0,0,0,0,0 ));
2595      gtk_signal_connect( GTK_OBJECT(obj->view_adj), "value-changed",
2596 			 GTK_SIGNAL_FUNC(mainwindow_value_changed), obj);
2597      obj->zoom_adj = GTK_ADJUSTMENT( gtk_adjustment_new ( 0, 0, 1.2,0.01, 0.1,
2598 							  0.2 ));
2599      gtk_signal_connect( GTK_OBJECT(obj->zoom_adj), "value-changed",
2600 			 GTK_SIGNAL_FUNC(mainwindow_zoom_changed), obj);
2601      obj->vertical_zoom_adj =
2602        GTK_ADJUSTMENT(gtk_adjustment_new ( 0, 0, 0.2 + log (inifile_get_guint32 ("vzoomMax", 100)) / log (100.0), 0.01, 0.1, 0.2 ));
2603      gtk_signal_connect( GTK_OBJECT(obj->vertical_zoom_adj), "value-changed",
2604 			 GTK_SIGNAL_FUNC(mainwindow_vertical_zoom_changed),
2605 			 obj);
2606 #ifdef INV_SPEED
2607      obj->speed_adj =
2608 	  GTK_ADJUSTMENT(gtk_adjustment_new(-1.0,-2.0,0.20,0.01,0.1,0.2));
2609 #else
2610      obj->speed_adj =
2611 	  GTK_ADJUSTMENT(gtk_adjustment_new(1.0,0.0,2.2,0.01,0.1,0.2));
2612 #endif
2613      gtk_signal_connect(GTK_OBJECT(obj->speed_adj),"value-changed",
2614 			GTK_SIGNAL_FUNC(mainwindow_speed_changed),
2615 			obj);
2616 
2617      obj->statusbar = STATUSBAR(status_bar_new());
2618      gtk_signal_connect(GTK_OBJECT(obj->statusbar),"progress_begin",
2619 			GTK_SIGNAL_FUNC(procstart),obj);
2620      gtk_signal_connect(GTK_OBJECT(obj->statusbar),"progress_end",
2621 			GTK_SIGNAL_FUNC(procend),obj);
2622      obj->loopmode = inifile_get_gboolean("loopMode",FALSE);
2623      obj->bouncemode = FALSE; /* Set to true by create_toolbar */
2624      obj->sensitive = TRUE;
2625      obj->vzoom_icon = obj->vzoom_slider = NULL;
2626      obj->hzoom_icon = obj->hzoom_slider = NULL;
2627      obj->speed_icon = obj->speed_slider = NULL;
2628      obj->speed_label = GTK_LABEL(gtk_label_new("S: 500%"));
2629      gtk_misc_set_alignment(GTK_MISC(obj->speed_label),0.0,0.0);
2630      gtk_widget_size_request(GTK_WIDGET(obj->speed_label),&req);
2631      gtk_widget_set_usize(GTK_WIDGET(obj->speed_label),req.width,req.height);
2632      obj->vzoom_label = GTK_LABEL(gtk_label_new("V: 1.000"));
2633      gtk_misc_set_alignment(GTK_MISC(obj->vzoom_label),0.0,0.0);
2634      gtk_widget_size_request(GTK_WIDGET(obj->vzoom_label),&req);
2635      gtk_widget_set_usize(GTK_WIDGET(obj->vzoom_label),req.width,req.height);
2636 
2637      obj->need_chunk_items = NULL;
2638      obj->need_selection_items = NULL;
2639      obj->need_clipboard_items = NULL;
2640      obj->need_undo_items = NULL;
2641      obj->zoom_items = NULL;
2642 
2643      fix_title ( obj );
2644 
2645      /* Bygg upp komponenterna */
2646      a = gtk_vbox_new( FALSE, 0 );
2647      gtk_container_add(GTK_CONTAINER(obj),a);
2648      b = create_menu( obj );
2649      obj->menubar = b;
2650      gtk_box_pack_start(GTK_BOX(a),b,FALSE,FALSE,0);
2651      b = gtk_table_new(3,4,FALSE);
2652      gtk_box_pack_start(GTK_BOX(a),b,TRUE,TRUE,0);
2653 
2654      c = create_toolbar( obj );
2655      obj->toolbar = c;
2656 
2657      c = gtk_event_box_new();
2658      gtk_container_add(GTK_CONTAINER(c),GTK_WIDGET(obj->toolbar));
2659      gtk_widget_size_request(c,&req);
2660      gtk_widget_set_usize(c,10,req.height);
2661 
2662      gtk_table_attach(GTK_TABLE(b),c,0,1,0,1,GTK_SHRINK|GTK_FILL,GTK_FILL,0,0);
2663 
2664      c = bitmap_new_from_data(vzoom_bits, vzoom_width, vzoom_height);
2665      bitmap_set_fg(BITMAP(c),0.8);
2666      gtk_table_attach(GTK_TABLE(b),c,1,2,0,1,GTK_FILL,0,0,0);
2667      obj->vzoom_icon = c;
2668 
2669      c = bitmap_new_from_data(hzoom_bits, hzoom_width, hzoom_height);
2670      bitmap_set_fg(BITMAP(c),0.8);
2671      gtk_table_attach(GTK_TABLE(b),c,2,3,0,1,GTK_FILL,0,0,0);
2672      obj->hzoom_icon = c;
2673 
2674      c = bitmap_new_from_data(speed_bits, speed_width, speed_height);
2675      bitmap_set_fg(BITMAP(c),0.8);
2676      gtk_table_attach(GTK_TABLE(b),c,3,4,0,1,GTK_FILL,0,0,0);
2677      obj->speed_icon = c;
2678 
2679      gtk_table_attach(GTK_TABLE(b),GTK_WIDGET(obj->view),0,1,1,2,
2680 		      GTK_EXPAND|GTK_FILL|GTK_SHRINK,
2681 		      GTK_EXPAND|GTK_FILL|GTK_SHRINK,0,0);
2682 
2683      c = gtk_vscale_new ( obj->zoom_adj );
2684      /* GTK1 doesn't work well with using the right mouse button press event.
2685       * As a work around, we use the release event instead */
2686 #if GTK_MAJOR_VERSION > 1
2687      gtk_signal_connect(GTK_OBJECT(c),"button_press_event",GTK_SIGNAL_FUNC(hzoom_scale_press),obj);
2688 #else
2689      gtk_signal_connect(GTK_OBJECT(c),"button_release_event",GTK_SIGNAL_FUNC(hzoom_scale_press),obj);
2690 #endif
2691      gtk_scale_set_digits(GTK_SCALE(c),3);
2692      gtk_scale_set_draw_value (GTK_SCALE(c), FALSE);
2693      gtk_table_attach(GTK_TABLE(b),c,2,3,1,2,0,GTK_EXPAND|GTK_FILL,0,0);
2694      obj->need_chunk_items = g_list_append(obj->need_chunk_items,c);
2695      obj->hzoom_slider = c;
2696 
2697      c = gtk_vscale_new ( obj->vertical_zoom_adj );
2698 #if GTK_MAJOR_VERSION > 1
2699      gtk_signal_connect(GTK_OBJECT(c),"button_press_event",GTK_SIGNAL_FUNC(vzoom_scale_press),obj);
2700 #else
2701      gtk_signal_connect(GTK_OBJECT(c),"button_release_event",GTK_SIGNAL_FUNC(vzoom_scale_press),obj);
2702 #endif
2703      gtk_scale_set_digits(GTK_SCALE(c),3);
2704      gtk_scale_set_draw_value (GTK_SCALE(c), FALSE);
2705      gtk_table_attach(GTK_TABLE(b),c,1,2,1,2,0,GTK_EXPAND|GTK_FILL,0,0);
2706      obj->need_chunk_items = g_list_append(obj->need_chunk_items,c);
2707      obj->vzoom_slider = c;
2708 
2709      c = gtk_vscale_new ( obj->speed_adj );
2710 #if GTK_MAJOR_VERSION > 1
2711      gtk_signal_connect(GTK_OBJECT(c),"button_press_event",GTK_SIGNAL_FUNC(speed_scale_press),obj);
2712 #else
2713      gtk_signal_connect(GTK_OBJECT(c),"button_release_event",GTK_SIGNAL_FUNC(speed_scale_press),obj);
2714 #endif
2715      gtk_scale_set_digits(GTK_SCALE(c),2);
2716      gtk_scale_set_draw_value (GTK_SCALE(c), FALSE);
2717      /* gtk_range_set_update_policy(GTK_RANGE(c),GTK_UPDATE_DELAYED); */
2718 #ifndef INV_SPEED
2719      gtk_range_set_inverted(GTK_RANGE(c),TRUE);
2720 #endif
2721      gtk_table_attach(GTK_TABLE(b),c,3,4,1,2,0,GTK_EXPAND|GTK_FILL,0,0);
2722      obj->need_chunk_items = g_list_append(obj->need_chunk_items,c);
2723      obj->speed_slider = c;
2724 
2725      c = gtk_hscrollbar_new ( obj->view_adj );
2726      gtk_table_attach(GTK_TABLE(b),c,0,1,2,3,GTK_FILL,0,0,0);
2727 
2728      c = GTK_WIDGET(obj->speed_label);
2729      gtk_table_attach(GTK_TABLE(b),c,1,4,3,4,GTK_FILL,0,2,0);
2730 
2731      c = gtk_event_box_new();
2732      gtk_container_add(GTK_CONTAINER(c),GTK_WIDGET (obj->statusbar));
2733      gtk_table_attach(GTK_TABLE(b),c,0,1,3,4,GTK_FILL,0,0,0);
2734 
2735      c = GTK_WIDGET(obj->vzoom_label);
2736      gtk_table_attach(GTK_TABLE(b),c,1,4,2,3,GTK_FILL,0,2,0);
2737 
2738      gtk_adjustment_value_changed(obj->speed_adj);
2739      gtk_adjustment_value_changed(obj->vertical_zoom_adj);
2740      gtk_widget_show_all(a);
2741 
2742      if (!inifile_get_gboolean(INI_SETTING_VZOOM,INI_SETTING_VZOOM_DEFAULT)) {
2743 	  gtk_widget_hide(obj->vzoom_icon);
2744 	  gtk_widget_hide(obj->vzoom_slider);
2745 	  gtk_widget_hide(GTK_WIDGET(obj->vzoom_label));
2746      }
2747 
2748      if (!inifile_get_gboolean(INI_SETTING_HZOOM,INI_SETTING_HZOOM_DEFAULT)) {
2749 	  gtk_widget_hide(obj->hzoom_icon);
2750 	  gtk_widget_hide(obj->hzoom_slider);
2751      }
2752 
2753      if (!inifile_get_gboolean(INI_SETTING_SPEED,INI_SETTING_SPEED_DEFAULT)) {
2754 	  gtk_widget_hide(obj->speed_icon);
2755 	  gtk_widget_hide(obj->speed_slider);
2756 	  gtk_widget_hide(GTK_WIDGET(obj->speed_label));
2757      }
2758 
2759      obj->show_labels = inifile_get_gboolean(INI_SETTING_SLABELS,INI_SETTING_SLABELS_DEFAULT);
2760      if (!obj->show_labels) {
2761 	  gtk_widget_hide(GTK_WIDGET(obj->vzoom_label));
2762 	  gtk_widget_hide(GTK_WIDGET(obj->speed_label));
2763      }
2764 
2765      gtk_window_set_policy(GTK_WINDOW(obj),FALSE,TRUE,FALSE);
2766 
2767      set_sensitive(obj->need_chunk_items, FALSE);
2768      set_sensitive(obj->need_selection_items, FALSE);
2769      set_sensitive(obj->need_clipboard_items, clipboard != NULL);
2770      set_sensitive(obj->need_undo_items, FALSE);
2771      set_sensitive(obj->need_redo_items, FALSE);
2772 
2773      if (!geometry_stack_pop(&window_geometry_stack,NULL,GTK_WINDOW(obj)))
2774 	  gtk_window_set_default_size(GTK_WINDOW(obj),540,230);
2775 
2776      /* Setup drag'n'drop target */
2777      gte.target = "text/uri-list";
2778      gte.flags = gte.info = 0;
2779      gtk_drag_dest_set(GTK_WIDGET(obj), GTK_DEST_DEFAULT_ALL, &gte, 1,
2780 		       GDK_ACTION_COPY | GDK_ACTION_MOVE);
2781 }
2782 
mainwindow_get_type(void)2783 GtkType mainwindow_get_type(void)
2784 {
2785 static GtkType id=0;
2786 if (!id) {
2787 	GtkTypeInfo info = {
2788 	     "Mainwindow",
2789 	     sizeof(Mainwindow),
2790 	     sizeof(MainwindowClass),
2791 	     (GtkClassInitFunc) mainwindow_class_init,
2792 	     (GtkObjectInitFunc) mainwindow_init
2793 	};
2794 	id=gtk_type_unique(gtk_window_get_type(),&info);
2795 	}
2796 return id;
2797 }
2798 
mainwindow_new(void)2799 GtkWidget *mainwindow_new(void)
2800 {
2801      return GTK_WIDGET( gtk_type_new(mainwindow_get_type()) );
2802 }
2803 
mainwindow_new_with_file(char * filename,gboolean log)2804 GtkWidget *mainwindow_new_with_file(char *filename, gboolean log)
2805 {
2806      Mainwindow *w;
2807      Document *doc;
2808      gchar *d;
2809      w = MAINWINDOW ( mainwindow_new() );
2810      d = make_filename_rooted(filename);
2811      doc = document_new_with_file(d, w->statusbar);
2812      if (doc != NULL) {
2813           mainwindow_set_document(w, doc, d);
2814           if (log) {
2815 	       inifile_set("lastOpenFile",d);
2816 	       recent_file(d);
2817 	  }
2818      }
2819      g_free(d);
2820      return GTK_WIDGET(w);
2821 }
2822 
reset_statusbar(Mainwindow * w)2823 static void reset_statusbar(Mainwindow *w)
2824 {
2825      status_bar_reset(w->statusbar);
2826 }
2827 
mainwindow_update_texts(void)2828 void mainwindow_update_texts(void)
2829 {
2830      list_object_foreach(mainwindow_objects,(GFunc)fix_title,NULL);
2831      list_object_foreach(mainwindow_objects,(GFunc)reset_statusbar,NULL);
2832      list_object_foreach(mainwindow_objects,(GFunc)update_desc,NULL);
2833 }
2834 
mainwindow_set_sensitive(Mainwindow * mw,gboolean sensitive)2835 void mainwindow_set_sensitive(Mainwindow *mw, gboolean sensitive)
2836 {
2837      gtk_widget_set_sensitive(mw->menubar,sensitive);
2838      gtk_widget_set_sensitive(mw->toolbar,sensitive);
2839      gtk_widget_set_sensitive(GTK_WIDGET(mw->view),sensitive);
2840      mw->sensitive = sensitive;
2841 }
2842 
mainwindow_set_all_sensitive(gboolean sensitive)2843 void mainwindow_set_all_sensitive(gboolean sensitive)
2844 {
2845      list_object_foreach(mainwindow_objects,(GFunc)mainwindow_set_sensitive,
2846 			 GINT_TO_POINTER(sensitive));
2847 }
2848 
mainwindow_repaint_views(void)2849 void mainwindow_repaint_views(void)
2850 {
2851      GList *l;
2852      for (l=mainwindow_objects->list; l!=NULL; l=l->next) {
2853 	  chunk_view_force_repaint(MAINWINDOW(l->data)->view);
2854      }
2855 }
2856