/* FIXME: maybe we can support different encoding for different mount points? */ char* fm_path_display_basename(FmPath* path) { if(G_UNLIKELY(!path->parent)) /* root element */ { if( !fm_path_is_native(path) && fm_path_is_virtual(path) ) { if(fm_path_is_trash_root(path)) return g_strdup(_("Trash Can")); if(g_str_has_prefix(path->name, "computer:/")) return g_strdup(_("My Computer")); if(g_str_has_prefix(path->name, "applications:/")) return g_strdup(_("Applications")); if(g_str_has_prefix(path->name, "network:/")) return g_strdup(_("Network")); } } return g_filename_display_name(path->name); }
gboolean fm_dnd_dest_files_dropped(FmDndDest* dd, GdkDragAction action, int info_type, FmList* files) { FmPath* dest; GtkWidget* parent; dest = fm_dnd_dest_get_dest_path(dd); if(!dest) return FALSE; g_debug("%d files-dropped!, info_type: %d", fm_list_get_length(files), info_type); if(fm_list_is_file_info_list(files)) files = fm_path_list_new_from_file_info_list(files); else fm_list_ref(files); parent = gtk_widget_get_toplevel(dd->widget); switch(action) { case GDK_ACTION_MOVE: if(fm_path_is_trash_root(fm_dnd_dest_get_dest_path(dd))) fm_trash_files(GTK_WINDOW(parent), files); else fm_move_files(GTK_WINDOW(parent), files, fm_dnd_dest_get_dest_path(dd)); break; case GDK_ACTION_COPY: fm_copy_files(GTK_WINDOW(parent), files, fm_dnd_dest_get_dest_path(dd)); break; case GDK_ACTION_LINK: // fm_link_files(parent, files, fm_dnd_dest_get_dest_path(dd)); break; case GDK_ACTION_ASK: g_debug("TODO: GDK_ACTION_ASK"); break; } fm_list_unref(files); return TRUE; }
void on_dnd_dest_files_dropped(FmDndDest* dd, GdkDragAction action, int info_type, FmList* files, FmPlacesView* view) { FmPath* dest; GList* l; dest = fm_dnd_dest_get_dest_path(dd); g_debug("action= %d, %d files-dropped!, info_type: %d", action, fm_list_get_length(files), info_type); if(action != GDK_ACTION_LINK) { if(fm_list_is_file_info_list(files)) files = fm_path_list_new_from_file_info_list(files); else fm_list_ref(files); } switch(action) { case GDK_ACTION_MOVE: if(fm_path_is_trash_root(dest)) fm_trash_files(files); else fm_move_files(files, dest); break; case GDK_ACTION_COPY: fm_copy_files(files, dest); break; case GDK_ACTION_LINK: { GtkTreePath* tp = view->dest_row; if(tp) { GtkTreePath* sep = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &sep_it); int idx = gtk_tree_path_get_indices(tp)[0] - gtk_tree_path_get_indices(sep)[0]; gtk_tree_path_free(sep); if(view->dest_pos == GTK_TREE_VIEW_DROP_BEFORE) --idx; for( l=fm_list_peek_head_link(files); l; l=l->next, ++idx ) { FmBookmarkItem* item; if(fm_list_is_file_info_list(files)) { FmFileInfo* fi = (FmFileInfo*)l->data; item = fm_bookmarks_insert( bookmarks, fi->path, fi->disp_name, idx); } else { FmPath* path = (FmPath*)l->data; char* disp_name = g_filename_display_name(path->name); item = fm_bookmarks_insert( bookmarks, path, disp_name, idx); g_free(disp_name); } /* we don't need to add item to places view. Later the bookmarks will be reloaded. */ } } } break; } fm_list_unref(files); if(view->dest_row) { gtk_tree_path_free(view->dest_row); view->dest_row = NULL; } }
GtkWidget* place_item_get_menu(PlaceItem* item) { GtkWidget* menu = NULL; FmFileMenu* file_menu; GtkUIManager* ui = gtk_ui_manager_new(); GtkActionGroup* act_grp = act_grp = gtk_action_group_new("Popup"); gtk_action_group_set_translation_domain(act_grp, GETTEXT_PACKAGE); /* FIXME: merge with FmFileMenu when possible */ if(item->type == PLACE_PATH) { if(item->bm_item) { gtk_action_group_add_actions(act_grp, bm_menu_actions, G_N_ELEMENTS(bm_menu_actions), item); gtk_ui_manager_add_ui_from_string(ui, bookmark_menu_xml, -1, NULL); } else if(fm_path_is_trash_root(item->path)) { gtk_action_group_add_actions(act_grp, trash_menu_actions, G_N_ELEMENTS(trash_menu_actions), item); gtk_ui_manager_add_ui_from_string(ui, trash_menu_xml, -1, NULL); } } else if(item->type == PLACE_VOL) { GtkAction* act; GMount* mnt; gtk_action_group_add_actions(act_grp, vol_menu_actions, G_N_ELEMENTS(vol_menu_actions), item); gtk_ui_manager_add_ui_from_string(ui, vol_menu_xml, -1, NULL); mnt = g_volume_get_mount(item->vol); if(mnt) /* mounted */ { g_object_unref(mnt); act = gtk_action_group_get_action(act_grp, "Mount"); gtk_action_set_sensitive(act, FALSE); } else /* not mounted */ { act = gtk_action_group_get_action(act_grp, "Unmount"); gtk_action_set_sensitive(act, FALSE); } if(g_volume_can_eject(item->vol)) act = gtk_action_group_get_action(act_grp, "Unmount"); else act = gtk_action_group_get_action(act_grp, "Eject"); gtk_action_set_visible(act, FALSE); } else goto _out; gtk_ui_manager_insert_action_group(ui, act_grp, 0); menu = gtk_ui_manager_get_widget(ui, "/popup"); if(menu) { g_signal_connect(menu, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL); g_object_weak_ref(G_OBJECT(menu), g_object_unref, g_object_ref(ui)); } _out: g_object_unref(act_grp); g_object_unref(ui); return menu; }
/** * fm_dnd_dest_get_default_action * @dd FmDndDest object * @target GdkTarget of the target data type * @dest FmFileInfo of the destination file at drop site. * * Returns the default action to take for the dragged files. */ GdkDragAction fm_dnd_dest_get_default_action(FmDndDest* dd, GdkDragContext* drag_context, GdkTarget target) { GdkDragAction action; FmFileInfo* dest = dd->dest_file; if(!dest || !dest->path) return FALSE; /* this is XDirectSave */ if(target == xds_target_atom) return GDK_ACTION_COPY; if(dd->src_files) /* we have got drag source files */ { FmPath* dest_path = dest->path; if(fm_path_is_trash(dest_path)) { if(fm_path_is_trash_root(dest_path)) /* we can only move files to trash can */ action = GDK_ACTION_MOVE; else /* files inside trash are read only */ action = 0; } else if(fm_path_is_virtual(dest_path)) { /* computer:/// and network:/// shouldn't received dropped files. */ /* FIXME: some special handling can be done with menu:// */ action = 0; } else if(list_contains_path(dd->src_files, dest_path)) { /* don't allow dropping files into themselves */ action = 0; } else /* dest is a ordinary path */ { /* determine if the dragged files are on the same device as destination file */ /* Here we only check the first dragged file since checking all of them can * make the operation very slow. */ gboolean same_fs; if(dd->src_dev || dd->src_fs_id) /* we know the device of dragged source files */ { /* compare the device/filesystem id against that of destination file */ if(fm_path_is_native(dest_path)) same_fs = dd->src_dev && (dd->src_dev == dest->dev); else /* FIXME: can we use direct comparison here? */ same_fs = dd->src_fs_id && (0 == g_strcmp0(dd->src_fs_id, dest->fs_id)); action = same_fs ? GDK_ACTION_MOVE : GDK_ACTION_COPY; } else /* we don't know on which device the dragged source files are. */ action = 0; } } else /* we didn't have any data */ { action = 0; if(!dd->waiting_data) /* we're still waiting for "drag-data-received" signal */ { /* retrieve the source files */ gtk_drag_get_data(dd->widget, drag_context, target, time); dd->waiting_data = TRUE; } } if( action && 0 == (drag_context->actions & action) ) action = drag_context->suggested_action; return action; }
static gboolean deep_count_gio(FmDeepCountJob* job, GFileInfo* inf, GFile* gf) { FmJob* fmjob = FM_JOB(job); GError* err = NULL; GFileType type; const char* fs_id; gboolean descend; if(inf) g_object_ref(inf); else { _retry_query_info: inf = g_file_query_info(gf, query_str, (job->flags & FM_DC_JOB_FOLLOW_LINKS) ? 0 : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, fm_job_get_cancellable(fmjob), &err); if(!inf) { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) goto _retry_query_info; return FALSE; } } if(fm_job_is_cancelled(fmjob)) { g_object_unref(inf); return FALSE; } type = g_file_info_get_file_type(inf); descend = TRUE; ++job->count; job->total_size += g_file_info_get_size(inf); job->total_ondisk_size += g_file_info_get_attribute_uint64(inf, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE); /* prepare for moving across different devices */ if( job->flags & FM_DC_JOB_PREPARE_MOVE ) { fs_id = g_file_info_get_attribute_string(inf, G_FILE_ATTRIBUTE_ID_FILESYSTEM); if( g_strcmp0(fs_id, job->dest_fs_id) != 0 ) { /* files on different device requires an additional 'delete' for the source file. */ ++job->total_size; /* this is for the additional delete */ ++job->total_ondisk_size; ++job->count; } else descend = FALSE; } if( type == G_FILE_TYPE_DIRECTORY ) { FmPath* fm_path = fm_path_new_for_gfile(gf); /* check if we need to decends into the dir. */ /* trash:/// doesn't support deleting files recursively */ if(job->flags & FM_DC_JOB_PREPARE_DELETE && fm_path_is_trash(fm_path) && ! fm_path_is_trash_root(fm_path)) descend = FALSE; else { /* only descends into files on the same filesystem */ if( job->flags & FM_DC_JOB_SAME_FS ) { fs_id = g_file_info_get_attribute_string(inf, G_FILE_ATTRIBUTE_ID_FILESYSTEM); descend = (g_strcmp0(fs_id, job->dest_fs_id) == 0); } } fm_path_unref(fm_path); g_object_unref(inf); inf = NULL; if(descend) { GFileEnumerator* enu; _retry_enum_children: enu = g_file_enumerate_children(gf, query_str, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, fm_job_get_cancellable(fmjob), &err); if(enu) { while( !fm_job_is_cancelled(fmjob) ) { inf = g_file_enumerator_next_file(enu, fm_job_get_cancellable(fmjob), &err); if(inf) { GFile* child = g_file_get_child(gf, g_file_info_get_name(inf)); deep_count_gio(job, inf, child); g_object_unref(child); g_object_unref(inf); inf = NULL; } else { if(err) /* error! */ { /* FM_JOB_RETRY is not supported */ /*FmJobErrorAction act = */ fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; } else { /* EOF is reached, do nothing. */ break; } } } g_file_enumerator_close(enu, NULL, NULL); g_object_unref(enu); } else { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) goto _retry_enum_children; } } } else g_object_unref(inf); return TRUE; }