1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * Goo
5 *
6 * Copyright (C) 2013 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #include <config.h>
24 #include <stdlib.h>
25 #include <glib/gi18n.h>
26 #include <glib/gprintf.h>
27 #include <gst/gst.h>
28 #include "goo-application.h"
29 #include "goo-application-actions-callbacks.h"
30 #include "goo-application-actions-entries.h"
31 #include "goo-window.h"
32 #include "gtk-utils.h"
33 #include "main.h"
34 #include "preferences.h"
35
36
37 /* -- command line arguments -- */
38
39 static const char *program_argv0 = NULL;
40 static int arg_toggle_play = FALSE;
41 static int arg_stop = FALSE;
42 static int arg_next = FALSE;
43 static int arg_prev = FALSE;
44 static int arg_eject = FALSE;
45 static int arg_quit = FALSE;
46 static gboolean arg_version = FALSE;
47 static char *arg_device = NULL;
48
49
50 static const GOptionEntry options[] = {
51 { "device", 'd', 0, G_OPTION_ARG_STRING, &arg_device,
52 N_("CD device to be used"),
53 N_("DEVICE_PATH") },
54 { "play", '\0', 0, G_OPTION_ARG_NONE, &arg_auto_play,
55 N_("Play the CD on startup"),
56 0 },
57 { "toggle-play", '\0', 0, G_OPTION_ARG_NONE, &arg_toggle_play,
58 N_("Toggle play"),
59 0 },
60 { "stop", '\0', 0, G_OPTION_ARG_NONE, &arg_stop,
61 N_("Stop playing"),
62 0 },
63 { "next", '\0', 0, G_OPTION_ARG_NONE, &arg_next,
64 N_("Play the next track"),
65 0 },
66 { "previous", '\0', 0, G_OPTION_ARG_NONE, &arg_prev,
67 N_("Play the previous track"),
68 0 },
69 { "eject", '\0', 0, G_OPTION_ARG_NONE, &arg_eject,
70 N_("Eject the CD"),
71 0 },
72 { "toggle-visibility", '\0', 0, G_OPTION_ARG_NONE, &arg_toggle_visibility,
73 N_("Toggle the main window visibility"),
74 0 },
75 { "quit", '\0', 0, G_OPTION_ARG_NONE, &arg_quit,
76 N_("Quit the application"),
77 0 },
78 { "version", 'v', 0, G_OPTION_ARG_NONE, &arg_version,
79 N_("Show version"),
80 0 },
81 { NULL }
82 };
83
84
85 /* -- GooApplication -- */
86
87
88 struct _GooApplicationPrivate {
89 GSettings *settings;
90 };
91
92
G_DEFINE_TYPE_WITH_CODE(GooApplication,goo_application,GTK_TYPE_APPLICATION,G_ADD_PRIVATE (GooApplication))93 G_DEFINE_TYPE_WITH_CODE (GooApplication, goo_application, GTK_TYPE_APPLICATION,
94 G_ADD_PRIVATE (GooApplication))
95
96
97 static void
98 goo_application_finalize (GObject *object)
99 {
100 GooApplication *self = (GooApplication *) object;
101
102 g_object_unref (self->priv->settings);
103 G_OBJECT_CLASS (goo_application_parent_class)->finalize (object);
104 }
105
106
107 static gboolean
required_gstreamer_plugins_available(void)108 required_gstreamer_plugins_available (void)
109 {
110 char *required_plugins[] = { "cdparanoiasrc", "audioconvert", "volume", "giosink" };
111 int i;
112
113 for (i = 0; i < G_N_ELEMENTS (required_plugins); i++) {
114 GstElement *element;
115 gboolean present;
116
117 element = gst_element_factory_make (required_plugins[i], NULL);
118 present = (element != NULL);
119 if (element != NULL)
120 gst_object_unref (GST_OBJECT (element));
121
122 if (! present)
123 return FALSE;
124 }
125
126 return TRUE;
127 }
128
129
130 static int
goo_application_command_line_finished(GApplication * application,int status)131 goo_application_command_line_finished (GApplication *application,
132 int status)
133 {
134 if (status == EXIT_SUCCESS)
135 gdk_notify_startup_complete ();
136
137 /* reset the arguments */
138
139 arg_auto_play = FALSE;
140 arg_toggle_play = FALSE;
141 arg_stop = FALSE;
142 arg_next = FALSE;
143 arg_prev = FALSE;
144 arg_eject = FALSE;
145 arg_toggle_visibility = FALSE;
146 arg_quit = FALSE;
147 g_free (arg_device);
148 arg_device = NULL;
149
150 return status;
151 }
152
153
154 static GOptionContext *
goo_application_create_option_context(void)155 goo_application_create_option_context (void)
156 {
157 GOptionContext *options_context;
158 static gsize initialized = FALSE;
159
160 options_context = g_option_context_new (N_("Play CDs and save the tracks to disk as files"));
161 g_option_context_set_translation_domain (options_context, GETTEXT_PACKAGE);
162 g_option_context_set_ignore_unknown_options (options_context, TRUE);
163 g_option_context_add_main_entries (options_context, options, GETTEXT_PACKAGE);
164
165 if (g_once_init_enter (&initialized)) {
166 g_option_context_add_group (options_context, gtk_get_option_group (TRUE));
167 g_option_context_add_group (options_context, gst_init_get_option_group ());
168
169 g_once_init_leave (&initialized, TRUE);
170 }
171
172 return options_context;
173 }
174
175
176 static int
goo_application_command_line(GApplication * application,GApplicationCommandLine * command_line)177 goo_application_command_line (GApplication *application,
178 GApplicationCommandLine *command_line)
179 {
180 char **argv;
181 int argc;
182 GOptionContext *options_context;
183 GError *error = NULL;
184 GtkWidget *window;
185
186 argv = g_application_command_line_get_arguments (command_line, &argc);
187 options_context = goo_application_create_option_context ();
188 if (! g_option_context_parse (options_context, &argc, &argv, &error)) {
189 g_critical ("Failed to parse arguments: %s", error->message);
190 g_error_free (error);
191 g_option_context_free (options_context);
192 return goo_application_command_line_finished (application, EXIT_FAILURE);
193 }
194 g_option_context_free (options_context);
195
196 /* check the gstreamer plugins */
197
198 if (! required_gstreamer_plugins_available ()) {
199 GtkWidget *d;
200 d = _gtk_error_dialog_new (NULL,
201 0,
202 NULL,
203 _("Cannot start the CD player"),
204 "%s",
205 _("In order to read CDs you have to install the GStreamer base plugins"));
206 g_signal_connect_swapped (G_OBJECT (d), "response",
207 G_CALLBACK (gtk_widget_destroy),
208 d);
209 gtk_window_set_application (GTK_WINDOW (d), GTK_APPLICATION (application));
210 gtk_widget_show (d);
211
212 return goo_application_command_line_finished (application, EXIT_FAILURE);
213 }
214
215 /* execute the command line */
216
217 window = _gtk_application_get_current_window (GTK_APPLICATION (application));
218 if (window == NULL)
219 window = goo_window_new (NULL);
220 gtk_window_present (GTK_WINDOW (window));
221
222 if (arg_auto_play) {
223 goo_window_play (GOO_WINDOW (window));
224 }
225 else if (arg_toggle_play) {
226 goo_window_toggle_play (GOO_WINDOW (window));
227 }
228 else if (arg_stop) {
229 goo_window_stop (GOO_WINDOW (window));
230 }
231 else if (arg_next) {
232 goo_window_next (GOO_WINDOW (window));
233 }
234 else if (arg_prev) {
235 goo_window_prev (GOO_WINDOW (window));
236 }
237 else if (arg_eject) {
238 goo_window_eject (GOO_WINDOW (window));
239 }
240 else if (arg_toggle_visibility) {
241 goo_window_toggle_visibility (GOO_WINDOW (window));
242 }
243 else if (arg_quit) {
244 goo_window_close (GOO_WINDOW (window));
245 }
246 else if (arg_device != NULL) {
247 BraseroDrive *drive;
248
249 drive = main_get_drive_for_device (arg_device);
250 window = main_get_window_from_device (arg_device);
251 if (window == NULL) {
252 window = goo_window_new (drive);
253 gtk_widget_show (window);
254 }
255 else
256 goo_window_set_drive (GOO_WINDOW (window), drive);
257
258 g_object_unref (drive);
259 g_free (arg_device);
260 arg_device = NULL;
261 }
262
263 return goo_application_command_line_finished (application, EXIT_SUCCESS);
264 }
265
266
267 static gboolean
goo_application_local_command_line(GApplication * application,char *** arguments,int * exit_status)268 goo_application_local_command_line (GApplication *application,
269 char ***arguments,
270 int *exit_status)
271 {
272 char **local_argv;
273 int local_argc;
274 GOptionContext *options_context;
275 GError *error = NULL;
276 gboolean handled_locally = FALSE;
277
278 local_argv = g_strdupv (*arguments);
279 local_argc = g_strv_length (local_argv);
280
281 program_argv0 = g_strdup (local_argv[0]);
282 *exit_status = EXIT_SUCCESS;
283
284 options_context = goo_application_create_option_context ();
285 if (! g_option_context_parse (options_context, &local_argc, &local_argv, &error)) {
286 *exit_status = EXIT_FAILURE;
287 g_critical ("Failed to parse arguments: %s", error->message);
288 g_clear_error (&error);
289 handled_locally = TRUE;
290 }
291
292 if (arg_version) {
293 g_printf ("%s %s, Copyright © 2001-2013 Free Software Foundation, Inc.\n", PACKAGE_NAME, PACKAGE_VERSION);
294 handled_locally = TRUE;
295 }
296
297 g_option_context_free (options_context);
298 g_strfreev (local_argv);
299
300 return handled_locally;
301 }
302
303
304 /* -- goo_application_startup -- */
305
306
307 static void
pref_playlist_playall_changed(GSettings * settings,const char * key,gpointer user_data)308 pref_playlist_playall_changed (GSettings *settings,
309 const char *key,
310 gpointer user_data)
311 {
312 GooApplication *application = user_data;
313
314 g_simple_action_set_state (G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (application), PREF_PLAYLIST_PLAYALL)),
315 g_variant_new_boolean (g_settings_get_boolean (application->priv->settings, PREF_PLAYLIST_PLAYALL)));
316 update_actions_sensitivity (G_APPLICATION (application));
317 }
318
319
320 static void
pref_playlist_repeat_changed(GSettings * settings,const char * key,gpointer user_data)321 pref_playlist_repeat_changed (GSettings *settings,
322 const char *key,
323 gpointer user_data)
324 {
325 GooApplication *application = user_data;
326
327 g_simple_action_set_state (G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (application), PREF_PLAYLIST_REPEAT)),
328 g_variant_new_boolean (g_settings_get_boolean (application->priv->settings, PREF_PLAYLIST_REPEAT)));
329 update_actions_sensitivity (G_APPLICATION (application));
330 }
331
332
333 static void
pref_playlist_shuffle_changed(GSettings * settings,const char * key,gpointer user_data)334 pref_playlist_shuffle_changed (GSettings *settings,
335 const char *key,
336 gpointer user_data)
337 {
338 GooApplication *application = user_data;
339
340 g_simple_action_set_state (G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (application), PREF_PLAYLIST_SHUFFLE)),
341 g_variant_new_boolean (g_settings_get_boolean (application->priv->settings, PREF_PLAYLIST_SHUFFLE)));
342 update_actions_sensitivity (G_APPLICATION (application));
343 }
344
345
346 static void
initialize_app_menu(GApplication * application)347 initialize_app_menu (GApplication *application)
348 {
349 const _GtkAccelerator app_accelerators[] = {
350 { "app.help", "F1" },
351 { "app.quit", "<Control>q" }
352 };
353 GooApplication *self = (GooApplication *) application;
354
355 g_action_map_add_action_entries (G_ACTION_MAP (application),
356 goo_application_actions,
357 G_N_ELEMENTS (goo_application_actions),
358 application);
359
360 _gtk_application_add_accelerators (GTK_APPLICATION (application), app_accelerators, G_N_ELEMENTS (app_accelerators));
361
362 g_simple_action_set_state (G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (application), PREF_PLAYLIST_PLAYALL)),
363 g_variant_new_boolean (g_settings_get_boolean (self->priv->settings, PREF_PLAYLIST_PLAYALL)));
364 g_simple_action_set_state (G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (application), PREF_PLAYLIST_REPEAT)),
365 g_variant_new_boolean (g_settings_get_boolean (self->priv->settings, PREF_PLAYLIST_REPEAT)));
366 g_simple_action_set_state (G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (application), PREF_PLAYLIST_SHUFFLE)),
367 g_variant_new_boolean (g_settings_get_boolean (self->priv->settings, PREF_PLAYLIST_SHUFFLE)));
368
369 g_signal_connect (self->priv->settings,
370 "changed::" PREF_PLAYLIST_PLAYALL,
371 G_CALLBACK (pref_playlist_playall_changed),
372 self);
373 g_signal_connect (self->priv->settings,
374 "changed::" PREF_PLAYLIST_SHUFFLE,
375 G_CALLBACK (pref_playlist_shuffle_changed),
376 self);
377 g_signal_connect (self->priv->settings,
378 "changed::" PREF_PLAYLIST_REPEAT,
379 G_CALLBACK (pref_playlist_repeat_changed),
380 self);
381 }
382
383
384 static void
goo_application_startup(GApplication * application)385 goo_application_startup (GApplication *application)
386 {
387 G_APPLICATION_CLASS (goo_application_parent_class)->startup (application);
388
389 g_set_application_name (_("CD Player"));
390 gtk_window_set_default_icon_name ("goobox");
391
392 initialize_app_menu (application);
393 }
394
395
396 static void
goo_application_activate(GApplication * application)397 goo_application_activate (GApplication *application)
398 {
399 GtkWidget *window;
400
401 window = _gtk_application_get_current_window (GTK_APPLICATION (application));
402 if (window != NULL)
403 gtk_window_present (GTK_WINDOW (window));
404 }
405
406
407 static void
goo_application_class_init(GooApplicationClass * klass)408 goo_application_class_init (GooApplicationClass *klass)
409 {
410 GObjectClass *object_class;
411 GApplicationClass *application_class;
412
413 object_class = G_OBJECT_CLASS (klass);
414 object_class->finalize = goo_application_finalize;
415
416 application_class = G_APPLICATION_CLASS (klass);
417 application_class->command_line = goo_application_command_line;
418 application_class->local_command_line = goo_application_local_command_line;
419 application_class->startup = goo_application_startup;
420 application_class->activate = goo_application_activate;
421 }
422
423
424 static void
goo_application_init(GooApplication * self)425 goo_application_init (GooApplication *self)
426 {
427 self->priv = goo_application_get_instance_private (self);
428 self->priv->settings = g_settings_new (GOOBOX_SCHEMA_PLAYLIST);
429 }
430
431
432 GtkApplication *
goo_application_new(void)433 goo_application_new (void)
434 {
435 return g_object_new (GOO_TYPE_APPLICATION,
436 "application-id", "org.gnome.Goobox",
437 "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
438 NULL);
439 }
440