1 /*
2  * Copyright (c) 2005-2006 Jean-François Wauthy (pollux@xfce.org)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
26 
27 #include <stdlib.h>
28 
29 #include <gtk/gtk.h>
30 
31 #include <libxfce4util/libxfce4util.h>
32 #include <libxfce4ui/libxfce4ui.h>
33 
34 #ifdef HAVE_GST
35 #include <gst/gst.h>
36 #endif
37 
38 #include "xfburn-main.h"
39 #include "xfburn-global.h"
40 #include "xfburn-device-list.h"
41 #include "xfburn-utils.h"
42 #include "xfburn-settings.h"
43 #include "xfburn-burn-image-dialog.h"
44 #include "xfburn-main-window.h"
45 #include "xfburn-blank-dialog.h"
46 #include "xfburn-udev-manager.h"
47 #include "xfburn-transcoder-basic.h"
48 #include "xfburn-transcoder-gst.h"
49 
50 
51 /* internal prototypes */
52 static gboolean parse_option (const gchar *option_name, const gchar *value,
53 			      gpointer data, GError **error);
54 static void xfburn_main_enter_main_window (void);
55 static void print_available_transcoders (void);
56 
57 /* globals */
58 static int window_counter = 0;
59 
60 
61 /* command line parameters */
62 static gchar *image_filename = NULL;
63 static gboolean show_version = FALSE;
64 static gboolean other_action = FALSE;
65 static gboolean show_main = FALSE;
66 static gboolean add_data_composition = FALSE;
67 static gboolean add_audio_composition = FALSE;
68 static gboolean blank = FALSE;
69 static gchar *transcoder_selection = NULL;
70 static gchar *initial_dir = NULL;
71 
72 static GOptionEntry optionentries[] = {
73   { "burn-image", 'i', G_OPTION_FLAG_OPTIONAL_ARG /* || G_OPTION_FLAG_FILENAME */, G_OPTION_ARG_CALLBACK, &parse_option,
74     N_("Open the burn image dialog, optionally followed by the image filename"), NULL },
75   { "blank", 'b', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &parse_option,
76     N_("Open the blank disc dialog"), NULL },
77   { "data-composition", 'd', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &parse_option,
78     N_("Start a data composition, optionally followed by files/directories to be added to the composition"), NULL },
79   { "audio-composition", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &parse_option,
80     N_("Start an audio composition, optionally followed by files/directories to be added to the composition"), NULL },
81   { "transcoder", 't', 0, G_OPTION_ARG_STRING, &transcoder_selection,
82     N_("Select the transcoder, run with --transcoder=list to see the available ones"), NULL },
83   { "directory", 'D', G_OPTION_FLAG_OPTIONAL_ARG , G_OPTION_ARG_CALLBACK, &parse_option,
84     N_("Start the file browser in the specified directory, or the current directory if none is specified (the default is to start in your home directory)"), NULL },
85   { "version", 'V', 0 , G_OPTION_ARG_NONE, &show_version,
86     N_("Display program version and exit"), NULL },
87   { "main", 'm', 0, G_OPTION_ARG_NONE, &show_main,
88     N_("Show main program even when other action is specified on the command line."), NULL },
89   { NULL, ' ', 0, 0, NULL, NULL, NULL }
90 };
91 
92 
93 /* public functions */
94 void
xfburn_main_enter_window(void)95 xfburn_main_enter_window (void)
96 {
97   /* if a main window is present, then it is in control */
98   if (window_counter != -42)
99     window_counter++;
100 }
101 
102 void
xfburn_main_leave_window(void)103 xfburn_main_leave_window (void)
104 {
105   /* if a main window is present, then it is in control */
106   if (window_counter == -42)
107     return;
108 
109   window_counter--;
110   if (window_counter <= 0)
111     g_idle_add ((GSourceFunc) gtk_main_quit, NULL );
112 }
113 
114 static void
xfburn_main_enter_main_window(void)115 xfburn_main_enter_main_window (void)
116 {
117   /* mark the window_counter as having a main window */
118   window_counter = -42;
119 }
120 
121 
122 const gchar *
xfburn_main_get_initial_dir()123 xfburn_main_get_initial_dir ()
124 {
125   if (initial_dir)
126     return initial_dir;
127   else
128     return xfce_get_homedir ();
129 }
130 
131 gboolean
xfburn_main_has_initial_dir()132 xfburn_main_has_initial_dir ()
133 {
134   if (initial_dir)
135     return TRUE;
136   else
137     return FALSE;
138 }
139 
140 
141 /* private functions */
142 
parse_option(const gchar * option_name,const gchar * value,gpointer data,GError ** error)143 static gboolean parse_option (const gchar *option_name, const gchar *value,
144                               gpointer data, GError **error)
145 {
146   if (strcmp (option_name, "-i") == 0 || strcmp (option_name, "--burn-image") == 0) {
147     if (value == NULL)
148       image_filename = "";
149     else
150       image_filename = g_strdup(value);
151   } else if (strcmp (option_name, "-d") == 0 || strcmp (option_name, "--data-composition") == 0) {
152     add_data_composition = TRUE;
153   } else if (strcmp (option_name, "-a") == 0 || strcmp (option_name, "--audio-composition") == 0) {
154     add_audio_composition = TRUE;
155   } else if (strcmp (option_name, "-b") == 0 || strcmp (option_name, "--blank") == 0) {
156     blank = TRUE;
157   } else if (strcmp (option_name, "-D") == 0 || strcmp (option_name, "--directory") == 0) {
158     if (value == NULL)
159       initial_dir = g_get_current_dir ();
160     else
161       initial_dir = g_strdup(value);
162   } else {
163     g_set_error (error, 0, G_OPTION_ERROR_FAILED, "Invalid command line option. Please report, this is a bug.");
164     return FALSE;
165   }
166 
167   return TRUE;
168 }
169 
170 
171 static void
print_available_transcoders(void)172 print_available_transcoders (void)
173 {
174   g_print ("Valid transcoders are:\n");
175   g_print ("\tbasic\tCan only burn uncompressed CD quality .wav files.\n");
176 #ifdef HAVE_GST
177   g_print ("\tgst\tUses gstreamer, and can burn all formats supported by it.\n");
178 #endif
179 }
180 
181 /* entry point */
182 int
main(int argc,char ** argv)183 main (int argc, char **argv)
184 {
185   GtkWidget *mainwin;
186   gint n_burners;
187   GError *error = NULL;
188 #ifdef HAVE_GUDEV
189   gchar *error_msg;
190 #endif
191   XfburnTranscoder *transcoder;
192   XfburnDeviceList *devlist;
193 
194 #if DEBUG > 0
195   /* I have to disable this until GtkTreeView gets fixed,
196    * and doesn't complain anymore when a DnD doesn't add any
197    * rows
198   g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
199    */
200 #endif
201 
202   g_set_application_name (_("Xfburn"));
203 
204   gdk_threads_init ();
205   gdk_threads_enter ();
206 
207   xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
208 
209   if (!gtk_init_with_args (&argc, &argv, NULL, optionentries, GETTEXT_PACKAGE, &error)) {
210     if (error != NULL) {
211       g_print (_("%s: %s\nTry %s --help to see a full list of available command line options.\n"), PACKAGE, error->message, PACKAGE_NAME);
212       g_error_free (error);
213       gdk_threads_leave ();
214       return EXIT_FAILURE;
215     }
216   }
217 
218   if (!burn_initialize ()) {
219     g_critical ("Unable to initialize libburn");
220     xfce_dialog_show_error (NULL, NULL, _("Unable to initialize the burning backend."));
221     gdk_threads_leave ();
222     return EXIT_FAILURE;
223   }
224 
225 #ifdef HAVE_GST
226   if (!gst_init_check (&argc, &argv, &error)) {
227     g_critical ("Failed to initialize gstreamer!");
228     /* I'm assuming this pretty much never happens. If it does, we should make this a soft failure and fall back to basic */
229     gdk_threads_leave ();
230     burn_finish ();
231     return EXIT_FAILURE;
232   }
233 #endif
234 
235   if (show_version) {
236 #ifdef HAVE_GST
237     const char *nano_str;
238     guint gst_major, gst_minor, gst_micro, gst_nano;
239 #endif
240 
241     g_print ("%s version %s for Xfce %s\n", PACKAGE, VERSION, xfce_version_string ());
242     g_print ("\tbuilt with GTK+-%d.%d.%d, ", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
243     g_print ("linked with GTK+-%d.%d.%d.\n", gtk_major_version, gtk_minor_version, gtk_micro_version);
244 
245 #ifdef HAVE_GST
246     gst_version (&gst_major, &gst_minor, &gst_micro, &gst_nano);
247 
248     if (gst_nano == 1)
249       nano_str = " (CVS)";
250     else if (gst_nano == 2)
251       nano_str = " (Prerelease)";
252     else
253       nano_str = "";
254 
255     g_print ("\tGStreamer support (built with %d.%d.%d, linked against %d.%d.%d%s)\n",
256              GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO,
257              gst_major, gst_minor, gst_micro, nano_str);
258 
259 #endif
260     exit (EXIT_SUCCESS);
261   }
262 
263   if (transcoder_selection && strcmp (transcoder_selection, "list") == 0) {
264     print_available_transcoders();
265     gdk_threads_leave ();
266     burn_finish ();
267     return EXIT_SUCCESS;
268   }
269 
270   DBG ("%s version %s for Xfce %s\n", PACKAGE, VERSION, xfce_version_string ());
271 
272   xfburn_settings_init ();
273 
274 #ifdef HAVE_GUDEV
275   error_msg = xfburn_udev_manager_create_global ();
276   if (error_msg) {
277     xfce_dialog_show_error (NULL, NULL, "%s", error_msg);
278     gdk_threads_leave ();
279     burn_finish ();
280     return EXIT_FAILURE;
281   } else {
282     g_message ("Using UDEV");
283   }
284 #endif
285 
286   devlist = xfburn_device_list_new ();
287   g_object_get (devlist, "num-burners", &n_burners, NULL);
288 
289   if (n_burners < 1) {
290     GtkMessageDialog *dialog = (GtkMessageDialog *) gtk_message_dialog_new (NULL,
291                                     GTK_DIALOG_DESTROY_WITH_PARENT,
292                                     GTK_MESSAGE_WARNING,
293                                     GTK_BUTTONS_CLOSE,
294                                     ((const gchar *) _("No burners are currently available")));
295     gtk_message_dialog_format_secondary_text (dialog,
296                                     _("Possibly the disc(s) are in use, and cannot get accessed.\n\n"
297                                       "Please unmount and restart the application.\n\n"
298                                       "If no disc is in the drive, check that you have read and write access to the drive with the current user."));
299     gtk_dialog_run (GTK_DIALOG (dialog));
300     gtk_widget_destroy (GTK_WIDGET (dialog));
301   }
302 
303 
304   /*----------Transcoder--------------------------------------------------*/
305 
306   if (!transcoder_selection) {
307     /* select the best available */
308 #ifdef HAVE_GST
309     transcoder = XFBURN_TRANSCODER (xfburn_transcoder_gst_new ());
310 #else
311     transcoder = XFBURN_TRANSCODER (xfburn_transcoder_basic_new ());
312 #endif
313 #ifdef HAVE_GST
314   } else if (strcmp (transcoder_selection, "gst") == 0) {
315     transcoder = XFBURN_TRANSCODER (xfburn_transcoder_gst_new ());
316 #endif
317   } else if (strcmp (transcoder_selection, "basic") == 0) {
318     transcoder = XFBURN_TRANSCODER (xfburn_transcoder_basic_new ());
319   } else {
320     g_print ("'%s' is an invalid transcoder selection.\n",
321              transcoder_selection);
322     g_print ("\n");
323     print_available_transcoders();
324     gdk_threads_leave ();
325     burn_finish ();
326     return EXIT_FAILURE;
327   }
328 
329   if (!xfburn_transcoder_is_initialized (transcoder, &error)) {
330     xfce_dialog_show_warning(NULL, NULL, _("Failed to initialize %s transcoder: %s\n\t(falling back to basic implementation)"), xfburn_transcoder_get_name (transcoder), error->message);
331     g_error_free (error);
332     g_object_unref (transcoder);
333     transcoder = XFBURN_TRANSCODER (xfburn_transcoder_basic_new ());
334   } else {
335     g_message ("Using %s transcoder.", xfburn_transcoder_get_name (transcoder));
336   }
337   xfburn_transcoder_set_global (transcoder);
338 
339 
340   /*----------evaluate parsed command line action options-------------------------*/
341 
342   /* heuristic for file names on the commandline */
343   if (argc == 2 && !add_data_composition && !add_audio_composition) {
344     /* exactly one filename, assume it is an image */
345       image_filename = argv[1];
346   } else if (argc > 2 && !add_data_composition && !add_audio_composition) {
347     /* several file names, for now just open up a data composition */
348     /* TODO: auto-detect music files for audio compositions */
349     add_data_composition = TRUE;
350   }
351 
352   if (show_main) {
353     xfburn_main_enter_main_window ();
354   }
355 
356   if (image_filename != NULL) {
357     GtkWidget *dialog = xfburn_burn_image_dialog_new ();
358     other_action = TRUE;
359 
360     DBG ("image_filename = '%s'\n", image_filename);
361 
362     if (*image_filename != '\0') {
363       gchar *image_fullname;
364 
365       if (!g_path_is_absolute (image_filename))
366 	image_fullname  = g_build_filename (g_get_current_dir (), image_filename, NULL);
367       else
368 	image_fullname = image_filename;
369 
370       if (g_file_test (image_fullname, G_FILE_TEST_EXISTS))
371 	xfburn_burn_image_dialog_set_filechooser_name (dialog, image_fullname);
372       else
373         xfce_dialog_show_error (NULL, NULL, _("Image file '%s' does not exist."), image_fullname);
374     }
375 
376     gtk_dialog_run (GTK_DIALOG (dialog));
377     gtk_widget_destroy (dialog);
378   } else if (blank) {
379     GtkWidget *dialog = xfburn_blank_dialog_new ();
380 
381     other_action = TRUE;
382     gtk_dialog_run (GTK_DIALOG (dialog));
383     gtk_widget_destroy (dialog);
384   }
385 
386 
387   /*----------main window--------------------------------------------------*/
388 
389   if (!other_action || show_main) {
390     xfburn_main_enter_main_window ();
391     mainwin = xfburn_main_window_new ();
392 
393     gtk_widget_show (mainwin);
394 
395     if (add_data_composition)
396       xfburn_main_window_add_data_composition_with_files (XFBURN_MAIN_WINDOW (mainwin), argc-1, argv+1);
397 
398     if (add_audio_composition)
399       xfburn_main_window_add_audio_composition_with_files (XFBURN_MAIN_WINDOW (mainwin), argc-1, argv+1);
400   }
401 
402 
403   gtk_main ();
404 
405 
406   /*----------shutdown--------------------------------------------------*/
407 
408   g_object_unref (devlist);
409   g_object_unref (transcoder);
410 
411 #ifdef HAVE_GUDEV
412   xfburn_udev_manager_shutdown ();
413 #endif
414 
415   xfburn_settings_flush ();
416   xfburn_settings_free ();
417 
418   burn_finish ();
419 
420   gdk_threads_leave ();
421 
422   return EXIT_SUCCESS;
423 }
424