aboutsummaryrefslogtreecommitdiff
path: root/monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'monitor.c')
-rw-r--r--monitor.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/monitor.c b/monitor.c
new file mode 100644
index 0000000..13214bf
--- /dev/null
+++ b/monitor.c
@@ -0,0 +1,212 @@
+#include "rodisc.h"
+
+#include <gio/gio.h>
+
+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);
+}