#include "rodisc.h" #include static GVolumeMonitor *monitor; static bool guess_volume_type(GVolume *volume, const char **type) { GIcon *icon = g_volume_get_icon(volume); g_return_val_if_fail(G_IS_THEMED_ICON(icon), false); GThemedIcon *ticon = G_THEMED_ICON(icon); const gchar * const * names = g_themed_icon_get_names(ticon); for (const gchar * const * name = names; *name; ++name) { if (g_str_has_prefix(*name, "media-optical")) { if (g_str_has_prefix(*name, "media-optical-dvd")) { *type = RODISC_TYPE_DVD; } else if (g_str_has_prefix(*name, "media-optical-cd")) { *type = RODISC_TYPE_CD; } else { *type = RODISC_TYPE_GENERIC; } return true; } } return false; } static bool set_disc_attrs(RODisc *disc, GVolume *volume) { g_free(disc->label); disc->label = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_LABEL); if (!disc->label || disc->label[0] == '\0') { g_free(disc->label); disc->label = g_volume_get_name(volume); } if (!disc->label || disc->label[0] == '\0') { g_free(disc->label); disc->label = g_strdup("Disc"); } // Open file and seek to end to verify read permission and file size GError *error = NULL; GFileInputStream * stream = g_file_read(disc->file, NULL, &error); if (!stream) { g_warning("Could not open file '%s' for reading: %s", disc->file_path, error->message); g_error_free(error); return false; } if (!g_seekable_seek(G_SEEKABLE(stream), 0, G_SEEK_END, NULL, &error)) { g_warning("Could not seek in file '%s' for obtaining file size: %s", disc->file_path, error->message); g_error_free(error); return false; } disc->size = g_seekable_tell(G_SEEKABLE(stream)); g_input_stream_close(G_INPUT_STREAM(stream), NULL, NULL); g_object_unref(stream); return true; } static void try_add_volume(GVolume *volume) { const char * type; if (!guess_volume_type(volume, &type)) { // Ignore non-optical device return; } char *device_file_path = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); if (!device_file_path) { return; } RODisc *disc = rodisc_new(); char *basename = g_path_get_basename(device_file_path); disc->id = device_file_path; disc->uri = g_strconcat("/", basename, NULL); disc->file = g_file_new_for_path(device_file_path); disc->file_path = g_file_get_path(disc->file); disc->type = type; g_free(basename); if (set_disc_attrs(disc, volume)) { rodisc_export(disc); } else { rodisc_destroy(disc); } } static void try_update_volume(GVolume *volume, RODisc *disc) { const char * type; if (!guess_volume_type(volume, &type)) { g_debug("no longer a optical media"); rodisc_remove(disc); return; } disc->type = type; if (set_disc_attrs(disc, volume)) { rodisc_refresh(disc); } else { rodisc_remove(disc); } } static void monitor_volume_added_cb(GVolumeMonitor *volume_monitor, GVolume *volume, gpointer user_data) { char *device_file_path = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); if (!device_file_path) { return; } g_debug("Volume added: %s", device_file_path); RODisc *disc = rodisc_lookup(device_file_path); if (disc) { g_warning("Device already added: %s", device_file_path); } else { try_add_volume(volume); } g_free(device_file_path); } static void monitor_volume_changed_cb(GVolumeMonitor *volume_monitor, GVolume *volume, gpointer user_data) { char *device_file_path = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); if (!device_file_path) { return; } g_debug("Volume changed: %s", device_file_path); RODisc *disc = rodisc_lookup(device_file_path); if (disc) { try_update_volume(volume, disc); } else { try_add_volume(volume); } g_free(device_file_path); } static void monitor_volume_removed_cb(GVolumeMonitor *volume_monitor, GVolume *volume, gpointer user_data) { char *device_file_path = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); if (!device_file_path) { return; } g_debug("Volume removed: %s", device_file_path); RODisc *disc = rodisc_lookup(device_file_path); if (disc) { rodisc_remove(disc); } g_free(device_file_path); } static void enumerate_volumes() { GList *volumes = g_volume_monitor_get_volumes(monitor); for (GList *l = volumes; l != NULL; l = l->next) { GVolume *volume = G_VOLUME(l->data); try_add_volume(volume); } g_list_free_full(volumes, g_object_unref); } bool monitor_start() { monitor = g_volume_monitor_get(); if (!monitor) { g_warning("Could not get volume monitor"); return false; } g_signal_connect(monitor, "volume-added", G_CALLBACK(monitor_volume_added_cb), NULL); g_signal_connect(monitor, "volume-changed", G_CALLBACK(monitor_volume_changed_cb), NULL); g_signal_connect(monitor, "volume-removed", G_CALLBACK(monitor_volume_removed_cb), NULL); enumerate_volumes(); return true; } void monitor_stop() { g_object_unref(monitor); }