/* main.c * sets up the GUI and connects the main callback functions. * * for Denemo, a gtk+ frontend to GNU Lilypond * (c) 1999-2005 Matthew Hiller, Adam Tee */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_GETOPT_H #include #endif #include #include #include #include #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_WAIT_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #include "importxml.h" #include #include #include #include #include "midiseq.h" GList *displays = NULL; midi_seq *sq; #include "view.h" #include "exportxml.h" #include "runsilent.h" #include "binreloc.h" #include "alsaplayback.h" int openfile (gchar * name); static const GtkStockItem denemo_stock_items[] = { {"denemo-staccato", N_("Staccato"), (GdkModifierType) 0, 0, NULL}, {"denemo-staccatissimo", N_("Staccatissimo"), (GdkModifierType) 0, 0, NULL}, {"denemo-marcato", N_("Marcato"), (GdkModifierType) 0, 0, NULL}, {"denemo-accent", N_("Accent"), (GdkModifierType) 0, 0, NULL}, {"denemo-fermata", N_("Fermata"), (GdkModifierType) 0, 0, NULL}, {"denemo-coda", N_("Coda"), (GdkModifierType) 0, 0, NULL}, {"denemo-tenuto", N_("Tenuto"), (GdkModifierType) 0, 0, NULL}, {"denemo-turn", N_("Turn"), (GdkModifierType) 0, 0, NULL}, {"denemo-reverse-turn", N_("Reverse turn"), (GdkModifierType) 0, 0, NULL}, {"denemo-trill", N_("Trill"), (GdkModifierType) 0, 0, NULL}, {"denemo-mordent", N_("Mordent"), (GdkModifierType) 0, 0, NULL}, {"denemo-up-bow", N_("Up bow"), (GdkModifierType) 0, 0, NULL}, {"denemo-down-bow", N_("Down bow"), (GdkModifierType) 0, 0, NULL}, {"denemo-rheel", N_("Right heel"), (GdkModifierType) 0, 0, NULL}, {"denemo-lheel", N_("Left heel"), (GdkModifierType) 0, 0, NULL}, {"denemo-ltoe", N_("Left toe"), (GdkModifierType) 0, 0, NULL}, {"denemo-rtoe", N_("Right toe"), (GdkModifierType) 0, 0, NULL}, {"denemo-whole-note", N_("Whole note"), (GdkModifierType) 0, 0, NULL}, {"denemo-half-note", N_("Half note"), (GdkModifierType) 0, 0, NULL}, {"denemo-quarter-note", N_("Quarter note"), (GdkModifierType) 0, 0, NULL}, {"denemo-eight-note", N_("Eight note"), (GdkModifierType) 0, 0, NULL}, {"denemo-sixteenth-note", N_("Sixteenth note"), (GdkModifierType) 0, 0, NULL}, {"denemo-whole-rest", N_("Whole rest"), (GdkModifierType) 0, 0, NULL}, {"denemo-half-rest", N_("Half rest"), (GdkModifierType) 0, 0, NULL}, {"denemo-quarter-rest", N_("Quarter rest"), (GdkModifierType) 0, 0, NULL}, {"denemo-eight-rest", N_("Eigth rest"), (GdkModifierType) 0, 0, NULL}, {"denemo-sixteenth-rest", N_("Sixteenth rest"), (GdkModifierType) 0, 0, NULL}, {"denemo-prall", N_("Prall"), (GdkModifierType) 0, 0, NULL}, {"denemo-flageolet", N_("Flageolet"), (GdkModifierType) 0, 0, NULL}, {"denemo-prallmordent", N_("PrallMordent"), (GdkModifierType) 0, 0, NULL}, {"denemo-prallprall", N_("PrallPrall"), (GdkModifierType) 0, 0, NULL}, {"denemo-open", N_("Open"), (GdkModifierType) 0, 0, NULL}, {"denemo-segno", N_("Segno"), (GdkModifierType) 0, 0, NULL}, {"denemo-stopped", N_("Stopped"), (GdkModifierType) 0, 0, NULL}, {"denemo-thumb", N_("Thumb"), (GdkModifierType) 0, 0, NULL}, {"denemo-upprall", N_("Upprall"), (GdkModifierType) 0, 0, NULL}, {"denemo-arpeggio", N_("Arpeggio"), (GdkModifierType) 0, 0, NULL} }; static void register_stock_icon (GtkIconFactory * icon_factory, const gchar * stock_id, const gchar * file) { GtkIconSet *icon_set; GdkPixbuf *pixbuf; gchar *path; gchar *syspath = gbr_find_data_dir (PKGDATADIR); gchar *syspath2 = g_strconcat (syspath, "/pixmaps/", NULL); path = g_build_filename (syspath2, file, NULL); #ifdef DEBUG g_print ("path is %s\n", path); #endif pixbuf = gdk_pixbuf_new_from_file (path, NULL); g_assert (pixbuf != NULL); icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); g_object_unref (pixbuf); gtk_icon_factory_add (icon_factory, stock_id, icon_set); g_free (path); g_free (syspath); g_free (syspath2); //g_free(pixbuf); } static void register_stock_items () { GtkIconFactory *icon_factory; /* Load stock items (icons) */ gtk_stock_add_static (denemo_stock_items, G_N_ELEMENTS (denemo_stock_items)); icon_factory = gtk_icon_factory_new (); gtk_icon_factory_add_default (icon_factory); register_stock_icon (icon_factory, "denemo-staccato", "staccato.svg"); register_stock_icon (icon_factory, "denemo-staccatissimo", "staccatissimo.svg"); register_stock_icon (icon_factory, "denemo-marcato", "marcato.svg"); register_stock_icon (icon_factory, "denemo-accent", "accent.svg"); register_stock_icon (icon_factory, "denemo-fermata", "fermata.svg"); register_stock_icon (icon_factory, "denemo-tenuto", "tenuto.svg"); register_stock_icon (icon_factory, "denemo-turn", "turn.svg"); register_stock_icon (icon_factory, "denemo-reverse-turn", "reverse-turn.svg"); register_stock_icon (icon_factory, "denemo-trill", "trill.svg"); register_stock_icon (icon_factory, "denemo-mordent", "mordent.svg"); register_stock_icon (icon_factory, "denemo-up-bow", "upbow.svg"); register_stock_icon (icon_factory, "denemo-down-bow", "downbow.svg"); register_stock_icon (icon_factory, "denemo-rheel", "rheel.svg"); register_stock_icon (icon_factory, "denemo-lheel", "lheel.svg"); register_stock_icon (icon_factory, "denemo-rtoe", "rtoe.svg"); register_stock_icon (icon_factory, "denemo-ltoe", "ltoe.svg"); register_stock_icon (icon_factory, "denemo-whole-note", "icon-note-0.svg"); register_stock_icon (icon_factory, "denemo-half-note", "icon-note-1.svg"); register_stock_icon (icon_factory, "denemo-quarter-note", "icon-note-2.svg"); register_stock_icon (icon_factory, "denemo-eight-note", "icon-note-3.svg"); register_stock_icon (icon_factory, "denemo-sixteenth-note", "icon-note-4.svg"); register_stock_icon (icon_factory, "denemo-whole-rest", "icon-rest-0.svg"); register_stock_icon (icon_factory, "denemo-half-rest", "icon-rest-1.svg"); register_stock_icon (icon_factory, "denemo-quarter-rest", "icon-rest-2.svg"); register_stock_icon (icon_factory, "denemo-eight-rest", "icon-rest-3.svg"); register_stock_icon (icon_factory, "denemo-sixteenth-rest", "icon-rest-4.svg"); //New Ornaments added here, loding XBM's until svgs have been generated. register_stock_icon (icon_factory, "denemo-coda", "feta26-scripts-coda.xbm"); register_stock_icon (icon_factory, "denemo-prall", "feta26-scripts-prall.xbm"); register_stock_icon (icon_factory, "denemo-flageolet", "feta26-scripts-flageolet.xbm"); register_stock_icon (icon_factory, "denemo-prallmordent", "feta26-scripts-prallmordent.xbm"); register_stock_icon (icon_factory, "denemo-prallprall", "feta26-scripts-prallprall.xbm"); register_stock_icon (icon_factory, "denemo-open", "feta26-scripts-open.xbm"); register_stock_icon (icon_factory, "denemo-segno", "feta26-scripts-segno.xbm"); register_stock_icon (icon_factory, "denemo-stopped", "feta26-scripts-stopped.xbm"); register_stock_icon (icon_factory, "denemo-thumb", "feta26-scripts-thumb.xbm"); register_stock_icon (icon_factory, "denemo-upprall", "feta26-scripts-upprall.xbm"); register_stock_icon (icon_factory, "denemo-arpeggio", "feta26-scripts-arpeggio.xbm"); g_object_unref (icon_factory); } /* Code by Erik Mouw, taken directly from the gtk+ FAQ */ /** * signal handler to be invoked when child processes _exit() without * having to wait for them */ void sigchld_handler (gint num) { sigset_t set, oldset; pid_t pid; gint status, exitstatus; #ifndef G_OS_WIN32 /* block other incoming SIGCHLD signals */ sigemptyset (&set); sigaddset (&set, SIGCHLD); sigprocmask (SIG_BLOCK, &set, &oldset); /* wait for child */ while ((pid = waitpid ((pid_t) - 1, &status, WNOHANG)) > 0) { if (WIFEXITED (status)) { exitstatus = WEXITSTATUS (status); fprintf (stderr, _("Parent: child exited, pid = %d, exit status = %d\n"), (int) pid, exitstatus); } else if (WIFSIGNALED (status)) { exitstatus = WTERMSIG (status); fprintf (stderr, _("Parent: child terminated by signal %d, pid = %d\n"), exitstatus, (int) pid); } else if (WIFSTOPPED (status)) { exitstatus = WSTOPSIG (status); fprintf (stderr, _("Parent: child stopped by signal %d, pid = %d\n"), exitstatus, (int) pid); } else { fprintf (stderr, _("Parent: child exited magically, pid = %d\n"), (int) pid); } } /* re-install the signal handler (some systems need this) */ signal (SIGCHLD, sigchld_handler); /* and unblock it */ sigemptyset (&set); sigaddset (&set, SIGCHLD); sigprocmask (SIG_UNBLOCK, &set, &oldset); #endif } #if GTK_MAJOR_VERSION > 1 /** * Segmentation fault dialog warning the cannot continue * */ void segdialog (gchar * sigtype, gchar * message) { GtkWidget *dialog; dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s : %s", sigtype, message); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } #endif /** * SIGSEGV Handler to do nice things if denemo bombs * */ void denemo_signal_handler (int sig) { GList *tmp = NULL; DenemoGUI *gui; static int already_in_segfault = 0; if (already_in_segfault) exit (1); else already_in_segfault = 1; g_print ("\nNo of displays : %d\n", g_list_length (displays)); if (g_list_length (displays) == 1) { gui = (DenemoGUI *) displays->data; g_print ("si is %p", gui); char *filename = locatedotdenemo (); strncat (filename, "crashrecovery.denemo", 20); if (gui->si->lily_file) exportmudela (filename, gui->si, 0, 0); else exportXML (filename, gui->si, 0, 0); } else { int i = 0; for (tmp = displays; tmp && g_list_length (tmp) > 1; tmp = tmp->next) { gui = (DenemoGUI *) tmp->data; char *filename = locatedotdenemo (); strncat (filename, "crashrecovery", 13); char t[5]; sprintf (t, "%d", i); strncat (filename, t, strlen (t)); strcat (filename, ".denemo"); if (gui->si->lily_file) exportmudela (filename, gui->si, 0, 0); else exportXML (filename, gui->si, 0, 0); i++; } } exit (1); } /** * Main function * */ int main (int argc, char *argv[]) { gint opts; GError *error = NULL; gchar *localedir; DenemoGUI *gui = (DenemoGUI *) g_malloc0 (sizeof (DenemoGUI)); #ifdef HAVE_GETOPT_H static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'} }; #endif gchar *helptext = g_strconcat (_("\nGNU Denemo version "), VERSION ".\n\n", _("usage: denemo [OPTION... [FILE]\n\n\ Run denemo, opening save file FILE\n\n\ Denemo is a graphical music notation editor. It produces save files\n\ in GNU Lilypond input format (suitable for immediate typesetting with GNU\n\ Lilypond) and Adam Tee's JTF file format. Denemo is part of the GNU\n\ project.\n\n\ Options:\n\ -h,--help print this help and exit\n\ -s,--silent lets just start with silent lilypond conversion\n\ -v,--version print version number and exit\n\n\n\ Report bugs to bug-denemo@gnu.org\n"), NULL); gchar *copytext = _("(c) 1999-2005 Matthew Hiller, Adam Tee, and others\n\n\n\ This program is provided with absolutely NO WARRANTY; see\n\ the file COPYING for details.\n\n\ This software may be redistributed and modified under the\n\ terms of the GNU General Public License; again, see the file\n\ COPYING for details.\n\n"); /* gchar *win32text = _("Warning: the win32 port of Denemo is as yet incomplete.\n\ Most prominently, playback and options do not work.\n\n"); */ if (!gbr_init (&error)) { g_print ("BinReloc failed to initialize:\n"); g_print ("Domain: %d (%s)\n", (int) error->domain, g_quark_to_string (error->domain)); g_print ("Code: %d\n", error->code); g_print ("Message: %s\n", error->message); g_error_free (error); g_print ("----------------\n"); } /* why unset user defined locale ? */ #if 1 setlocale (LC_CTYPE, ""); setlocale (LC_MESSAGES, ""); setlocale (LC_ALL, ""); gtk_set_locale (); #endif #ifndef ENABLE_BINRELOC /* default */ /* it seems to be the standard way (no binreloc) * to set the path of translations this way: * messages are in $LOCALEDIR/$LANG/denemo */ #ifdef DEBUG g_print ("LOCALEDIR: %s\n", LOCALEDIR); #endif bindtextdomain (PACKAGE, LOCALEDIR); bind_textdomain_codeset (PACKAGE, "UTF-8"); textdomain (PACKAGE); #else /* alternatively, we use binreloc */ /* binreloc says it is disabled even with built thanks to * --enable-binreloc... So, searhing falls back to * $LOCALEDIR/denemo/$LANG which is not a valid path */ localedir = gbr_find_locale_dir (LOCALEDIR); gchar *localedir2 = g_strconcat (localedir, "/denemo", NULL); #ifdef DEBUG g_print ("LOCALEDIR2: %s\n", localedir2); #endif bindtextdomain (PACKAGE, localedir2); textdomain (PACKAGE); g_free (localedir); g_free (localedir2); #endif gtk_init (&argc, &argv); #ifndef G_OS_WIN32 #ifdef HAVE_GETOPT_H while ((opts = getopt_long (argc, argv, "shvt:", long_options, NULL)) != -1) #else while ((opts = getopt (argc, argv, "shvt:")) != -1) #endif { if (opts == 'h') { printf (helptext); exit (0); } else if (opts == 's') { printf (copytext); silentconversion (argv[optind], gui->si); exit (0); } else if (opts == 'v') { printf (_("\nGNU Denemo version ")); printf (VERSION ".\n\n"); printf (copytext); exit (0); } } #endif printf (_("\nGNU Denemo, a gtk+ frontend for GNU Lilypond\n")); printf (copytext); #ifdef G_OS_WIN32 printf (win32text); #endif g_free (helptext); register_stock_items (); ext_init (); /* external players (midi...) */ midi_init (); /* internal (not working yet) */ //DenemoPrefs prefs; // readxmlprefs("src/denemorc", &prefs); #ifdef HAVEALSA if (NULL == (sq = midi_seq_new ("Denemo"))) { g_print ("Sequencer Error.\n"); } #endif newview (); /* Set up the signal handler */ #ifndef G_OS_WIN32 signal (SIGSEGV, denemo_signal_handler); signal (SIGCHLD, sigchld_handler); #endif /* And open a file, if it was specified on the command line. Note * that this had to be done after the window was created, otherwise * there wouldn't have been a titlebar to set. Also note that * a blank score is created whether or not a load was specified. * This is done this way because the load could bomb out. */ #ifndef G_OS_WIN32 GDir *dir; gchar *filename; error = NULL; dir = g_dir_open (locatedotdenemo (), 0, &error); if (error) g_print ("Cannot find .denemo directory\n"); while ((filename = (gchar *) g_dir_read_name (dir)) != NULL) { if (0 == strcmp ("crashrecovery.denemo", filename)) { GtkWidget *dialog = gtk_dialog_new_with_buttons (NULL, NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_YES, GTK_RESPONSE_ACCEPT, GTK_STOCK_SAVE_AS, GTK_RESPONSE_CANCEL, GTK_STOCK_DELETE, GTK_RESPONSE_REJECT, NULL); GtkWidget *label = gtk_label_new ("\nDenemo crashed, The open file has been recovered\n" "do you want to contiue editing your work?\n"); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), label); gtk_widget_show_all (dialog); gint result = gtk_dialog_run (GTK_DIALOG (dialog)); g_print ("Dialog result is %d\n", result); gchar *name = locatedotdenemo (); name = g_strconcat (name, "/", filename, NULL); switch (result) { case GTK_RESPONSE_ACCEPT: openfile (name); g_remove (name); break; case GTK_RESPONSE_CANCEL: gui->window = NULL; result = importXML (name, gui->si); if (result != -1) file_saveas (NULL, gui); else g_print ("Cannot open %s\n", name); g_free (gui); g_remove (name); break; case GTK_RESPONSE_REJECT: g_print ("Removing %s\n", name); g_remove (name); //g_free(name); break; } gtk_widget_destroy (dialog); } } g_dir_close (dir); if (optind < argc) { if (openfile (argv[optind]) == -1) { g_print ("Attempt to read in file %s failed\n", argv[optind]); return 1; } } #endif /* Now launch into the main gtk event loop and we're all set */ gtk_main (); g_free (gui); return 0; } int openfile (gchar * name) { GList *tmp = g_list_nth (displays, 0); DenemoGUI *gui = (DenemoGUI *) tmp->data; gint result = open_for_real (name, gui); gui->si->readonly = FALSE; //si->readonly = TRUE; return result; }