static gboolean
grl_optical_media_source_notify_change_stop (GrlSource *source,
                                             GError **error)
{
  GrlOpticalMediaSourcePrivate *priv = GRL_OPTICAL_MEDIA_SOURCE (source)->priv;

  priv->notify_changes = FALSE;

  return TRUE;
}
static void
grl_optical_media_source_finalize (GObject *object)
{
  GrlOpticalMediaSource *source = GRL_OPTICAL_MEDIA_SOURCE (object);
  guint i;

  for (i = 0; i < NUM_MONITOR_SIGNALS; i++) {
    g_signal_handler_disconnect (G_OBJECT (source->priv->monitor),
                                 source->priv->monitor_signal_ids[i]);
  }

  g_object_unref (source->priv->monitor);
  source->priv->monitor = NULL;

  G_OBJECT_CLASS (grl_optical_media_source_parent_class)->finalize (object);
}
static void
parsed_finished (TotemPlParser *pl, GAsyncResult *result, BrowseData *data)
{
  TotemPlParserResult retval;
  GError *error = NULL;

  retval = totem_pl_parser_parse_finish (TOTEM_PL_PARSER (pl), result, &error);

  /* Do the fallback ourselves */
  if (retval == TOTEM_PL_PARSER_RESULT_IGNORED) {
    GRL_DEBUG ("%s: Falling back for %s as has it's been ignored", __FUNCTION__,
               grl_media_get_id (data->media));
    grl_media_set_url (data->media, grl_media_get_id (data->media));
    retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
  }

  if (retval == TOTEM_PL_PARSER_RESULT_SUCCESS &&
      grl_media_get_url (data->media) != NULL) {
    GrlOpticalMediaSource *source;

    source = GRL_OPTICAL_MEDIA_SOURCE (data->bs->source);

    GRL_DEBUG ("%s: Adding %s which resolved to %s", __FUNCTION__,
               grl_media_get_id (data->media),
               grl_media_get_url (data->media));
    data->bs->callback (GRL_SOURCE (source),
                        data->bs->operation_id,
                        data->media,
                        -1,
                        data->bs->user_data,
                        NULL);
    source->priv->list = g_list_append (source->priv->list, g_object_ref (data->media));
  } else {
    if (retval == TOTEM_PL_PARSER_RESULT_ERROR ||
        retval == TOTEM_PL_PARSER_RESULT_CANCELLED) {
      GRL_WARNING ("Failed to parse '%s': %s",
                   grl_media_get_id (data->media),
                   error ? error->message : "No reason");
      g_error_free (error);
    }
    g_object_unref (data->media);
  }
  data->media = NULL;

  resolve_disc_urls (data);
}
static void
grl_optical_media_source_finalize (GObject *object)
{
  GrlOpticalMediaSource *source = GRL_OPTICAL_MEDIA_SOURCE (object);
  guint i;

  g_cancellable_cancel (source->priv->cancellable);
  g_clear_object (&source->priv->cancellable);

  for (i = 0; i < NUM_MONITOR_SIGNALS; i++) {
    g_signal_handler_disconnect (G_OBJECT (source->priv->monitor),
                                 source->priv->monitor_signal_ids[i]);
  }

  g_list_free_full (source->priv->list, g_object_unref);

  g_clear_object (&source->priv->monitor);

  G_OBJECT_CLASS (grl_optical_media_source_parent_class)->finalize (object);
}
static void
grl_optical_media_source_browse (GrlSource *source,
                                 GrlSourceBrowseSpec *bs)
{
  GList *drives;
  GList *volumes;
  GList *l;
  GrlOpticalMediaSourcePrivate *priv = GRL_OPTICAL_MEDIA_SOURCE (source)->priv;
  BrowseData *data;
  GList *media_list;

  GRL_DEBUG ("%s", __FUNCTION__);

  media_list = NULL;

  /* Get the drives */
  drives = g_volume_monitor_get_connected_drives (priv->monitor);
  for (l = drives; l != NULL; l = l->next) {
    GDrive *drive = l->data;

    media_list = add_drive (media_list, drive, GRL_OPTICAL_MEDIA_SOURCE (source));
    g_object_unref (drive);
  }
  g_list_free (drives);

  /* Look for mounted ISO images */
  volumes = g_volume_monitor_get_volumes (priv->monitor);
  for (l = volumes; l != NULL; l = l->next) {
    GVolume *volume = l->data;
    char *path;

    path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);

    if (path != NULL && g_str_has_prefix (path, "/dev/loop"))
      media_list = add_volume (media_list, volume, NULL, GRL_OPTICAL_MEDIA_SOURCE (source));

    g_free (path);
    g_object_unref (volume);
  }
  g_list_free (volumes);

  /* Got nothing? */
  if (media_list == NULL) {
    /* Tell the caller we're done */
    bs->callback (bs->source,
                  bs->operation_id,
                  NULL,
                  0,
                  bs->user_data,
                  NULL);
    return;
  }

  media_list = g_list_reverse (media_list);

  /* And go to resolve all those devices */
  data = g_new0 (BrowseData, 1);
  data->source = source;
  data->bs = bs;
  data->media_list = media_list;
  data->cancellable = g_cancellable_new ();

  grl_operation_set_data (bs->operation_id, data->cancellable);

  data->parser = totem_pl_parser_new ();
  g_object_set (data->parser, "recurse", FALSE, NULL);
  g_signal_connect (G_OBJECT (data->parser), "entry-parsed",
                    G_CALLBACK (entry_parsed_cb), data);

  resolve_disc_urls (data);
}
static void
grl_optical_media_source_browse (GrlSource *source,
                                 GrlSourceBrowseSpec *bs)
{
  GList *mounts, *l;
  GrlOpticalMediaSourcePrivate *priv = GRL_OPTICAL_MEDIA_SOURCE (source)->priv;
  BrowseData *data;
  GList *media_list;

  GRL_DEBUG ("%s", __FUNCTION__);

  g_list_free_full (priv->list, g_object_unref);

  media_list = NULL;

  /* Look for loopback-mounted ISO images and discs */
  mounts = g_volume_monitor_get_mounts (priv->monitor);
  for (l = mounts; l != NULL; l = l->next) {
    GMount *mount = l->data;

    if (!ignore_mount (mount)) {
      GrlMedia *media;
      media = create_media_from_mount (mount);
      if (media)
        media_list = g_list_prepend (media_list, media);
    }

    g_object_unref (mount);
  }
  g_list_free (mounts);

  /* Got nothing? */
  if (media_list == NULL) {
    /* Tell the caller we're done */
    bs->callback (bs->source,
                  bs->operation_id,
                  NULL,
                  0,
                  bs->user_data,
                  NULL);
    return;
  }

  media_list = g_list_reverse (media_list);

  /* And go to resolve all those devices */
  data = g_new0 (BrowseData, 1);
  data->source = source;
  data->bs = bs;
  data->media_list = media_list;
  data->cancellable = g_cancellable_new ();

  grl_operation_set_data (bs->operation_id, data->cancellable);

  data->parser = totem_pl_parser_new ();
  g_object_set (data->parser, "recurse", FALSE, NULL);
  g_signal_connect (G_OBJECT (data->parser), "entry-parsed",
                    G_CALLBACK (entry_parsed_cb), &data->media);

  resolve_disc_urls (data);
}