static void
xfdesktop_volume_icon_update_file_info(XfdesktopFileIcon *icon,
                                       GFileInfo *info)
{
    XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon);

    g_return_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon));

    DBG("entering");

    /* just replace the file info here */
    if(volume_icon->priv->file_info)
        g_object_unref(volume_icon->priv->file_info);
    volume_icon->priv->file_info = info ? g_object_ref(info) : NULL;

    /* update the filesystem info as well */
    if(volume_icon->priv->filesystem_info)
        g_object_unref(volume_icon->priv->filesystem_info);
    if(volume_icon->priv->file) {
        volume_icon->priv->filesystem_info = g_file_query_filesystem_info(volume_icon->priv->file,
                                                                          XFDESKTOP_FILE_INFO_NAMESPACE,
                                                                          NULL, NULL);
    }

    /* invalidate the tooltip */
    if(volume_icon->priv->tooltip) {
        g_free(volume_icon->priv->tooltip);
        volume_icon->priv->tooltip = NULL;
    }

    /* not really easy to check if this changed or not, so just invalidate it */
    xfdesktop_file_icon_invalidate_icon(XFDESKTOP_FILE_ICON(icon));
    xfdesktop_icon_invalidate_pixbuf(XFDESKTOP_ICON(icon));
    xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(icon));
}
static void
cb_show_thumbnails_notify(GObject *gobject,
                          GParamSpec *pspec,
                          gpointer user_data)
{
    XfdesktopRegularFileIcon *regular_file_icon;
    gboolean show_thumbnails = FALSE;

    TRACE("entering");

    if(!user_data || !XFDESKTOP_IS_REGULAR_FILE_ICON(user_data))
        return;

    regular_file_icon = XFDESKTOP_REGULAR_FILE_ICON(user_data);

    g_object_get(regular_file_icon->priv->fmanager, "show-thumbnails", &show_thumbnails, NULL);

    if(regular_file_icon->priv->show_thumbnails != show_thumbnails) {
        XF_DEBUG("show-thumbnails changed! now: %s", show_thumbnails ? "TRUE" : "FALSE");
        regular_file_icon->priv->show_thumbnails = show_thumbnails;
        xfdesktop_file_icon_invalidate_icon(XFDESKTOP_FILE_ICON(regular_file_icon));
        xfdesktop_icon_invalidate_pixbuf(XFDESKTOP_ICON(regular_file_icon));
        xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(regular_file_icon));
    }
}
static void
xfdesktop_regular_file_icon_update_file_info(XfdesktopFileIcon *icon,
                                             GFileInfo *info)
{
    XfdesktopRegularFileIcon *regular_file_icon = XFDESKTOP_REGULAR_FILE_ICON(icon);
    const gchar *old_display_name;
    gchar *new_display_name;
    
    g_return_if_fail(XFDESKTOP_IS_REGULAR_FILE_ICON(icon));
    g_return_if_fail(G_IS_FILE_INFO(info));

    /* release the old file info */
    if(regular_file_icon->priv->file_info) { 
        g_object_unref(regular_file_icon->priv->file_info);
        regular_file_icon->priv->file_info = NULL;
    }

    regular_file_icon->priv->file_info = g_object_ref(info);

    if(regular_file_icon->priv->filesystem_info)
        g_object_unref(regular_file_icon->priv->filesystem_info);

    regular_file_icon->priv->filesystem_info = g_file_query_filesystem_info(regular_file_icon->priv->file,
                                                                            XFDESKTOP_FILESYSTEM_INFO_NAMESPACE,
                                                                            NULL, NULL);

    /* get both, old and new display name */
    old_display_name = regular_file_icon->priv->display_name;
    new_display_name = xfdesktop_file_utils_get_display_name(regular_file_icon->priv->file,
                                                             regular_file_icon->priv->file_info);

    /* check whether the display name has changed with the info update */
    if(g_strcmp0 (old_display_name, new_display_name) != 0) {
        /* replace the display name */
        g_free (regular_file_icon->priv->display_name);
        regular_file_icon->priv->display_name = new_display_name;

        /* notify listeners of the label change */
        xfdesktop_icon_label_changed(XFDESKTOP_ICON(icon));
    } else {
        /* no change, release the new display name */
        g_free (new_display_name);
    }

    /* invalidate the tooltip */
    g_free(regular_file_icon->priv->tooltip);
    regular_file_icon->priv->tooltip = NULL;
    
    /* not really easy to check if this changed or not, so just invalidate it */
    xfdesktop_file_icon_invalidate_icon(XFDESKTOP_FILE_ICON(icon));
    xfdesktop_icon_invalidate_pixbuf(XFDESKTOP_ICON(icon));
    xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(icon));
}
static void
xfdesktop_special_file_icon_changed(GFileMonitor *monitor,
                                    GFile *file,
                                    GFile *other_file,
                                    GFileMonitorEvent event,
                                    XfdesktopSpecialFileIcon *special_file_icon)
{
    g_return_if_fail(G_IS_FILE_MONITOR(monitor));
    g_return_if_fail(G_IS_FILE(file));
    g_return_if_fail(XFDESKTOP_IS_SPECIAL_FILE_ICON(special_file_icon));

    /* We don't care about change events only created/deleted */
    if(event == G_FILE_MONITOR_EVENT_CHANGED ||
       event == G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED ||
       event == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
        return;

    /* release the old file information */
    if(special_file_icon->priv->file_info) {
        g_object_unref(special_file_icon->priv->file_info);
        special_file_icon->priv->file_info = NULL;
    }

    /* release the old file system information */
    if(special_file_icon->priv->filesystem_info) {
        g_object_unref(special_file_icon->priv->filesystem_info);
        special_file_icon->priv->filesystem_info = NULL;
    }

    /* reload the file information */
    special_file_icon->priv->file_info = g_file_query_info(special_file_icon->priv->file,
                                                           XFDESKTOP_FILE_INFO_NAMESPACE,
                                                           G_FILE_QUERY_INFO_NONE,
                                                           NULL, NULL);

    /* reload the file system information */
    special_file_icon->priv->filesystem_info = g_file_query_filesystem_info(special_file_icon->priv->file,
                                                                            XFDESKTOP_FILESYSTEM_INFO_NAMESPACE,
                                                                            NULL, NULL);

    /* update the trash full state */
    if(special_file_icon->priv->type == XFDESKTOP_SPECIAL_FILE_ICON_TRASH)
        xfdesktop_special_file_icon_update_trash_count(special_file_icon);

    /* invalidate the tooltip */
    g_free(special_file_icon->priv->tooltip);
    special_file_icon->priv->tooltip = NULL;

    /* update the icon */
    xfdesktop_file_icon_invalidate_icon(XFDESKTOP_FILE_ICON(special_file_icon));
    xfdesktop_icon_invalidate_pixbuf(XFDESKTOP_ICON(special_file_icon));
    xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(special_file_icon));
}
void
xfdesktop_regular_file_icon_set_pixbuf_opacity(XfdesktopRegularFileIcon *icon,
                                       guint opacity)
{
    g_return_if_fail(XFDESKTOP_IS_REGULAR_FILE_ICON(icon) && opacity <= 100);
    
    if(opacity == icon->priv->pix_opacity)
        return;
    
    icon->priv->pix_opacity = opacity;
    
    xfdesktop_icon_invalidate_pixbuf(XFDESKTOP_ICON(icon));
    xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(icon));
}
static void
xfdesktop_volume_icon_menu_unmount(GtkWidget *widget, gpointer user_data)
{
    XfdesktopVolumeIcon *icon = XFDESKTOP_VOLUME_ICON(user_data);
    GtkWidget *icon_view = xfdesktop_icon_peek_icon_view(XFDESKTOP_ICON(icon));
    GtkWidget *toplevel = gtk_widget_get_toplevel(icon_view);
    GVolume *volume;
    GMount *mount;
    GMountOperation *operation;

    volume = xfdesktop_volume_icon_peek_volume(icon);
    mount = g_volume_get_mount(volume);

    if(!mount)
        return;

#ifdef HAVE_LIBNOTIFY
    xfdesktop_notify_unmount(mount);
#endif

    operation = gtk_mount_operation_new(toplevel ? GTK_WINDOW(toplevel) : NULL);
    gtk_mount_operation_set_screen(GTK_MOUNT_OPERATION(operation),
                                   icon->priv->gscreen);

    g_mount_unmount_with_operation(mount,
                                   G_MOUNT_UNMOUNT_NONE,
                                   operation,
                                   NULL,
                                   xfdesktop_volume_icon_unmount_finish,
                                   g_object_ref(icon));

    g_object_unref(mount);
    g_object_unref(operation);
}
static void
xfdesktop_special_file_icon_trash_empty(GtkWidget *w,
                                        gpointer user_data)
{
    XfdesktopSpecialFileIcon *file_icon = XFDESKTOP_SPECIAL_FILE_ICON(user_data);
    GtkWidget *icon_view, *toplevel;

    icon_view = xfdesktop_icon_peek_icon_view(XFDESKTOP_ICON(file_icon));
    toplevel = gtk_widget_get_toplevel(icon_view);

    xfdesktop_file_utils_empty_trash(file_icon->priv->gscreen,
                                     GTK_WINDOW(toplevel));
}
static void
xfdesktop_volume_icon_unmount_finish(GObject *object,
                                     GAsyncResult *result,
                                     gpointer user_data)
{
    XfdesktopVolumeIcon *icon = XFDESKTOP_VOLUME_ICON(user_data);
    GtkWidget *icon_view = xfdesktop_icon_peek_icon_view(XFDESKTOP_ICON(icon));
    GtkWidget *toplevel = gtk_widget_get_toplevel(icon_view);
    GMount *mount = G_MOUNT(object);
    GError *error = NULL;
    gboolean unmount_successful;
      
    g_return_if_fail(G_IS_MOUNT(object));
    g_return_if_fail(G_IS_ASYNC_RESULT(result));
    g_return_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon));

    unmount_successful = g_mount_unmount_with_operation_finish(mount, result, &error);

    if(!unmount_successful) {
        /* ignore GIO errors handled internally */
        if(error->domain != G_IO_ERROR || error->code != G_IO_ERROR_FAILED_HANDLED) {
            gchar *mount_name = g_mount_get_name(mount);
            gchar *primary = g_markup_printf_escaped(_("Failed to eject \"%s\""), 
                                                     mount_name);

            /* display an error dialog to inform the user */
            xfce_message_dialog(toplevel ? GTK_WINDOW(toplevel) : NULL,
                                _("Eject Failed"), GTK_STOCK_DIALOG_ERROR, 
                                primary, error->message,
                                GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL);

            g_free(primary);
            g_free(mount_name);
        }

        g_error_free(error);
    }

#ifdef HAVE_LIBNOTIFY
    xfdesktop_notify_unmount_finish(mount, unmount_successful);
#endif

    g_object_unref(icon);
}
static void
cb_folder_contents_changed(GFileMonitor     *monitor,
                           GFile            *file,
                           GFile            *other_file,
                           GFileMonitorEvent event,
                           gpointer          user_data)
{
    XfdesktopRegularFileIcon *regular_file_icon;
    gchar *thumbnail_file = NULL;

    if(!user_data || !XFDESKTOP_IS_REGULAR_FILE_ICON(user_data))
        return;

    regular_file_icon = XFDESKTOP_REGULAR_FILE_ICON(user_data);

    /* not showing thumbnails */
    if(!regular_file_icon->priv->show_thumbnails)
        return;

    /* Already has a thumbnail */
    if(regular_file_icon->priv->thumbnail_file != NULL)
        return;

    switch(event) {
        case G_FILE_MONITOR_EVENT_CREATED:
                thumbnail_file = xfdesktop_load_icon_location_from_folder(XFDESKTOP_FILE_ICON(regular_file_icon));
                if(thumbnail_file) {
                    GFile *thumbnail = g_file_new_for_path(thumbnail_file);
                    /* found a thumbnail file, apply it */
                    xfdesktop_regular_file_icon_set_thumbnail_file(XFDESKTOP_ICON(regular_file_icon),
                                                                   thumbnail);
                    g_free(thumbnail_file);
                }
            break;
        default:
            break;
    }
}
static gboolean
volume_icon_changed_timeout(XfdesktopVolumeIcon *volume_icon)
{
    GMount *mount;
    gboolean mounted_before = FALSE;
    gboolean mounted_after = FALSE;

    g_return_val_if_fail(XFDESKTOP_IS_VOLUME_ICON(volume_icon), FALSE);

    DBG("TIMEOUT");

    /* reset the icon's mount point information */
    if(volume_icon->priv->file) {
        g_object_unref(volume_icon->priv->file);
        volume_icon->priv->file = NULL;

        /* apparently the volume was mounted before, otherwise
         * we wouldn't have had a mount point for it */
        mounted_before = TRUE;
    }
    if(volume_icon->priv->file_info) {
        g_object_unref(volume_icon->priv->file_info);
        volume_icon->priv->file_info = NULL;
    }
    if(volume_icon->priv->filesystem_info) {
        g_object_unref(volume_icon->priv->filesystem_info);
        volume_icon->priv->filesystem_info = NULL;
    }

    /* check if we have a valid mount now */
    mount = g_volume_get_mount(volume_icon->priv->volume);
    if(mount) {
        /* load mount point information */
        volume_icon->priv->file = g_mount_get_root(mount);
        volume_icon->priv->file_info = 
            g_file_query_info(volume_icon->priv->file, 
                              XFDESKTOP_FILE_INFO_NAMESPACE,
                              G_FILE_QUERY_INFO_NONE,
                              NULL, NULL);
        volume_icon->priv->filesystem_info = 
            g_file_query_filesystem_info(volume_icon->priv->file,
                                         XFDESKTOP_FILESYSTEM_INFO_NAMESPACE,
                                         NULL, NULL);

        /* release the mount itself */
        g_object_unref(mount);

        /* the device is mounted now (we have a mount point for it) */
        mounted_after = TRUE;
    }

    DBG("MOUNTED BEFORE: %d, MOUNTED AFTER: %d", mounted_before, mounted_after);

    if(mounted_before != mounted_after) {
        /* invalidate the tooltip */
        if(volume_icon->priv->tooltip) {
            g_free(volume_icon->priv->tooltip);
            volume_icon->priv->tooltip = NULL;
        }

        /* not really easy to check if this changed or not, so just invalidate it */
        xfdesktop_icon_invalidate_pixbuf(XFDESKTOP_ICON(volume_icon));
        xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(volume_icon));

        /* finalize the timeout source */
        volume_icon->priv->changed_timeout_id = 0;
        return FALSE;
    } else {
        /* increment the timeout counter */
        volume_icon->priv->changed_timeout_count += 1;

        if(volume_icon->priv->changed_timeout_count >= 5) {
            /* finalize the timeout source */
            volume_icon->priv->changed_timeout_id = 0;
            return FALSE;
        } else {
            DBG("TRY AGAIN");
            return TRUE;
        }
    }
}
static void
xfdesktop_volume_icon_mount_finish(GObject *object,
                                   GAsyncResult *result,
                                   gpointer user_data)
{
    XfdesktopVolumeIcon *icon = XFDESKTOP_VOLUME_ICON(user_data);
    GtkWidget *icon_view = xfdesktop_icon_peek_icon_view(XFDESKTOP_ICON(icon));
    GtkWidget *toplevel = gtk_widget_get_toplevel(icon_view);
    GVolume *volume = G_VOLUME(object);
    GError *error = NULL;

    if(!g_volume_mount_finish(volume, result, &error)) {
        if(error->domain != G_IO_ERROR || error->code != G_IO_ERROR_FAILED_HANDLED) {
            gchar *volume_name = g_volume_get_name(volume);
            gchar *primary = g_markup_printf_escaped(_("Failed to mount \"%s\""),
                                                     volume_name);
            xfce_message_dialog(toplevel ? GTK_WINDOW(toplevel) : NULL,
                                _("Mount Failed"), GTK_STOCK_DIALOG_ERROR, 
                                primary, error->message,
                                GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL);
            g_free(primary);
            g_free(volume_name);
        }
        
        g_error_free(error);
    } else {
        GMount *mount = g_volume_get_mount(volume);
        GFile *file = NULL;
        GFileInfo *info = NULL;

        if(mount) {
            file = g_mount_get_root(mount);
            info = g_file_query_info(file,
                                     XFDESKTOP_FILE_INFO_NAMESPACE,
                                     G_FILE_QUERY_INFO_NONE,
                                     NULL, NULL);
            g_object_unref(mount);
        }

        if(file && info) {
            gboolean activated = FALSE;

            if(icon->priv->file)
                g_object_unref(icon->priv->file);
            icon->priv->file = g_object_ref(file);

            xfdesktop_file_icon_update_file_info(XFDESKTOP_FILE_ICON(icon), info);

            activated = GPOINTER_TO_UINT(g_object_get_qdata(G_OBJECT(icon), 
                                                            xfdesktop_volume_icon_activated_quark));
            if(activated) {
                XfdesktopIcon *icon_p = XFDESKTOP_ICON(icon);
                XFDESKTOP_ICON_CLASS(xfdesktop_volume_icon_parent_class)->activated(icon_p);
            }
            g_object_set_qdata(G_OBJECT(icon), xfdesktop_volume_icon_activated_quark, NULL);
        } else {
            if(icon->priv->file)
                g_object_unref(icon->priv->file);
            icon->priv->file = NULL;

            xfdesktop_file_icon_update_file_info(XFDESKTOP_FILE_ICON(icon), NULL);
        }
            
        if(file)
            g_object_unref(file);

        if(info)
            g_object_unref(info);
    }
}