Updated Finnish translation
[rhythmbox.git] / plugins / audiocd / rb-audiocd-plugin.c
blobb1e9cd4beae2943d9ea0690b32c0bac511452f85
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * rb-audiocd-plugin.c
4 * * Copyright (C) 2006 James Livingston
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 * * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 #define __EXTENSIONS__
22 #include "config.h"
24 #include <string.h> /* For strlen */
26 #include <glib.h>
27 #include <glib-object.h>
28 #include <glib/gi18n-lib.h>
29 #include <gmodule.h>
30 #include <gtk/gtk.h>
32 /* nautilus-cd-burner stuff */
33 #include <nautilus-burn-drive.h>
34 #ifndef NAUTILUS_BURN_CHECK_VERSION
35 #define NAUTILUS_BURN_CHECK_VERSION(a,b,c) FALSE
36 #endif
38 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
39 #include <nautilus-burn.h>
40 #endif
42 #ifndef HAVE_BURN_DRIVE_UNREF
43 #define nautilus_burn_drive_unref nautilus_burn_drive_free
44 #endif
47 #include "rb-plugin.h"
48 #include "rb-debug.h"
49 #include "rb-shell.h"
50 #include "rb-shell-player.h"
51 #include "rb-dialog.h"
52 #include "rb-removable-media-manager.h"
53 #include "rb-audiocd-source.h"
56 #define RB_TYPE_AUDIOCD_PLUGIN (rb_audiocd_plugin_get_type ())
57 #define RB_AUDIOCD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_AUDIOCD_PLUGIN, RBAudioCdPlugin))
58 #define RB_AUDIOCD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_AUDIOCD_PLUGIN, RBAudioCdPluginClass))
59 #define RB_IS_AUDIOCD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_AUDIOCD_PLUGIN))
60 #define RB_IS_AUDIOCD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_AUDIOCD_PLUGIN))
61 #define RB_AUDIOCD_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_AUDIOCD_PLUGIN, RBAudioCdPluginClass))
63 typedef struct
65 RBPlugin parent;
67 RBShell *shell;
68 guint ui_merge_id;
70 GHashTable *sources;
71 char *playing_uri;
73 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3) && !HAVE_HAL
74 GHashTable *cd_drive_mapping;
75 #endif
76 } RBAudioCdPlugin;
78 typedef struct
80 RBPluginClass parent_class;
81 } RBAudioCdPluginClass;
84 G_MODULE_EXPORT GType register_rb_plugin (GTypeModule *module);
85 GType rb_audiocd_plugin_get_type (void) G_GNUC_CONST;
87 static void rb_audiocd_plugin_init (RBAudioCdPlugin *plugin);
88 static void rb_audiocd_plugin_finalize (GObject *object);
89 static void impl_activate (RBPlugin *plugin, RBShell *shell);
90 static void impl_deactivate (RBPlugin *plugin, RBShell *shell);
92 static void rb_audiocd_plugin_playing_uri_changed_cb (RBShellPlayer *player,
93 const char *uri,
94 RBAudioCdPlugin *plugin);
95 static RBSource * create_source_cb (RBRemovableMediaManager *rmm,
96 GnomeVFSVolume *volume,
97 RBAudioCdPlugin *plugin);
99 RB_PLUGIN_REGISTER(RBAudioCdPlugin, rb_audiocd_plugin)
101 static void
102 rb_audiocd_plugin_class_init (RBAudioCdPluginClass *klass)
104 GObjectClass *object_class = G_OBJECT_CLASS (klass);
105 RBPluginClass *plugin_class = RB_PLUGIN_CLASS (klass);
107 object_class->finalize = rb_audiocd_plugin_finalize;
109 plugin_class->activate = impl_activate;
110 plugin_class->deactivate = impl_deactivate;
112 RB_PLUGIN_REGISTER_TYPE(rb_audiocd_source);
115 static void
116 rb_audiocd_plugin_init (RBAudioCdPlugin *plugin)
118 rb_debug ("RBAudioCdPlugin initialising");
120 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
121 nautilus_burn_init ();
122 #endif
125 static void
126 rb_audiocd_plugin_finalize (GObject *object)
129 RBAudioCdPlugin *plugin = RB_AUDIOCD_PLUGIN (object);
131 rb_debug ("RBAudioCdPlugin finalising");
133 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
134 nautilus_burn_shutdown ();
135 #endif
137 G_OBJECT_CLASS (rb_audiocd_plugin_parent_class)->finalize (object);
140 static void
141 rb_audiocd_plugin_mount_volume (RBAudioCdPlugin *plugin,
142 GnomeVFSVolume *volume)
144 RBRemovableMediaManager *rmm = NULL;
145 RBSource *source;
147 g_object_get (G_OBJECT (plugin->shell),
148 "removable-media-manager", &rmm,
149 NULL);
151 rb_debug ("checking audiocd for %s", gnome_vfs_volume_get_device_path (volume));
152 source = create_source_cb (rmm, volume, plugin);
153 if (source) {
154 rb_debug ("creating audio cd source behind RMMs back for %p", volume);
155 rb_shell_append_source (plugin->shell, source, NULL);
158 g_object_unref (rmm);
161 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3) && !HAVE_HAL
162 typedef struct
164 gboolean removed;
165 gboolean tray_opened;
166 RBAudioCdPlugin *plugin;
167 NautilusBurnDrive *drive;
168 } RbCdDriveInfo;
170 static void
171 rb_audiocd_plugin_unmount_volume (RBAudioCdPlugin *plugin,
172 GnomeVFSVolume *volume)
174 RBSource *source;
176 source = g_hash_table_lookup (plugin->sources, volume);
177 if (source != NULL) {
178 rb_source_delete_thyself (source);
182 #ifdef HAVE_BURN_DRIVE_DOOR
183 static
184 gboolean poll_tray_opened (RbCdDriveInfo *info)
186 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor ();
187 gboolean new_status;
188 GnomeVFSVolume *volume;
190 if (info->removed) {
191 nautilus_burn_drive_unref (info->drive);
192 g_free (info);
193 return FALSE;
196 new_status = nautilus_burn_drive_door_is_open (info->drive);
198 if (new_status != info->tray_opened) {
199 volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, info->drive->device);
200 rb_debug ("found volume for %s", info->drive->device);
201 if (volume) {
202 if (new_status) {
203 rb_audiocd_plugin_unmount_volume (info->plugin, volume);
204 } else {
205 rb_audiocd_plugin_mount_volume (info->plugin, volume);
207 gnome_vfs_volume_unref (volume);
210 info->tray_opened = new_status;
212 return TRUE;
214 #endif
216 static
217 void end_cd_drive_monitor (RbCdDriveInfo *info,
218 gpointer data)
220 /* this will be freed when the poll next gets called */
221 info->removed = TRUE;
224 static
225 void begin_cd_drive_monitor (NautilusBurnDrive *drive,
226 RBAudioCdPlugin *plugin)
228 #ifdef HAVE_BURN_DRIVE_DOOR
229 RbCdDriveInfo *info = g_new0 (RbCdDriveInfo, 1);
230 GnomeVFSVolumeMonitor *monitor= gnome_vfs_get_volume_monitor ();
231 GnomeVFSVolume *volume;
233 info->drive = drive;
234 info->tray_opened = nautilus_burn_drive_door_is_open (drive);
235 info->plugin = plugin;
237 g_hash_table_insert (plugin->cd_drive_mapping, drive, info);
238 g_timeout_add (1000, (GSourceFunc)poll_tray_opened, info);
240 volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, drive->device);
241 rb_debug ("found volume for %s", drive->device);
243 if (volume) {
244 if (!nautilus_burn_drive_door_is_open (drive)) {
245 rb_audiocd_plugin_mount_volume (plugin, volume);
246 } else {
247 /* it may have got ejected while we weren't monitoring */
248 rb_audiocd_plugin_unmount_volume (plugin, volume);
251 #endif
254 static NautilusBurnDrive *
255 get_nautilus_burn_drive_for_path (const char *path)
257 #ifdef HAVE_BURN_DRIVE_NEW_FROM_PATH
258 return nautilus_burn_drive_new_from_path (path);
259 #else
260 GList *drives, *l;
261 NautilusBurnDrive *path_drive = NULL;
263 drives = nautilus_burn_drive_get_list (FALSE, FALSE);
264 for (l = drives; l != NULL; l = g_list_next (l)) {
265 NautilusBurnDrive *drive = (NautilusBurnDrive*)l->data;
267 if (path_drive == NULL && strcmp (drive->device, path) == 0) {
268 path_drive = drive;
269 } else {
270 nautilus_burn_drive_unref (drive);
273 g_list_free (drives);
275 return path_drive;
276 #endif
278 #endif /* NAUTILUS_BURN < 2.15.3 */
280 static char *
281 split_drive_from_cdda_uri (const char *uri)
283 gchar *copy, *temp, *split;
284 int len;
286 if (!g_str_has_prefix (uri, "cdda://"))
287 return NULL;
289 len = strlen ("cdda://");
291 copy = g_strdup (uri);
292 split = g_utf8_strrchr (copy + len, -1, ':');
294 if (split == NULL) {
295 /* invalid URI, it doesn't contain a ':' */
296 g_free (copy);
297 return NULL;
300 *split = 0;
301 temp = g_strdup (copy + len);
302 g_free (copy);
304 return temp;
307 static void
308 rb_audiocd_plugin_playing_uri_changed_cb (RBShellPlayer *player,
309 const char *uri,
310 RBAudioCdPlugin *plugin)
312 char *old_drive = NULL;
313 char *new_drive = NULL;
315 /* extract the drive paths */
316 if (plugin->playing_uri)
317 old_drive = split_drive_from_cdda_uri (plugin->playing_uri);
319 if (uri != NULL) {
320 new_drive = split_drive_from_cdda_uri (uri);
323 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3) && !HAVE_HAL
324 /* if the drive we're playing from has changed, adjust the polling */
325 if (old_drive == NULL || new_drive == NULL || strcmp (old_drive, new_drive) != 0) {
326 if (old_drive != NULL) {
327 NautilusBurnDrive *drive;
329 rb_debug ("restarting monitoring of drive %s after playing", old_drive);
330 drive = get_nautilus_burn_drive_for_path (old_drive);
331 begin_cd_drive_monitor (drive, plugin);
332 nautilus_burn_drive_unref (drive);
335 if (new_drive != NULL) {
336 NautilusBurnDrive *drive;
338 rb_debug ("stopping monitoring of drive %s while playing", new_drive);
339 drive = get_nautilus_burn_drive_for_path (new_drive);
340 /* removing it from the hash table makes it stop monitoring */
341 g_hash_table_remove (plugin->cd_drive_mapping, drive);
342 nautilus_burn_drive_unref (drive);
345 #endif
347 g_free (plugin->playing_uri);
348 plugin->playing_uri = uri ? g_strdup (uri) : NULL;
351 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3)
352 static const char *
353 nautilus_burn_drive_get_device (NautilusBurnDrive *drive)
355 g_return_val_if_fail (drive != NULL, NULL);
357 return drive->device;
359 #endif
361 static void
362 rb_audiocd_plugin_source_deleted (RBAudioCdSource *source,
363 RBAudioCdPlugin *plugin)
365 GnomeVFSVolume *volume;
367 g_object_get (source, "volume", &volume, NULL);
368 g_hash_table_remove (plugin->sources, volume);
369 g_object_unref (volume);
372 static RBSource *
373 create_source_cb (RBRemovableMediaManager *rmm,
374 GnomeVFSVolume *volume,
375 RBAudioCdPlugin *plugin)
377 RBSource *source = NULL;
379 if (rb_audiocd_is_volume_audiocd (volume)) {
380 source = RB_SOURCE (rb_audiocd_source_new (plugin->shell, volume));
383 if (source != NULL) {
384 g_hash_table_insert (plugin->sources, g_object_ref (volume), g_object_ref (source));
385 g_signal_connect_object (G_OBJECT (source),
386 "deleted", G_CALLBACK (rb_audiocd_plugin_source_deleted),
387 plugin, 0);
390 return source;
393 static void
394 impl_activate (RBPlugin *plugin,
395 RBShell *shell)
397 RBAudioCdPlugin *pi = RB_AUDIOCD_PLUGIN (plugin);
398 RBRemovableMediaManager *rmm;
399 gboolean scanned;
400 GList *drives;
401 GList *it;
402 GnomeVFSVolumeMonitor *monitor;
404 pi->sources = g_hash_table_new_full (g_direct_hash,
405 g_direct_equal,
406 g_object_unref,
407 g_object_unref);
409 pi->shell = shell;
410 g_object_get (G_OBJECT (shell),
411 "removable-media-manager", &rmm,
412 NULL);
414 /* watch for new removable media. use connect_after so * plugins for more specific device types can get in first.
416 g_signal_connect_after (G_OBJECT (rmm),
417 "create-source", G_CALLBACK (create_source_cb),
418 pi);
420 /* only scan if we're being loaded after the initial scan has been done */
421 g_object_get (G_OBJECT (rmm), "scanned", &scanned, NULL);
422 if (scanned) {
423 rb_removable_media_manager_scan (rmm);
426 g_object_unref (rmm);
430 /* monitor the playing song, to disable cd drive polling */
431 g_signal_connect (rb_shell_get_player (shell), "playing-uri-changed",
432 G_CALLBACK (rb_audiocd_plugin_playing_uri_changed_cb),
433 plugin);
436 * Monitor all cd drives for inserted audio cds
438 * This needs to be done seperately from the above, because non-HAL systems don't
439 * (currently) report audio cd insertions as mount events.
441 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3) && !HAVE_HAL
442 pi->cd_drive_mapping = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)end_cd_drive_monitor);
443 drives = nautilus_burn_drive_get_list (FALSE, FALSE);
444 g_list_foreach (drives, (GFunc)begin_cd_drive_monitor, plugin);
445 g_list_free (drives);
446 #endif
448 /* scan cd drives */
449 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
450 drives = nautilus_burn_drive_monitor_get_drives (nautilus_burn_get_drive_monitor ());
451 #else
452 drives = nautilus_burn_drive_get_list (FALSE, FALSE);
453 #endif
455 monitor = gnome_vfs_get_volume_monitor ();
456 for (it = drives; it != NULL; it = g_list_next (it)) {
457 NautilusBurnDrive *drive = (NautilusBurnDrive *)it->data;
458 GnomeVFSVolume *volume;
460 volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, nautilus_burn_drive_get_device (drive));
461 rb_debug ("found volume for %s", nautilus_burn_drive_get_device (drive));
462 if (volume != NULL) {
463 rb_audiocd_plugin_mount_volume (pi, volume);
464 gnome_vfs_volume_unref (volume);
467 g_list_free (drives);
470 static void
471 _delete_cb (GnomeVFSVolume *volume,
472 RBSource *source,
473 RBAudioCdPlugin *plugin)
475 /* block the source deleted handler so we don't modify the hash table
476 * while iterating it.
478 g_signal_handlers_block_by_func (source, rb_audiocd_plugin_source_deleted, plugin);
479 rb_source_delete_thyself (source);
482 static void
483 impl_deactivate (RBPlugin *bplugin,
484 RBShell *shell)
486 RBAudioCdPlugin *plugin = RB_AUDIOCD_PLUGIN (bplugin);
487 RBRemovableMediaManager *rmm = NULL;
488 GtkUIManager *uimanager = NULL;
490 g_object_get (G_OBJECT (shell),
491 "removable-media-manager", &rmm,
492 "ui-manager", &uimanager,
493 NULL);
494 g_signal_handlers_disconnect_by_func (G_OBJECT (rmm), create_source_cb, plugin);
496 g_hash_table_foreach (plugin->sources, (GHFunc)_delete_cb, plugin);
497 g_hash_table_destroy (plugin->sources);
498 plugin->sources = NULL;
499 if (plugin->ui_merge_id) {
500 gtk_ui_manager_remove_ui (uimanager, plugin->ui_merge_id);
501 plugin->ui_merge_id = 0;
504 g_object_unref (G_OBJECT (uimanager));
505 g_object_unref (G_OBJECT (rmm));
507 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3) && !HAVE_HAL
508 g_hash_table_destroy (plugin->cd_drive_mapping);
509 #endif