1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
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)
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__
24 #include <string.h> /* For strlen */
27 #include <glib-object.h>
28 #include <glib/gi18n-lib.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
38 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
39 #include <nautilus-burn.h>
42 #ifndef HAVE_BURN_DRIVE_UNREF
43 #define nautilus_burn_drive_unref nautilus_burn_drive_free
47 #include "rb-plugin.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))
73 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3) && !HAVE_HAL
74 GHashTable
*cd_drive_mapping
;
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
,
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
)
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
);
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 ();
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 ();
137 G_OBJECT_CLASS (rb_audiocd_plugin_parent_class
)->finalize (object
);
141 rb_audiocd_plugin_mount_volume (RBAudioCdPlugin
*plugin
,
142 GnomeVFSVolume
*volume
)
144 RBRemovableMediaManager
*rmm
= NULL
;
147 g_object_get (G_OBJECT (plugin
->shell
),
148 "removable-media-manager", &rmm
,
151 rb_debug ("checking audiocd for %s", gnome_vfs_volume_get_device_path (volume
));
152 source
= create_source_cb (rmm
, volume
, plugin
);
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
165 gboolean tray_opened
;
166 RBAudioCdPlugin
*plugin
;
167 NautilusBurnDrive
*drive
;
171 rb_audiocd_plugin_unmount_volume (RBAudioCdPlugin
*plugin
,
172 GnomeVFSVolume
*volume
)
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
184 gboolean
poll_tray_opened (RbCdDriveInfo
*info
)
186 GnomeVFSVolumeMonitor
*monitor
= gnome_vfs_get_volume_monitor ();
188 GnomeVFSVolume
*volume
;
191 nautilus_burn_drive_unref (info
->drive
);
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
);
203 rb_audiocd_plugin_unmount_volume (info
->plugin
, volume
);
205 rb_audiocd_plugin_mount_volume (info
->plugin
, volume
);
207 gnome_vfs_volume_unref (volume
);
210 info
->tray_opened
= new_status
;
217 void end_cd_drive_monitor (RbCdDriveInfo
*info
,
220 /* this will be freed when the poll next gets called */
221 info
->removed
= TRUE
;
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
;
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
);
244 if (!nautilus_burn_drive_door_is_open (drive
)) {
245 rb_audiocd_plugin_mount_volume (plugin
, volume
);
247 /* it may have got ejected while we weren't monitoring */
248 rb_audiocd_plugin_unmount_volume (plugin
, volume
);
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
);
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) {
270 nautilus_burn_drive_unref (drive
);
273 g_list_free (drives
);
278 #endif /* NAUTILUS_BURN < 2.15.3 */
281 split_drive_from_cdda_uri (const char *uri
)
283 gchar
*copy
, *temp
, *split
;
286 if (!g_str_has_prefix (uri
, "cdda://"))
289 len
= strlen ("cdda://");
291 copy
= g_strdup (uri
);
292 split
= g_utf8_strrchr (copy
+ len
, -1, ':');
295 /* invalid URI, it doesn't contain a ':' */
301 temp
= g_strdup (copy
+ len
);
308 rb_audiocd_plugin_playing_uri_changed_cb (RBShellPlayer
*player
,
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
);
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
);
347 g_free (plugin
->playing_uri
);
348 plugin
->playing_uri
= uri
? g_strdup (uri
) : NULL
;
351 #if !NAUTILUS_BURN_CHECK_VERSION(2,15,3)
353 nautilus_burn_drive_get_device (NautilusBurnDrive
*drive
)
355 g_return_val_if_fail (drive
!= NULL
, NULL
);
357 return drive
->device
;
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
);
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
),
394 impl_activate (RBPlugin
*plugin
,
397 RBAudioCdPlugin
*pi
= RB_AUDIOCD_PLUGIN (plugin
);
398 RBRemovableMediaManager
*rmm
;
402 GnomeVFSVolumeMonitor
*monitor
;
404 pi
->sources
= g_hash_table_new_full (g_direct_hash
,
410 g_object_get (G_OBJECT (shell
),
411 "removable-media-manager", &rmm
,
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
),
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
);
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
),
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
);
449 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
450 drives
= nautilus_burn_drive_monitor_get_drives (nautilus_burn_get_drive_monitor ());
452 drives
= nautilus_burn_drive_get_list (FALSE
, FALSE
);
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
);
471 _delete_cb (GnomeVFSVolume
*volume
,
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
);
483 impl_deactivate (RBPlugin
*bplugin
,
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
,
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
);