mp3splt-gtk
main_window.c
Go to the documentation of this file.
1 /**********************************************************
2  *
3  * mp3splt-gtk -- utility based on mp3splt,
4  * for mp3/ogg splitting without decoding
5  *
6  * Copyright: (C) 2005-2012 Alexandru Munteanu
7  * Contact: io_fx@yahoo.fr
8  *
9  * http://mp3splt.sourceforge.net/
10  *
11  *********************************************************/
12 /**********************************************************
13  *
14  * This program is free software; you can redistribute it and/or
15 
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28  * USA.
29  *
30  *********************************************************/
31 
32 /*!********************************************************
33  * \file
34  * The main window
35  *
36  * main file that initialises the menubar, the toolbar,
37  * the tabs, about window, status error messages
38  *
39  *********************************************************/
40 
41 //we include the "config.h" file from the config options
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #else
45 #define VERSION "0.7.3"
46 #define PACKAGE_NAME "mp3splt-gtk"
47 #endif
48 
49 #include "main_window.h"
50 
52 void set_input_filename(const gchar *filename, ui_state *ui)
53 {
54  if (filename == NULL)
55  {
56  return;
57  }
58 
59  lock_mutex(&ui->variables_mutex);
60  if (ui->gui->input_filename != NULL)
61  {
62  g_string_free(ui->gui->input_filename,TRUE);
63  }
64  ui->gui->input_filename = g_string_new(filename);
65 
66  if (ui->gui->open_file_chooser_button != NULL && !ui->status->file_selection_changed)
67  {
68  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(ui->gui->open_file_chooser_button), filename);
69  }
70  unlock_mutex(&ui->variables_mutex);
71 }
72 
80 {
81  if (gui->input_filename != NULL)
82  {
83  return gui->input_filename->str;
84  }
85 
86  return "";
87 }
88 
89 static gboolean configure_window_callback(GtkWindow *window, GdkEvent *event, ui_state *ui)
90 {
91  ui_set_main_win_position(ui, event->configure.x, event->configure.y);
92  ui_set_main_win_size(ui, event->configure.width, event->configure.height);
93 
94  refresh_drawing_area(ui->gui);
95  refresh_preview_drawing_areas(ui->gui);
96 
97  return FALSE;
98 }
99 
100 static void initialize_window(ui_state *ui)
101 {
102  GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
103  ui->gui->window = window;
104 
105  g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(configure_window_callback), ui);
106 
107  gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME" "VERSION);
108  gtk_container_set_border_width(GTK_CONTAINER(window), 0);
109 
110  g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(exit_application), ui);
111 
112  GString *imagefile = g_string_new("");
113  build_path(imagefile, PIXMAP_PATH, "mp3splt-gtk_ico"ICON_EXT);
114  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(imagefile->str, NULL);
115  gtk_window_set_default_icon(pixbuf);
116  g_string_free(imagefile, TRUE);
117 }
118 
119 static void activate_url(GtkAboutDialog *about, const gchar *link, ui_state *ui)
120 {
121 #ifdef __WIN32__
122  char default_browser[512] = { '\0' };
123  DWORD dwType, dwSize = sizeof(default_browser) - 1;
124 
125  SHGetValue(HKEY_CURRENT_USER,
126  TEXT("Software\\Clients\\StartMenuInternet"),
127  TEXT(""),
128  &dwType,
129  default_browser,
130  &dwSize);
131 
132  if (default_browser[0] != '\0')
133  {
134  SHGetValue(HKEY_LOCAL_MACHINE,
135  TEXT("SOFTWARE\\Clients\\StartMenuInternet"),
136  TEXT(""),
137  &dwType,
138  default_browser,
139  &dwSize);
140  }
141 
142  if (default_browser[0] != '\0')
143  {
144  char browser_exe[2048] = { '\0' };
145  dwSize = sizeof(browser_exe) - 1;
146 
147  char browser_exe_registry[1024] = { '\0' };
148  snprintf(browser_exe_registry, 1024,
149  "SOFTWARE\\Clients\\StartMenuInternet\\%s\\shell\\open\\command\\",
150  default_browser);
151 
152  SHGetValue(HKEY_LOCAL_MACHINE,
153  TEXT(browser_exe_registry), TEXT(""),
154  &dwType, browser_exe, &dwSize);
155 
156  if (browser_exe[0] != '\0')
157  {
158  gint browser_command_size = strlen(browser_exe) + strlen(link) + 2;
159  char *browser_command = g_malloc(sizeof(char) * browser_command_size);
160  if (browser_command)
161  {
162  snprintf(browser_command, browser_command_size, "%s %s",
163  browser_exe, link);
164 
165  STARTUPINFO si;
166  PROCESS_INFORMATION pinf;
167  ZeroMemory(&si, sizeof(si));
168  si.cb = sizeof(si);
169  ZeroMemory(&pinf, sizeof(pinf));
170 
171  if (! CreateProcess(NULL, browser_command,
172  NULL, NULL, FALSE, 0, NULL, NULL, &si, &pinf))
173  {
174  put_status_message(_("Error launching external command"), ui);
175  }
176 
177  CloseHandle(pinf.hProcess);
178  CloseHandle(pinf.hThread);
179 
180  g_free(browser_command);
181  browser_command = NULL;
182  }
183  }
184  }
185 #endif
186 }
187 
188 static void about_window(GtkWidget *widget, ui_state *ui)
189 {
190  GtkWidget *dialog = gtk_about_dialog_new();
191 
192  GString *imagefile = g_string_new("");
193  build_path(imagefile, PIXMAP_PATH, "mp3splt-gtk.png");
194  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(imagefile->str, NULL);
195  gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf);
196  g_string_free(imagefile, TRUE);
197 
198  gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), (gchar *)PACKAGE_NAME);
199  gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION);
200  gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog),
201  PACKAGE_NAME" : Copyright © 2005-2012 Alexandru"
202  " Munteanu \n mp3splt : Copyright © 2002-2005 Matteo Trotta");
203 
204  gchar b3[100] = { '\0' };
205  gchar *b1 = _("using");
206  gchar library_version[20] = { '\0' };
207  mp3splt_get_version(library_version);
208  g_snprintf(b3, 100, "-%s-\n%s libmp3splt %s",
209  _("release of "MP3SPLT_GTK_DATE), b1, library_version);
210 
211  gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), b3);
212 
213  gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog),
214  "\n"
215  "This program is free software; you can "
216  "redistribute it and/or \n"
217  "modify it under the terms of the GNU General Public License\n"
218  "as published by the Free Software "
219  "Foundation; either version 2\n"
220  "of the License, or (at your option) "
221  "any later version.\n\n"
222  "This program is distributed in the "
223  "hope that it will be useful,\n"
224  "but WITHOUT ANY WARRANTY; without even "
225  "the implied warranty of\n"
226  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
227  "GNU General Public License for more details.\n\n"
228  "You should have received a copy of the GNU General Public License\n"
229  "along with this program; if not, write "
230  "to the Free Software\n"
231  "Foundation, Inc., 59 Temple Place -"
232  "Suite 330, Boston, MA 02111-1307, "
233  "USA.");
234 
235  g_signal_connect(G_OBJECT(dialog), "activate-link", G_CALLBACK(activate_url), ui);
236 
237  gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog),
238  "http://mp3splt.sourceforge.net");
239  gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog),
240  "http://mp3splt.sourceforge.net");
241 
242  gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(dialog),
243  "Mario Blättermann <mariobl@gnome.org>");
244 
245  gtk_dialog_run(GTK_DIALOG(dialog));
246  gtk_widget_destroy(dialog);
247 }
248 
254 {
255  guint status_id = gtk_statusbar_get_context_id(gui->status_bar, "mess");
256  gtk_statusbar_pop(gui->status_bar, status_id);
257 }
258 
265 void put_status_message(const gchar *text, ui_state *ui)
266 {
268 }
269 
279 void put_status_message_with_type(const gchar *text, splt_message_type mess_type, ui_state *ui)
280 {
281  gui_state *gui = ui->gui;
282 
283  if (mess_type == SPLT_MESSAGE_INFO)
284  {
285  guint status_id = gtk_statusbar_get_context_id(gui->status_bar, "mess");
286  gtk_statusbar_pop(gui->status_bar, status_id);
287  gtk_statusbar_push(gui->status_bar, status_id, text);
288  }
289 
290  put_message_in_history(text, mess_type, ui);
291 }
292 
293 void set_stop_split_safe(gboolean value, ui_state *ui)
294 {
295  lock_mutex(&ui->variables_mutex);
296  ui->status->stop_split = value;
297  unlock_mutex(&ui->variables_mutex);
298 }
299 
301 void cancel_button_event(GtkWidget *widget, ui_state *ui)
302 {
303  lmanager_stop_split(ui);
304 
305  set_stop_split_safe(TRUE, ui);
306 
307  if (widget != NULL)
308  {
309  gtk_widget_set_sensitive(widget, FALSE);
310  }
311 
312  put_status_message(_(" info: stopping the split process.. please wait"), ui);
313 }
314 
315 static void show_preferences_window(GtkWidget *widget, ui_state *ui)
316 {
317  if (ui->gui->preferences_window == NULL)
318  {
319  ui->gui->preferences_window =
320  wh_create_window_with_close_button(_("Preferences"), 600, 450, GTK_WIN_POS_CENTER,
321  GTK_WINDOW(ui->gui->window), ui->gui->preferences_widget, NULL);
322  }
323 
324  wh_show_window(ui->gui->preferences_window);
325 }
326 
327 static void show_tracktype_window(GtkWidget *widget, ui_state *ui)
328 {
329  if (ui->gui->freedb_window == NULL)
330  {
331  ui->gui->freedb_window =
332  wh_create_window_with_close_button(_("TrackType"), 500, 300, GTK_WIN_POS_CENTER,
333  GTK_WINDOW(ui->gui->window),
334  ui->gui->freedb_widget,
335  ui->gui->freedb_add_button, NULL);
336  }
337 
338  wh_show_window(ui->gui->freedb_window);
339  hide_freedb_spinner(ui->gui);
340 }
341 
342 static void show_split_files_window(GtkWidget *widget, ui_state *ui)
343 {
344  if (ui->gui->split_files_window == NULL)
345  {
346  ui->gui->split_files_window =
347  wh_create_window_with_close_button(_("Split files"), 500, 300, GTK_WIN_POS_CENTER,
348  GTK_WINDOW(ui->gui->window),
349  ui->gui->split_files_widget,
350  ui->gui->queue_files_button, ui->gui->remove_file_button,
351  ui->gui->remove_all_files_button, NULL);
352  }
353 
354  wh_show_window(ui->gui->split_files_window);
355 }
356 
357 static void show_splitpoints_window(GtkWidget *widget, ui_state *ui)
358 {
359  if (ui->gui->splitpoints_window == NULL)
360  {
361  ui->gui->splitpoints_window =
362  wh_create_window_with_close_button(_("Splitpoints"), 500, 300, GTK_WIN_POS_CENTER,
363  GTK_WINDOW(ui->gui->window),
364  ui->gui->splitpoints_widget,
365  ui->gui->scan_trim_silence_button, ui->gui->scan_silence_button, NULL);
366  }
367 
368  wh_show_window(ui->gui->splitpoints_window);
369 }
370 
371 void set_is_splitting_safe(gboolean value, ui_state *ui)
372 {
373  lock_mutex(&ui->variables_mutex);
374  ui->status->splitting = value;
375  unlock_mutex(&ui->variables_mutex);
376 }
377 
378 gint get_is_splitting_safe(ui_state *ui)
379 {
380  lock_mutex(&ui->variables_mutex);
381  gint is_splitting = ui->status->splitting;
382  unlock_mutex(&ui->variables_mutex);
383  return is_splitting;
384 }
385 
386 static void _set_process_in_progress_safe(gboolean value, ui_state *ui)
387 {
388  lock_mutex(&ui->variables_mutex);
389  if (value)
390  {
391  ui->status->process_in_progress++;
392  }
393  else
394  {
395  ui->status->process_in_progress--;
396  }
397  unlock_mutex(&ui->variables_mutex);
398 }
399 
400 void set_process_in_progress_and_wait_safe(gboolean value, ui_state *ui)
401 {
402  if (value == TRUE)
403  {
404  while (get_process_in_progress_safe(ui))
405  {
406  g_usleep(G_USEC_PER_SEC / 4);
407  }
408  }
409 
410  _set_process_in_progress_safe(value, ui);
411 }
412 
413 void set_process_in_progress_safe(gboolean value, ui_state *ui)
414 {
415 #ifdef __WIN32__
416  _set_process_in_progress_safe(value, ui);
417 #endif
418 }
419 
420 gint get_process_in_progress_safe(ui_state *ui)
421 {
422  lock_mutex(&ui->variables_mutex);
423  gint process_in_progress = ui->status->process_in_progress;
424  unlock_mutex(&ui->variables_mutex);
425  return process_in_progress > 0;
426 }
427 
429 void split_button_event(GtkWidget *widget, ui_state *ui)
430 {
431  if (get_is_splitting_safe(ui))
432  {
433  put_status_message(_(" error: split in progress..."), ui);
434  return;
435  }
436 
437  if (get_output_directory(ui) != NULL)
438  {
439  split_action(ui);
440  }
441  else
442  {
443  put_status_message(_(" error: no path of split selected"), ui);
444  }
445 }
446 
447 void set_split_file_mode_safe(gint file_mode, ui_state *ui)
448 {
449  lock_mutex(&ui->variables_mutex);
450  ui->infos->split_file_mode = file_mode;
451  unlock_mutex(&ui->variables_mutex);
452 }
453 
454 gint get_split_file_mode_safe(ui_state *ui)
455 {
456  lock_mutex(&ui->variables_mutex);
457  gint file_mode = ui->infos->split_file_mode;
458  unlock_mutex(&ui->variables_mutex);
459 
460  return file_mode;
461 }
462 
463 static void single_file_mode_split_button_event(GtkWidget *widget, ui_state *ui)
464 {
465  set_split_file_mode_safe(FILE_MODE_SINGLE, ui);
466  split_button_event(widget, ui);
467 }
468 
470 static void show_messages_history_window(GtkWidget *widget, ui_state *ui)
471 {
472  wh_show_window(ui->gui->mess_history_window);
473 }
474 
475 #ifndef NO_GNOME
476 static void ShowHelp(GtkWidget *widget, ui_state *ui)
477 {
478  GError* gerror = NULL;
479  gtk_show_uri(gdk_screen_get_default(), "ghelp:mp3splt-gtk", gtk_get_current_event_time(), &gerror);
480 }
481 #endif
482 
483 static gchar *my_dgettext(const gchar *key, const gchar *domain)
484 {
485  return dgettext("mp3splt-gtk", key);
486 }
487 
488 static void player_pause_action(GtkWidget *widget, ui_state *ui)
489 {
490  pause_event(ui->gui->pause_button, ui);
491 }
492 
493 static void player_seek_forward_action(GtkWidget *widget, ui_state *ui)
494 {
495  gfloat total_time = ui->infos->total_time;
496  gfloat new_time = ui->infos->current_time * 10 + 2./100. * total_time * 10;
497  if (new_time > total_time * 10) { new_time = total_time * 10; }
498  player_seek(new_time, ui);
499 }
500 
501 static void player_seek_backward_action(GtkWidget *widget, ui_state *ui)
502 {
503  gfloat total_time = ui->infos->total_time;
504  gfloat new_time = ui->infos->current_time * 10 - 2./100. * total_time * 10;
505  if (new_time <= 0) { new_time = 0; }
506  player_seek(new_time, ui);
507 }
508 
509 static void player_big_seek_forward_action(GtkWidget *widget, ui_state *ui)
510 {
511  gfloat total_time = ui->infos->total_time;
512  gfloat new_time = ui->infos->current_time * 10 + 15./100. * total_time * 10;
513  if (new_time > total_time * 10) { new_time = total_time * 10; }
514  player_seek(new_time, ui);
515 }
516 
517 static void player_big_seek_backward_action(GtkWidget *widget, ui_state *ui)
518 {
519  gfloat total_time = ui->infos->total_time;
520  gfloat new_time = ui->infos->current_time * 10 - 15./100. * total_time * 10;
521  if (new_time <= 0) { new_time = 0; }
522  player_seek(new_time, ui);
523 }
524 
525 static void player_small_seek_forward_action(GtkWidget *widget, ui_state *ui)
526 {
527  gfloat total_time = ui->infos->total_time;
528  gfloat new_time = ui->infos->current_time * 10 + 100 * 3 * 10;
529  if (new_time > total_time * 10) { new_time = total_time * 10; }
530  player_seek(new_time, ui);
531 }
532 
533 static void player_small_seek_backward_action(GtkWidget *widget, ui_state *ui)
534 {
535  gfloat new_time = ui->infos->current_time * 10 - 100 * 3 * 10;
536  if (new_time <= 0) { new_time = 0; }
537  player_seek(new_time, ui);
538 }
539 
540 static void player_seek_to_next_splitpoint_action(GtkWidget *widget, ui_state *ui)
541 {
542  gint time_left = -1;
543  gint time_right = -1;
544  get_current_splitpoints_time_left_right(&time_left, &time_right, NULL, ui);
545 
546  if (time_right != -1)
547  {
548  player_seek(time_right * 10, ui);
549  }
550 }
551 
552 static void player_seek_to_previous_splitpoint_action(GtkWidget *widget, ui_state *ui)
553 {
554  gint time_left = -1;
555  gint time_right = -1;
556  get_current_splitpoints_time_left_right(&time_left, &time_right, NULL, ui);
557 
558  if (time_left != -1)
559  {
560  player_seek(time_left * 10, ui);
561  }
562 }
563 
564 static void delete_closest_splitpoint(GtkWidget *widget, ui_state *ui)
565 {
566  gint left_index_point = -1;
567  gint right_index_point = -1;
568 
569  gint i = 0;
570  for (i = 0; i < ui->infos->splitnumber; i++ )
571  {
572  gint current_point_hundr_secs = get_splitpoint_time(i, ui);
573  if (current_point_hundr_secs <= ui->infos->current_time)
574  {
575  left_index_point = i;
576  continue;
577  }
578 
579  if (current_point_hundr_secs > ui->infos->current_time + (DELTA * 2))
580  {
581  right_index_point = i;
582  break;
583  }
584  }
585 
586  if (left_index_point == -1 && right_index_point == -1)
587  {
588  return;
589  }
590 
591  gint time_to_left = INT_MAX;
592  if (left_index_point != -1)
593  {
594  time_to_left = ui->infos->current_time - get_splitpoint_time(left_index_point, ui);
595  }
596 
597  gint time_to_right = INT_MAX;
598  if (right_index_point != -1)
599  {
600  time_to_right = get_splitpoint_time(right_index_point, ui) - ui->infos->current_time;
601  }
602 
603  if (time_to_right > time_to_left)
604  {
605  remove_splitpoint(left_index_point, TRUE, ui);
606  }
607  else
608  {
609  remove_splitpoint(right_index_point, TRUE, ui);
610  }
611 }
612 
613 static void zoom_in(GtkWidget *widget, ui_state *ui)
614 {
615  gdouble fraction = 40./100. * ui->infos->zoom_coeff;
616  ui->infos->zoom_coeff += fraction;
617  adjust_zoom_coeff(ui->infos);
618  refresh_drawing_area(ui->gui);
619 }
620 
621 static void zoom_out(GtkWidget *widget, ui_state *ui)
622 {
623  gdouble fraction = 40./100. * ui->infos->zoom_coeff;
624  ui->infos->zoom_coeff -= fraction;
625  adjust_zoom_coeff(ui->infos);
626  refresh_drawing_area(ui->gui);
627 }
628 
629 static gboolean window_key_press_event(GtkWidget *window, GdkEventKey *event, ui_state *ui)
630 {
631  if (event->type != GDK_KEY_PRESS) { return FALSE; }
632 
633  if (event->state != 0)
634  {
635  return FALSE;
636  }
637 
638  switch (event->keyval)
639  {
640  case GDK_Left:
641  player_seek_backward_action(NULL, ui);
642  return TRUE;
643  case GDK_Right:
644  player_seek_forward_action(NULL, ui);
645  return TRUE;
646  default:
647  return FALSE;
648  }
649 }
650 
651 void add_filters_to_file_chooser(GtkWidget *file_chooser)
652 {
653  GtkFileFilter *our_filter = gtk_file_filter_new();
654  gtk_file_filter_set_name(our_filter, _("mp3 and ogg files (*.mp3 *.ogg)"));
655  gtk_file_filter_add_pattern(our_filter, "*.mp3");
656  gtk_file_filter_add_pattern(our_filter, "*.ogg");
657  gtk_file_filter_add_pattern(our_filter, "*.MP3");
658  gtk_file_filter_add_pattern(our_filter, "*.OGG");
659  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), our_filter);
660 
661  our_filter = gtk_file_filter_new();
662  gtk_file_filter_set_name (our_filter, _("mp3 files (*.mp3)"));
663  gtk_file_filter_add_pattern(our_filter, "*.mp3");
664  gtk_file_filter_add_pattern(our_filter, "*.MP3");
665  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), our_filter);
666 
667  our_filter = gtk_file_filter_new();
668  gtk_file_filter_set_name (our_filter, _("ogg files (*.ogg)"));
669  gtk_file_filter_add_pattern(our_filter, "*.ogg");
670  gtk_file_filter_add_pattern(our_filter, "*.OGG");
671  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), our_filter);
672 }
673 
678 static void open_file_button_event(GtkWidget *widget, ui_state *ui)
679 {
680  GtkWidget *file_chooser = gtk_file_chooser_dialog_new(_("Choose File"), NULL,
681  GTK_FILE_CHOOSER_ACTION_OPEN,
682  GTK_STOCK_CANCEL,
683  GTK_RESPONSE_CANCEL,
684  GTK_STOCK_OPEN,
685  GTK_RESPONSE_ACCEPT, NULL);
686 
687  add_filters_to_file_chooser(file_chooser);
688  wh_set_browser_directory_handler(ui, file_chooser);
689 
690  if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT)
691  {
692  gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));
693  file_chooser_ok_event(filename, ui);
694  if (filename)
695  {
696  g_free(filename);
697  filename = NULL;
698  }
699  }
700 
701  gtk_widget_destroy(file_chooser);
702  remove_status_message(ui->gui);
703 }
704 
706 static GtkWidget *create_menu_bar(ui_state *ui)
707 {
708  static const GtkActionEntry entries[] = {
709  //name, stock id, label, accelerator, tooltip, callback
710  { "FileMenu", NULL, N_("_File"), NULL, NULL, NULL },
711  { "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL },
712  { "PlayerMenu", NULL, N_("_Player"), NULL, NULL, NULL },
713  { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
714 
715  { "Open", GTK_STOCK_OPEN, N_("_Open..."), "<Ctrl>O", N_("Open"),
716  G_CALLBACK(open_file_button_event) },
717 
718  { "AddFilesToBatch", GTK_STOCK_DIRECTORY,
719  N_("_Add files or directories to batch ..."), "<Ctrl>D",
720  N_("Add files or directories to batch"),
721  G_CALLBACK(multiple_files_add_button_event) },
722 
723  { "Import", GTK_STOCK_FILE, N_("_Import splitpoints from file..."), "<Ctrl>I",
724  N_("Import splitpoints from file..."), G_CALLBACK(import_event) },
725 
726  { "ImportFromTrackType", GTK_STOCK_FIND, N_("Import splitpoints from _TrackType.org..."), "<Ctrl>T",
727  N_("Import splitpoints from TrackType.org..."),
728  G_CALLBACK(show_tracktype_window) },
729 
730  { "Export", GTK_STOCK_SAVE_AS, N_("_Export splitpoints..."), "<Ctrl>E",
731  N_("Export splitpoints"), G_CALLBACK(ChooseCueExportFile) },
732 
733  { "Preferences", GTK_STOCK_PREFERENCES, N_("_Preferences"), "<Ctrl>P", N_("Preferences"),
734  G_CALLBACK(show_preferences_window) },
735 
736  { "SplitFiles", NULL, N_("Split _files"), "<Ctrl>F", N_("Split files"),
737  G_CALLBACK(show_split_files_window) },
738 
739  { "Splitpoints", GTK_STOCK_EDIT, N_("_Splitpoints"), "<Ctrl>L", N_("Splitpoints"),
740  G_CALLBACK(show_splitpoints_window) },
741 
742  { "Split", GTK_STOCK_APPLY, N_("_Split !"), "<Ctrl>S", N_("Split !"),
743  G_CALLBACK(single_file_mode_split_button_event) },
744 
745  { "BatchSplit", GTK_STOCK_EXECUTE, N_("_Batch split !"), "<Ctrl>B", N_("Batch split !"),
746  G_CALLBACK(batch_file_mode_split_button_event) },
747 
748  { "Quit", GTK_STOCK_QUIT, N_("_Quit"), "<Ctrl>Q", N_("Quit"),
749  G_CALLBACK(exit_application_bis) },
750 
751 #ifndef NO_GNOME
752  { "Contents", GTK_STOCK_HELP, N_("_Contents"), "F1", N_("Contents"),
753  G_CALLBACK(ShowHelp)},
754 #endif
755 
756  { "Messages history", GTK_STOCK_INFO, N_("Messages _history"), "<Ctrl>H", N_("Messages history"),
757  G_CALLBACK(show_messages_history_window) },
758 
759  { "About", GTK_STOCK_ABOUT, N_("_About"), "<Ctrl>A", N_("About"),
760  G_CALLBACK(about_window)},
761 
762  //player key bindings
763  { "Player_pause", NULL, N_("P_ause / Play"), "space", N_("Pause/Play"),
764  G_CALLBACK(player_pause_action)},
765 
766  { "Player_forward", GTK_STOCK_MEDIA_FORWARD, N_("Seek _forward"), "Right", N_("Seek forward"),
767  G_CALLBACK(player_seek_forward_action)},
768  { "Player_backward", GTK_STOCK_MEDIA_REWIND, N_("Seek _backward"), "Left", N_("Seek backward"),
769  G_CALLBACK(player_seek_backward_action)},
770 
771  { "Player_small_forward", NULL, N_("Small seek f_orward"), "<Alt>Right", N_("Small seek forward"),
772  G_CALLBACK(player_small_seek_forward_action)},
773  { "Player_small_backward", NULL, N_("Small seek back_ward"), "<Alt>Left", N_("Small seek backward"),
774  G_CALLBACK(player_small_seek_backward_action)},
775 
776  { "Player_big_forward", NULL, N_("Big seek fo_rward"), "<Shift>Right", N_("Big seek forward"),
777  G_CALLBACK(player_big_seek_forward_action)},
778  { "Player_big_backward", NULL, N_("Big seek bac_kward"), "<Shift>Left", N_("Big seek backward"),
779  G_CALLBACK(player_big_seek_backward_action)},
780 
781  { "Player_next_splitpoint", GTK_STOCK_MEDIA_NEXT, N_("Seek to _next splitpoint"), "<Ctrl>Right",
782  N_("Seek to next splitpoint"), G_CALLBACK(player_seek_to_next_splitpoint_action)},
783  { "Player_previous_splitpoint", GTK_STOCK_MEDIA_PREVIOUS, N_("Seek to _previous splitpoint"), "<Ctrl>Left",
784  N_("Seek to previous splitpoint"), G_CALLBACK(player_seek_to_previous_splitpoint_action)},
785 
786  { "Add_splitpoint", GTK_STOCK_ADD, N_("Add _splitpoint"), "s",
787  N_("Add splitpoint"), G_CALLBACK(add_splitpoint_from_player)},
788 
789  { "Delete_closest_splitpoint", GTK_STOCK_REMOVE, N_("_Delete closest splitpoint"), "d",
790  N_("Delete closest splitpoint"), G_CALLBACK(delete_closest_splitpoint)},
791 
792  { "Zoom_in", GTK_STOCK_ZOOM_IN, N_("Zoom _in"), "<Ctrl>plus", N_("Zoom in"), G_CALLBACK(zoom_in)},
793  { "Zoom_out", GTK_STOCK_ZOOM_OUT, N_("Zoom _out"), "<Ctrl>minus", N_("Zoom out"), G_CALLBACK(zoom_out)},
794  };
795 
796  static const gchar *ui_info =
797  "<ui>"
798  " <menubar name='MenuBar'>"
799  " <menu action='FileMenu'>"
800  " <menuitem action='Open'/>"
801  " <menuitem action='AddFilesToBatch'/>"
802  " <separator/>"
803  " <menuitem action='Import'/>"
804  " <menuitem action='ImportFromTrackType'/>"
805  " <menuitem action='Export'/>"
806  " <separator/>"
807  " <menuitem action='Preferences'/>"
808  " <separator/>"
809  " <menuitem action='Split'/>"
810  " <menuitem action='BatchSplit'/>"
811  " <separator/>"
812  " <menuitem action='Quit'/>"
813  " </menu>"
814  " <menu action='ViewMenu'>"
815  " <menuitem action='Splitpoints'/>"
816  " <menuitem action='SplitFiles'/>"
817  " </menu>"
818  " <menu action='PlayerMenu'>"
819  " <menuitem action='Player_pause'/>"
820  " <separator/>"
821  " <menuitem action='Player_forward'/>"
822  " <menuitem action='Player_backward'/>"
823  " <menuitem action='Player_small_forward'/>"
824  " <menuitem action='Player_small_backward'/>"
825  " <menuitem action='Player_big_forward'/>"
826  " <menuitem action='Player_big_backward'/>"
827  " <menuitem action='Player_next_splitpoint'/>"
828  " <menuitem action='Player_previous_splitpoint'/>"
829  " <separator/>"
830  " <menuitem action='Add_splitpoint'/>"
831  " <menuitem action='Delete_closest_splitpoint'/>"
832  " <separator/>"
833  " <menuitem action='Zoom_in'/>"
834  " <menuitem action='Zoom_out'/>"
835  " </menu>"
836  " <menu action='HelpMenu'>"
837 #ifndef NO_GNOME
838  " <menuitem action='Contents'/>"
839  " <separator/>"
840 #endif
841  " <menuitem action='Messages history'/>"
842  " <separator/>"
843  " <menuitem action='About'/>"
844  " </menu>"
845  " </menubar>"
846  "</ui>";
847 
848  GtkActionGroup *action_group = gtk_action_group_new("Actions");
849  ui->gui->action_group = action_group;
850 
851  gtk_action_group_set_translation_domain(action_group, "mp3splt-gtk");
852  gtk_action_group_set_translate_func(action_group,
853  (GtkTranslateFunc)my_dgettext, NULL, NULL);
854 
855  gtk_action_group_add_actions(action_group, entries, G_N_ELEMENTS(entries), ui);
856  GtkUIManager *uim = gtk_ui_manager_new();
857  gtk_ui_manager_insert_action_group(uim, action_group, 0);
858 
859  g_signal_connect(G_OBJECT(ui->gui->window), "key_press_event",
860  G_CALLBACK(window_key_press_event), ui);
861 
862  gtk_window_add_accel_group(GTK_WINDOW(ui->gui->window), gtk_ui_manager_get_accel_group(uim));
863  gtk_ui_manager_add_ui_from_string(uim, ui_info, -1, NULL);
864 
865  GtkWidget *menu_box = wh_hbox_new();
866  gtk_box_pack_start(GTK_BOX(menu_box), gtk_ui_manager_get_widget(uim, "/MenuBar"), FALSE, FALSE, 0);
867 
868  player_key_actions_set_sensitivity(FALSE, ui->gui);
869 
870  return menu_box;
871 }
872 
873 static void file_selection_changed(GtkFileChooser *open_file_chooser, ui_state *ui)
874 {
875  gchar *filename = gtk_file_chooser_get_filename(open_file_chooser);
876  gchar *previous_fname = get_input_filename(ui->gui);
877 
878  if (previous_fname != NULL && filename != NULL &&
879  strcmp(filename, previous_fname) == 0)
880  {
881  return;
882  }
883 
884  if (filename != NULL)
885  {
886  ui->status->file_selection_changed = TRUE;
887  file_chooser_ok_event(filename, ui);
888  ui->status->file_selection_changed = FALSE;
889 
890  g_free(filename);
891  filename = NULL;
892  return;
893  }
894 }
895 
896 static void file_set_event(GtkFileChooserButton *open_file_chooser_button, ui_state *ui)
897 {
898  file_selection_changed(GTK_FILE_CHOOSER(open_file_chooser_button), ui);
899 }
900 
901 static GtkWidget *create_choose_file_frame(ui_state *ui)
902 {
903  GtkWidget *open_file_chooser_button = gtk_file_chooser_button_new(_("Open file ..."), GTK_FILE_CHOOSER_ACTION_OPEN);
904  dnd_add_drag_data_received_to_widget(open_file_chooser_button, DND_SINGLE_MODE_AUDIO_FILE, ui);
905 
906  ui->gui->open_file_chooser_button = open_file_chooser_button;
907  add_filters_to_file_chooser(open_file_chooser_button);
908  wh_set_browser_directory_handler(ui, open_file_chooser_button);
909 
910  g_signal_connect(G_OBJECT(open_file_chooser_button), "file-set", G_CALLBACK(file_set_event), ui);
911  g_signal_connect(G_OBJECT(open_file_chooser_button), "selection-changed",
912  G_CALLBACK(file_selection_changed), ui);
913 
914  gchar *fname = get_input_filename(ui->gui);
915  if (fname != NULL && strlen(fname) != 0)
916  {
917  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(open_file_chooser_button), get_input_filename(ui->gui));
918  }
919 
920  return open_file_chooser_button;
921 }
922 
924 static GtkWidget *create_main_vbox(ui_state *ui)
925 {
926  GtkWidget *main_vbox = wh_vbox_new();
927  gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 0);
928 
929  /* tabbed notebook */
930  GtkWidget *notebook = gtk_notebook_new();
931 
932  gtk_box_pack_start(GTK_BOX(main_vbox), notebook, TRUE, TRUE, 0);
933  gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
934  gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), TRUE);
935  gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
936  gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
937 
938  /* player page */
939  GtkWidget *player_vbox = wh_vbox_new();
940 
941  //file & split button hbox
942  GtkWidget *top_hbox = wh_hbox_new();
943  gtk_box_pack_start(GTK_BOX(player_vbox), top_hbox, FALSE, FALSE, 0);
944 
945  //choose file
946  gtk_box_pack_start(GTK_BOX(top_hbox), create_choose_file_frame(ui), TRUE, TRUE, 0);
947 
948  //single mode split button
949  GtkWidget *split_button = wh_create_cool_button(GTK_STOCK_APPLY,_("Split !"), FALSE);
950  g_signal_connect(G_OBJECT(split_button), "clicked",
951  G_CALLBACK(single_file_mode_split_button_event), ui);
952  gtk_box_pack_start(GTK_BOX(top_hbox), split_button, FALSE, FALSE, 4);
953 
954  ui->gui->player_box = create_player_control_frame(ui);
955  gtk_box_pack_start(GTK_BOX(player_vbox), ui->gui->player_box, FALSE, FALSE, 0);
956 
957  ui->gui->playlist_box = create_player_playlist_frame(ui);
958  gtk_box_pack_start(GTK_BOX(player_vbox), ui->gui->playlist_box, TRUE, TRUE, 0);
959 
960  GtkWidget *notebook_label = wh_create_cool_label(GTK_STOCK_APPLY, _("Manual single file split"));
961  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), player_vbox, notebook_label);
962 
963  /* splitpoints page */
964  ui->gui->splitpoints_widget = create_splitpoints_frame(ui);
965 
966  /* split files page */
967  ui->gui->split_files_widget = create_split_files_frame(ui);
968 
969  /* freedb page */
970  ui->gui->freedb_widget = create_freedb_frame(ui);
971 
972  /* special split page */
973  GtkWidget *special_split_vbox = wh_vbox_new();
974  gtk_container_set_border_width(GTK_CONTAINER(special_split_vbox), 0);
975  GtkWidget *frame = create_special_split_page(ui);
976  gtk_box_pack_start(GTK_BOX(special_split_vbox), frame, TRUE, TRUE, 0);
977 
978  notebook_label = wh_create_cool_label(GTK_STOCK_EXECUTE, _("Batch & automatic split"));
979  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), special_split_vbox, notebook_label);
980 
981  /* preferences widget */
982  ui->gui->preferences_widget = create_choose_preferences(ui);
983 
984  /* progress bar */
985  GtkProgressBar *percent_progress_bar = GTK_PROGRESS_BAR(gtk_progress_bar_new());
986  ui->gui->percent_progress_bar = percent_progress_bar;
987  gtk_progress_bar_set_fraction(percent_progress_bar, 0.0);
988  gtk_progress_bar_set_text(percent_progress_bar, "");
989 
990 #if GTK_MAJOR_VERSION >= 3
991  gtk_progress_bar_set_show_text(percent_progress_bar, TRUE);
992 #endif
993 
994  GtkWidget *hbox = wh_hbox_new();
995  gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(percent_progress_bar), TRUE, TRUE, 0);
996 
997  //stop button
998  GtkWidget *cancel_button = wh_create_cool_button(GTK_STOCK_STOP,_("S_top"), FALSE);
999  ui->gui->cancel_button = cancel_button;
1000  g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(cancel_button_event), ui);
1001  gtk_box_pack_start(GTK_BOX(hbox), cancel_button, FALSE, TRUE, 3);
1002  gtk_widget_set_sensitive(cancel_button, FALSE);
1003 
1004  gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 2);
1005 
1006  /* show messages history dialog */
1008 
1009  /* statusbar */
1010  GtkStatusbar *status_bar = GTK_STATUSBAR(gtk_statusbar_new());
1011  ui->gui->status_bar = status_bar;
1012 
1013  gtk_box_pack_start(GTK_BOX(main_vbox), GTK_WIDGET(status_bar), FALSE, FALSE, 0);
1014 
1015  return main_vbox;
1016 }
1017 
1018 static void move_and_resize_main_window(ui_state *ui)
1019 {
1020  const ui_main_window *main_win = ui_get_main_window_infos(ui);
1021 
1022  gint x = main_win->root_x_pos;
1023  gint y = main_win->root_y_pos;
1024 
1025  if (x != 0 && y != 0)
1026  {
1027  gtk_window_move(GTK_WINDOW(ui->gui->window), x, y);
1028  }
1029  else
1030  {
1031  gtk_window_set_position(GTK_WINDOW(ui->gui->window), GTK_WIN_POS_CENTER);
1032  }
1033 
1034  gtk_window_resize(GTK_WINDOW(ui->gui->window), main_win->width, main_win->height);
1035 }
1036 
1037 void create_application(ui_state *ui)
1038 {
1039  initialize_window(ui);
1040 
1041  GtkWidget *window_vbox = wh_vbox_new();
1042  gtk_container_add(GTK_CONTAINER(ui->gui->window), window_vbox);
1043 
1044  gtk_box_pack_start(GTK_BOX(window_vbox), create_menu_bar(ui), FALSE, FALSE, 0);
1045  gtk_box_pack_start(GTK_BOX(window_vbox), create_main_vbox(ui), TRUE, TRUE, 0);
1046 
1047  ui_load_preferences(ui);
1048 
1049  move_and_resize_main_window(ui);
1050 
1051  gtk_widget_show_all(ui->gui->window);
1052 
1053  if (ui->infos->selected_player != PLAYER_GSTREAMER)
1054  {
1055  gtk_widget_hide(ui->gui->playlist_box);
1056  }
1057 
1058  hide_freedb_spinner(ui->gui);
1059 }
1060 
1066 {
1067  char *error_from_library = mp3splt_get_strerror(ui->mp3splt_state, error);
1068  if (error_from_library == NULL) { return; }
1069 
1070  put_status_message(error_from_library, ui);
1071  free(error_from_library);
1072  error_from_library = NULL;
1073 }
1074 
1075 static gboolean print_status_bar_confirmation_idle(ui_with_err *ui_err)
1076 {
1077  print_status_bar_confirmation(ui_err->err, ui_err->ui);
1078  g_free(ui_err);
1079  return FALSE;
1080 }
1081 
1082 void print_status_bar_confirmation_in_idle(gint error, ui_state *ui)
1083 {
1084  ui_with_err *ui_err = g_malloc0(sizeof(ui_with_err));
1085  ui_err->err = error;
1086  ui_err->ui = ui;
1087 
1088  gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE,
1089  (GSourceFunc)print_status_bar_confirmation_idle, ui_err, NULL);
1090 }
1091