/* * xfdesktop - xfce4's desktop manager * * Copyright(c) 2006 Brian Tarricone, * Copyright(c) 2006 Benedikt Meurer, * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #endif #ifndef PATH_MAX #define PATH_MAX 4096 #endif #include #ifdef HAVE_THUNARX #include #endif #include "xfdesktop-file-utils.h" #include "xfdesktop-file-properties-dialog.h" #include "xfdesktop-volume-icon.h" struct _XfdesktopVolumeIconPrivate { GdkPixbuf *pix; gchar *tooltip; gint cur_pix_size; ThunarVfsVolume *volume; ThunarVfsInfo *info; GdkScreen *gscreen; }; static void xfdesktop_volume_icon_finalize(GObject *obj); static GdkPixbuf *xfdesktop_volume_icon_peek_pixbuf(XfdesktopIcon *icon, gint size); static G_CONST_RETURN gchar *xfdesktop_volume_icon_peek_label(XfdesktopIcon *icon); static G_CONST_RETURN gchar *xfdesktop_volume_icon_peek_tooltip(XfdesktopIcon *icon); static GdkDragAction xfdesktop_volume_icon_get_allowed_drag_actions(XfdesktopIcon *icon); static GdkDragAction xfdesktop_volume_icon_get_allowed_drop_actions(XfdesktopIcon *icon); static gboolean xfdesktop_volume_icon_do_drop_dest(XfdesktopIcon *icon, XfdesktopIcon *src_icon, GdkDragAction action); static gboolean xfdesktop_volume_icon_populate_context_menu(XfdesktopIcon *icon, GtkWidget *menu); static G_CONST_RETURN ThunarVfsInfo *xfdesktop_volume_icon_peek_info(XfdesktopFileIcon *icon); static void xfdesktop_volume_icon_update_info(XfdesktopFileIcon *icon, ThunarVfsInfo *info); static gboolean xfdesktop_volume_icon_activated(XfdesktopIcon *icon); #ifdef HAVE_THUNARX static void xfdesktop_volume_icon_tfi_init(ThunarxFileInfoIface *iface); #endif static void xfdesktop_volume_icon_volume_changed_cb(ThunarVfsVolume *volume, gpointer user_data); static inline void xfdesktop_volume_icon_invalidate_pixbuf(XfdesktopVolumeIcon *icon); #ifdef HAVE_THUNARX G_DEFINE_TYPE_EXTENDED(XfdesktopVolumeIcon, xfdesktop_volume_icon, XFDESKTOP_TYPE_FILE_ICON, 0, G_IMPLEMENT_INTERFACE(THUNARX_TYPE_FILE_INFO, xfdesktop_volume_icon_tfi_init) ) #else G_DEFINE_TYPE(XfdesktopVolumeIcon, xfdesktop_volume_icon, XFDESKTOP_TYPE_FILE_ICON) #endif static void xfdesktop_volume_icon_class_init(XfdesktopVolumeIconClass *klass) { GObjectClass *gobject_class = (GObjectClass *)klass; XfdesktopIconClass *icon_class = (XfdesktopIconClass *)klass; XfdesktopFileIconClass *file_icon_class = (XfdesktopFileIconClass *)klass; g_type_class_add_private(klass, sizeof(XfdesktopVolumeIconClass)); gobject_class->finalize = xfdesktop_volume_icon_finalize; icon_class->peek_pixbuf = xfdesktop_volume_icon_peek_pixbuf; icon_class->peek_label = xfdesktop_volume_icon_peek_label; icon_class->peek_tooltip = xfdesktop_volume_icon_peek_tooltip; icon_class->get_allowed_drag_actions = xfdesktop_volume_icon_get_allowed_drag_actions; icon_class->get_allowed_drop_actions = xfdesktop_volume_icon_get_allowed_drop_actions; icon_class->do_drop_dest = xfdesktop_volume_icon_do_drop_dest; icon_class->populate_context_menu = xfdesktop_volume_icon_populate_context_menu; icon_class->activated = xfdesktop_volume_icon_activated; file_icon_class->peek_info = xfdesktop_volume_icon_peek_info; file_icon_class->update_info = xfdesktop_volume_icon_update_info; file_icon_class->can_rename_file = (gboolean (*)(XfdesktopFileIcon *))gtk_false; file_icon_class->can_delete_file = (gboolean (*)(XfdesktopFileIcon *))gtk_false; } static void xfdesktop_volume_icon_init(XfdesktopVolumeIcon *icon) { icon->priv = G_TYPE_INSTANCE_GET_PRIVATE(icon, XFDESKTOP_TYPE_VOLUME_ICON, XfdesktopVolumeIconPrivate); } static void xfdesktop_volume_icon_finalize(GObject *obj) { XfdesktopVolumeIcon *icon = XFDESKTOP_VOLUME_ICON(obj); GtkIconTheme *itheme = gtk_icon_theme_get_for_screen(icon->priv->gscreen); g_signal_handlers_disconnect_by_func(G_OBJECT(itheme), G_CALLBACK(xfdesktop_volume_icon_invalidate_pixbuf), icon); g_signal_handlers_disconnect_by_func(G_OBJECT(icon->priv->volume), G_CALLBACK(xfdesktop_volume_icon_volume_changed_cb), icon); if(icon->priv->pix) g_object_unref(G_OBJECT(icon->priv->pix)); if(icon->priv->info) thunar_vfs_info_unref(icon->priv->info); if(icon->priv->volume) g_object_unref(G_OBJECT(icon->priv->volume)); if(icon->priv->tooltip) g_free(icon->priv->tooltip); G_OBJECT_CLASS(xfdesktop_volume_icon_parent_class)->finalize(obj); } #ifdef HAVE_THUNARX static void xfdesktop_volume_icon_tfi_init(ThunarxFileInfoIface *iface) { iface->get_name = xfdesktop_thunarx_file_info_get_name; iface->get_uri = xfdesktop_thunarx_file_info_get_uri; iface->get_parent_uri = xfdesktop_thunarx_file_info_get_parent_uri; iface->get_uri_scheme = xfdesktop_thunarx_file_info_get_uri_scheme_file; iface->get_mime_type = xfdesktop_thunarx_file_info_get_mime_type; iface->has_mime_type = xfdesktop_thunarx_file_info_has_mime_type; iface->is_directory = xfdesktop_thunarx_file_info_is_directory; iface->get_vfs_info = xfdesktop_thunarx_file_info_get_vfs_info; } #endif /* HAVE_THUNARX */ static void xfdesktop_volume_icon_volume_changed_cb(ThunarVfsVolume *volume, gpointer user_data) { XfdesktopFileIcon *file_icon = XFDESKTOP_FILE_ICON(user_data); ThunarVfsPath *new_path; new_path = thunar_vfs_volume_get_mount_point(volume); if(new_path) { ThunarVfsInfo *new_info = thunar_vfs_info_new_for_path(new_path, NULL); if(new_info) { xfdesktop_file_icon_update_info(file_icon, new_info); thunar_vfs_info_unref(new_info); return; } /* |new_path| is owned by |volume| */ } /* both new and old info is NULL or stale */ xfdesktop_file_icon_update_info(file_icon, NULL); } static inline void xfdesktop_volume_icon_invalidate_pixbuf(XfdesktopVolumeIcon *icon) { if(icon->priv->pix) { g_object_unref(G_OBJECT(icon->priv->pix)); icon->priv->pix = NULL; } } static GdkPixbuf * xfdesktop_volume_icon_peek_pixbuf(XfdesktopIcon *icon, gint size) { XfdesktopVolumeIcon *file_icon = XFDESKTOP_VOLUME_ICON(icon); const gchar *icon_name; g_return_val_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon), NULL); if(size != file_icon->priv->cur_pix_size) xfdesktop_volume_icon_invalidate_pixbuf(file_icon); if(!file_icon->priv->pix) { icon_name = thunar_vfs_volume_lookup_icon_name(file_icon->priv->volume, gtk_icon_theme_get_default()); file_icon->priv->pix = xfdesktop_file_utils_get_file_icon(icon_name, file_icon->priv->info, size, NULL, 100); file_icon->priv->cur_pix_size = size; } return file_icon->priv->pix; } G_CONST_RETURN gchar * xfdesktop_volume_icon_peek_label(XfdesktopIcon *icon) { g_return_val_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon), NULL); return thunar_vfs_volume_get_name(XFDESKTOP_VOLUME_ICON(icon)->priv->volume); } static GdkDragAction xfdesktop_volume_icon_get_allowed_drag_actions(XfdesktopIcon *icon) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon); /* volume icons more or less represent the volume's mount point, usually * (hopefully) a local path. so when it's mounted, we certainly can't move * the mount point, but copying and linking should be OK. when not mounted, * we should just disallow everything, since, even if its ThunarVfsInfo * is valid, we can't guarantee it won't change after mounting. */ /* FIXME: should i allow all actions if not mounted as well, and try to * mount and resolve on drop? */ if(thunar_vfs_volume_is_mounted(volume_icon->priv->volume)) { const ThunarVfsInfo *info = xfdesktop_file_icon_peek_info(XFDESKTOP_FILE_ICON(icon)); if(info) { if(info->flags & THUNAR_VFS_FILE_FLAGS_READABLE) return GDK_ACTION_COPY | GDK_ACTION_LINK; else return GDK_ACTION_LINK; } } return 0; } static GdkDragAction xfdesktop_volume_icon_get_allowed_drop_actions(XfdesktopIcon *icon) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon); /* if not mounted, it doesn't really make sense to allow any operations * here. if mounted, we should allow everything if it's writable. */ /* FIXME: should i allow all actions if not mounted as well, and try to * mount and resolve on drop? */ if(thunar_vfs_volume_is_mounted(volume_icon->priv->volume)) { const ThunarVfsInfo *info = xfdesktop_file_icon_peek_info(XFDESKTOP_FILE_ICON(icon)); if(info && info->flags & THUNAR_VFS_FILE_FLAGS_WRITABLE) return GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK; } return 0; } static void xfdesktop_volume_icon_drag_job_error(ThunarVfsJob *job, GError *error, gpointer user_data) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(user_data); XfdesktopFileIcon *src_file_icon = g_object_get_data(G_OBJECT(job), "--xfdesktop-src-file-icon"); XfdesktopFileUtilsFileop fileop = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(job), "--xfdesktop-file-icon-action")); const ThunarVfsInfo *src_info = xfdesktop_file_icon_peek_info(src_file_icon); g_return_if_fail(volume_icon && src_file_icon); xfdesktop_file_utils_handle_fileop_error(NULL, src_info, volume_icon->priv->info, fileop, error); } static ThunarVfsInteractiveJobResponse xfdesktop_volume_icon_interactive_job_ask(ThunarVfsJob *job, const gchar *message, ThunarVfsInteractiveJobResponse choices, gpointer user_data) { GtkWidget *icon_view = xfdesktop_icon_peek_icon_view(XFDESKTOP_ICON(user_data)); GtkWidget *toplevel = gtk_widget_get_toplevel(icon_view); return xfdesktop_file_utils_interactive_job_ask(GTK_WINDOW(toplevel), message, choices); } static void xfdesktop_volume_icon_drag_job_finished(ThunarVfsJob *job, gpointer user_data) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(user_data); XfdesktopFileIcon *src_file_icon = g_object_get_data(G_OBJECT(job), "--xfdesktop-src-file-icon"); if(!xfdesktop_file_icon_remove_active_job(XFDESKTOP_FILE_ICON(volume_icon), job)) g_critical("ThunarVfsJob 0x%p not found in active jobs list", job); if(!xfdesktop_file_icon_remove_active_job(src_file_icon, job)) g_critical("ThunarVfsJob 0x%p not found in active jobs list", job); g_object_unref(G_OBJECT(job)); g_object_unref(G_OBJECT(src_file_icon)); g_object_unref(G_OBJECT(volume_icon)); } static gboolean xfdesktop_volume_icon_do_drop_dest(XfdesktopIcon *icon, XfdesktopIcon *src_icon, GdkDragAction action) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon); XfdesktopFileIcon *src_file_icon = XFDESKTOP_FILE_ICON(src_icon); const ThunarVfsInfo *src_info; ThunarVfsJob *job = NULL; const gchar *name; ThunarVfsPath *dest_path; DBG("entering"); g_return_val_if_fail(volume_icon && src_file_icon, FALSE); g_return_val_if_fail(xfdesktop_volume_icon_get_allowed_drop_actions(icon), FALSE); src_info = xfdesktop_file_icon_peek_info(src_file_icon); if(!src_info) return FALSE; if(thunar_vfs_path_is_root(src_info->path)) return FALSE; name = thunar_vfs_path_get_name(src_info->path); g_return_val_if_fail(name, FALSE); dest_path = thunar_vfs_path_relative(volume_icon->priv->info->path, name); g_return_val_if_fail(dest_path, FALSE); switch(action) { case GDK_ACTION_MOVE: DBG("doing move"); job = thunar_vfs_move_file(src_info->path, dest_path, NULL); break; case GDK_ACTION_COPY: DBG("doing copy"); job = thunar_vfs_copy_file(src_info->path, dest_path, NULL); break; case GDK_ACTION_LINK: DBG("doing link"); job = thunar_vfs_link_file(src_info->path, dest_path, NULL); break; default: g_warning("Unsupported drag action: %d", action); } thunar_vfs_path_unref(dest_path); if(job) { DBG("got job, action initiated"); /* ensure they aren't destroyed until the job is finished */ g_object_ref(G_OBJECT(src_file_icon)); g_object_ref(G_OBJECT(volume_icon)); g_object_set_data(G_OBJECT(job), "--xfdesktop-file-icon-callback", G_CALLBACK(xfdesktop_volume_icon_drag_job_finished)); g_object_set_data(G_OBJECT(job), "--xfdesktop-file-icon-data", icon); xfdesktop_file_icon_add_active_job(XFDESKTOP_FILE_ICON(volume_icon), job); xfdesktop_file_icon_add_active_job(src_file_icon, job); g_object_set_data(G_OBJECT(job), "--xfdesktop-src-file-icon", src_file_icon); g_object_set_data(G_OBJECT(job), "--xfdesktop-file-icon-action", GINT_TO_POINTER(action == GDK_ACTION_MOVE ? XFDESKTOP_FILE_UTILS_FILEOP_MOVE : (action == GDK_ACTION_COPY ? XFDESKTOP_FILE_UTILS_FILEOP_COPY : XFDESKTOP_FILE_UTILS_FILEOP_LINK))); g_signal_connect(G_OBJECT(job), "error", G_CALLBACK(xfdesktop_volume_icon_drag_job_error), volume_icon); g_signal_connect(G_OBJECT(job), "ask", G_CALLBACK(xfdesktop_volume_icon_interactive_job_ask), volume_icon); g_signal_connect(G_OBJECT(job), "finished", G_CALLBACK(xfdesktop_volume_icon_drag_job_finished), volume_icon); g_object_ref(G_OBJECT(job)); return TRUE; } else return FALSE; return FALSE; } static G_CONST_RETURN gchar * xfdesktop_volume_icon_peek_tooltip(XfdesktopIcon *icon) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon); if(!volume_icon->priv->info) return NULL; /* FIXME: something different? */ if(!volume_icon->priv->tooltip) { gchar freebuf[128], totbuf[128], *space; ThunarVfsPath *path; gchar mntpnt[THUNAR_VFS_PATH_MAXSTRLEN] = { 0, }; ThunarVfsFileSize size; struct statvfs stfs; path = thunar_vfs_volume_get_mount_point(volume_icon->priv->volume); if(path && thunar_vfs_path_to_string(path, mntpnt, sizeof(mntpnt), NULL) > 0 && thunar_vfs_info_get_free_space(volume_icon->priv->info, &size) && !statvfs(mntpnt, &stfs)) { thunar_vfs_humanize_size(size, freebuf, sizeof(freebuf)); thunar_vfs_humanize_size((ThunarVfsFileSize)(stfs.f_blocks * stfs.f_bsize), totbuf, sizeof(totbuf)); space = g_strdup_printf(_("%s (%s total)"), freebuf, totbuf); } else space = g_strdup(_("(unknown)")); volume_icon->priv->tooltip = g_strdup_printf(_("Kind: Removable Volume\n" "Mount Point: %s\n" "Free Space: %s"), *mntpnt ? mntpnt : _("(unknown)"), space); g_free(space); } return volume_icon->priv->tooltip; } static void xfdesktop_volume_icon_menu_toggle_mount(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); GError *error = NULL; gboolean is_mount; is_mount = !thunar_vfs_volume_is_mounted(icon->priv->volume); if(!is_mount) thunar_vfs_volume_unmount(icon->priv->volume, toplevel, &error); else thunar_vfs_volume_mount(icon->priv->volume, toplevel, &error); if(error) { gchar *primary = g_markup_printf_escaped(is_mount ? _("Unable to mount \"%s\":") : _("Unable to unmount \"%s\":"), thunar_vfs_volume_get_name(icon->priv->volume)); xfce_message_dialog(toplevel ? GTK_WINDOW(toplevel) : NULL, is_mount ? _("Mount Failed") : _("Unmount Failed"), GTK_STOCK_DIALOG_ERROR, primary, error->message, GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL); g_free(primary); g_error_free(error); } } static void xfdesktop_volume_icon_menu_eject(GtkWidget *widget, gpointer user_data) { XfdesktopVolumeIcon *icon = XFDESKTOP_VOLUME_ICON(user_data); GError *error = NULL; GtkWidget *icon_view = xfdesktop_icon_peek_icon_view(XFDESKTOP_ICON(icon)); GtkWidget *toplevel = gtk_widget_get_toplevel(icon_view); if(!thunar_vfs_volume_eject(icon->priv->volume, toplevel, &error)) { gchar *primary = g_markup_printf_escaped(_("Unable to eject \"%s\":"), thunar_vfs_volume_get_name(icon->priv->volume)); xfce_message_dialog(GTK_WINDOW(toplevel), _("Eject Failed"), GTK_STOCK_DIALOG_ERROR, primary, error->message, GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL); g_free(primary); g_error_free(error); } } static void xfdesktop_volume_icon_menu_properties(GtkWidget *widget, gpointer user_data) { XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(user_data); xfdesktop_file_properties_dialog_show(NULL, icon, NULL); } static gboolean xfdesktop_volume_icon_populate_context_menu(XfdesktopIcon *icon, GtkWidget *menu) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon); ThunarVfsVolume *volume = volume_icon->priv->volume; GtkWidget *mi, *img; img = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU); gtk_widget_show(img); mi = gtk_image_menu_item_new_with_mnemonic(_("_Open")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); g_signal_connect_swapped(G_OBJECT(mi), "activate", G_CALLBACK(xfdesktop_icon_activated), icon); mi = gtk_separator_menu_item_new(); gtk_widget_show(mi); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); if(thunar_vfs_volume_is_ejectable(volume) && thunar_vfs_volume_is_mounted(volume)) { img = gtk_image_new_from_icon_name("media-eject", GTK_ICON_SIZE_MENU); gtk_widget_show(img); mi = gtk_image_menu_item_new_with_mnemonic(_("E_ject Volume")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(xfdesktop_volume_icon_menu_eject), icon); } else { if(thunar_vfs_volume_is_mounted(volume)) { img = gtk_image_new_from_stock(GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU); mi = gtk_image_menu_item_new_with_mnemonic(_("_Unmount Volume")); } else { img = gtk_image_new_from_stock(GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU); mi = gtk_image_menu_item_new_with_mnemonic(_("_Mount Volume")); } gtk_widget_show(img); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(xfdesktop_volume_icon_menu_toggle_mount), icon); } mi = gtk_separator_menu_item_new(); gtk_widget_show(mi); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); img = gtk_image_new_from_stock(GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU); gtk_widget_show(img); mi = gtk_image_menu_item_new_with_mnemonic(_("_Properties...")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); if(!volume_icon->priv->info) gtk_widget_set_sensitive(mi, FALSE); else { g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(xfdesktop_volume_icon_menu_properties), icon); } return TRUE; } static G_CONST_RETURN ThunarVfsInfo * xfdesktop_volume_icon_peek_info(XfdesktopFileIcon *icon) { g_return_val_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon), NULL); return XFDESKTOP_VOLUME_ICON(icon)->priv->info; } static void xfdesktop_volume_icon_update_info(XfdesktopFileIcon *icon, ThunarVfsInfo *info) { XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon); gboolean label_changed = TRUE; g_return_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon)); if(volume_icon->priv->info) { if(info && !strcmp(volume_icon->priv->info->display_name, info->display_name)) { label_changed = FALSE; } thunar_vfs_info_unref(volume_icon->priv->info); } volume_icon->priv->info = info ? thunar_vfs_info_ref(info) : NULL; if(label_changed) xfdesktop_icon_label_changed(XFDESKTOP_ICON(icon)); /* not really easy to check if this changed or not, so just invalidate it */ xfdesktop_volume_icon_invalidate_pixbuf(volume_icon); xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(icon)); } static gboolean xfdesktop_volume_icon_activated(XfdesktopIcon *icon_p) { XfdesktopVolumeIcon *icon = XFDESKTOP_VOLUME_ICON(icon_p); ThunarVfsVolume *volume = (ThunarVfsVolume *)xfdesktop_volume_icon_peek_volume(icon); TRACE("entering"); if(!thunar_vfs_volume_is_mounted(volume)) { xfdesktop_volume_icon_menu_toggle_mount(NULL, icon); if(!thunar_vfs_volume_is_mounted(volume)) return TRUE; /* mount failed; halt signal emission */ } /* chain up */ return XFDESKTOP_ICON_CLASS(xfdesktop_volume_icon_parent_class)->activated(icon_p); } XfdesktopVolumeIcon * xfdesktop_volume_icon_new(ThunarVfsVolume *volume, GdkScreen *screen) { XfdesktopVolumeIcon *volume_icon; ThunarVfsPath *path; g_return_val_if_fail(THUNAR_VFS_IS_VOLUME(volume), NULL); volume_icon = g_object_new(XFDESKTOP_TYPE_VOLUME_ICON, NULL); volume_icon->priv->volume = g_object_ref(G_OBJECT(volume)); volume_icon->priv->gscreen = screen; path = thunar_vfs_volume_get_mount_point(volume); if(path) { volume_icon->priv->info = thunar_vfs_info_new_for_path(path, NULL); /* |path| is owned by |volume|, do not free */ } g_signal_connect(G_OBJECT(volume), "changed", G_CALLBACK(xfdesktop_volume_icon_volume_changed_cb), volume_icon); return volume_icon; } G_CONST_RETURN ThunarVfsVolume * xfdesktop_volume_icon_peek_volume(XfdesktopVolumeIcon *icon) { g_return_val_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon), NULL); return icon->priv->volume; }