Summary:
The device monitor flow looks like:
kernel ->
udev (use cdrom_id/usb_id/... to read HW) ->
udisks (monitor device change and collect/map device property to dbus) ->
gnome-disk-utility(connect udisks dbus and map as libgdu) ->
gvfs (monitor gdu_pool or mtab/fstab file to generate signal) ->
GVolumeMonitor signal
gvfs-gdu-volume-monitor can monitor drive/volume/mount change, it depend on libgdu which belong gnome-disk-utility rpm. The libgdu get disks property from dbus of "org.freedesktop.UDisks"(udisks rpm).
1. gdu-volume-monitor-daemon create gduvolumemonitor(real monitor device's status) instance
2. request dbus connection
3. connect gduvolumemonitor signal(drive-changed/volume-added...) dispatch to dbus signal
./monitor/gdu/gdu-volume-monitor-daemon.c: main(){ return g_vfs_proxy_volume_monitor_daemon_main (argc, argv, "org.gtk.Private.GduVolumeMonitor", G_TYPE_GDU_VOLUME_MONITOR); } ./monitor/proxy/gvfsproxyvolumemonitordaemon.c: g_vfs_proxy_volume_monitor_daemon_main (int argc, char *argv[], const char *dbus_name, GType volume_monitor_type){ monitor = G_VOLUME_MONITOR (g_object_new (volume_monitor_type, NULL)); dbus_bus_request_name (connection, dbus_name, DBUS_NAME_FLAG_ALLOW_REPLACEMENT | DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING, &dbus_error); g_signal_connect (monitor, "drive-changed", (GCallback) drive_changed, connection); g_signal_connect (monitor, "drive-connected", (GCallback) drive_connected, connection); g_signal_connect (monitor, "drive-disconnected", (GCallback) drive_disconnected, connection); g_signal_connect (monitor, "drive-eject-button", (GCallback) drive_eject_button, connection); g_signal_connect (monitor, "drive-stop-button", (GCallback) drive_stop_button, connection); g_signal_connect (monitor, "volume-changed", (GCallback) volume_changed, connection); g_signal_connect (monitor, "volume-added", (GCallback) volume_added, connection); g_signal_connect (monitor, "volume-removed", (GCallback) volume_removed, connection); g_signal_connect (monitor, "mount-changed", (GCallback) mount_changed, connection); g_signal_connect (monitor, "mount-added", (GCallback) mount_added, connection); g_signal_connect (monitor, "mount-pre-unmount", (GCallback) mount_pre_unmount, connection); g_signal_connect (monitor, "mount-removed", (GCallback) mount_removed, connection); } static void drive_disconnected (GVolumeMonitor *monitor, GDrive *drive, DBusConnection *connection) { emit_signal (connection, "DriveDisconnected", drive, (AppendFunc) append_drive); }
Trace gduvolumemonitor:
1. construct:
a. init g_unix_mount_monitor instance to monitor mount change
b. init gdu_pool instance to monitor device change
c. connect "mounts_changed/presentable_added..." signal for invoke update_all()
2. update_all(drive for example, it's same as volume/mount):
a. call update_drives() get the current drive list(previous store in monitor->drives)
b. diff current list(monitor->drives) with the new list(real-time store in monitor->pool and ignor fstab)
c. if diff list not null, list_emit change signal("drive_connected/drive_disconnected") to outside
d. gdu-volume-monitor-daemon will catch the signal and send to dbus
g_gdu_volume_monitor_constructor (){ monitor = G_GDU_VOLUME_MONITOR (object); monitor->mount_monitor = g_unix_mount_monitor_new (); g_signal_connect (monitor->mount_monitor, "mounts_changed", G_CALLBACK (mounts_changed), monitor); g_signal_connect (monitor->mount_monitor, "mountpoints_changed", G_CALLBACK (mountpoints_changed), monitor); monitor->pool = gdu_pool_new (); g_signal_connect (monitor->pool, "presentable_added", G_CALLBACK (presentable_added), monitor); g_signal_connect (monitor->pool, "presentable_removed", G_CALLBACK (presentable_removed), monitor); g_signal_connect (monitor->pool, "presentable_changed", G_CALLBACK (presentable_changed), monitor); g_signal_connect (monitor->pool, "presentable_job_changed", G_CALLBACK (presentable_job_changed), monitor); update_all (monitor, TRUE); } update_all (GGduVolumeMonitor *monitor, gboolean emit_changes){ GList *added_drives, *removed_drives; GList *added_volumes, *removed_volumes; GList *added_mounts, *removed_mounts; added_drives = NULL; removed_drives = NULL; added_volumes = NULL; removed_volumes = NULL; added_mounts = NULL; removed_mounts = NULL; update_drives (monitor, &added_drives, &removed_drives); update_volumes (monitor, &added_volumes, &removed_volumes); update_fstab_volumes (monitor, &added_volumes, &removed_volumes); update_mounts (monitor, &added_mounts, &removed_mounts); update_discs (monitor, &added_volumes, &removed_volumes, &added_mounts, &removed_mounts); if (emit_changes) { list_emit (monitor, "drive_disconnected", NULL, removed_drives); list_emit (monitor, "drive_connected", NULL, added_drives); list_emit (monitor, "volume_removed", "removed", added_volumes); list_emit (monitor, "mount_removed", "unmounted", removed_mounts); list_emit (monitor, "mount_added", NULL, added_mounts); } } static void update_drives (GGduVolumeMonitor *monitor, GList **added_drives, GList **removed_drives){ cur_drives = NULL; for (l = monitor->drives; l != NULL; l = l->next) cur_drives = g_list_prepend (cur_drives, g_gdu_drive_get_presentable (G_GDU_DRIVE (l->data))); new_drives = gdu_pool_get_presentables (monitor->pool); for (l = new_drives; l != NULL; l = ll) { GduPresentable *p = GDU_PRESENTABLE (l->data); ll = l->next; if (!GDU_IS_DRIVE (p) || should_drive_be_ignored (monitor->pool, GDU_DRIVE (p), fstab_mount_points)) { g_object_unref (p); new_drives = g_list_delete_link (new_drives, l); } } diff_sorted_lists (cur_drives, new_drives, (GCompareFunc) gdu_presentable_compare, &added, &removed); for (l = removed; l != NULL; l = l->next) { GduPresentable *p = GDU_PRESENTABLE (l->data); drive = find_drive_by_presentable (monitor, p); if (drive != NULL) { /*g_debug ("removing drive %s", gdu_presentable_get_id (p));*/ g_gdu_drive_disconnected (drive); monitor->drives = g_list_remove (monitor->drives, drive); *removed_drives = g_list_prepend (*removed_drives, drive); } } for (l = added; l != NULL; l = l->next) { GduPresentable *p = GDU_PRESENTABLE (l->data); drive = find_drive_by_presentable (monitor, p); if (drive == NULL) { /*g_debug ("adding drive %s", gdu_presentable_get_id (p));*/ drive = g_gdu_drive_new (G_VOLUME_MONITOR (monitor), p); if (drive != NULL) { monitor->drives = g_list_prepend (monitor->drives, drive); *added_drives = g_list_prepend (*added_drives, g_object_ref (drive)); } } } }
Trace gdupool: