/** * fm_launch_paths * @ctx: (allow-none): a launch context * @paths: (element-type FmPath): files to launch * @launcher: #FmFileLauncher with callbacks * @user_data: data supplied for callbacks * * Launches files using callbacks in @launcher. * * Returns: %TRUE in case of success. * * Since: 0.1.0 */ gboolean fm_launch_paths(GAppLaunchContext* ctx, GList* paths, FmFileLauncher* launcher, gpointer user_data) { FmFileInfoJob* job = fm_file_info_job_new(NULL, 0); GList* l; QueryErrorData data; gboolean ret; for(l=paths;l;l=l->next) fm_file_info_job_add(job, (FmPath*)l->data); data.ctx = ctx; data.launcher = launcher; data.user_data = user_data; g_signal_connect(job, "error", G_CALLBACK(on_query_target_info_error), &data); ret = fm_job_run_sync_with_mainloop(FM_JOB(job)); g_signal_handlers_disconnect_by_func(job, on_query_target_info_error, &data); if(ret) { GList* file_infos = fm_file_info_list_peek_head_link(job->file_infos); if(file_infos) ret = fm_launch_files(ctx, file_infos, launcher, user_data); else ret = FALSE; } g_object_unref(job); return ret; }
/** * fm_file_ops_job_run_with_progress * @parent: parent window to show dialog over it * @job: (transfer full): job descriptor to run * * Runs the file operation job with a progress dialog. * The returned data structure will be freed in idle handler automatically * when it's not needed anymore. * * NOTE: INCONSISTENCY: it takes a reference from job * * Before 0.1.15 this call had different arguments. * * Return value: (transfer none): progress data; not usable; caller should not free it either. * * Since: 0.1.0 */ FmProgressDisplay* fm_file_ops_job_run_with_progress(GtkWindow* parent, FmFileOpsJob* job) { FmProgressDisplay* data; g_return_val_if_fail(job != NULL, NULL); data = g_slice_new0(FmProgressDisplay); data->job = job; if(parent) data->parent = g_object_ref(parent); data->delay_timeout = g_timeout_add(SHOW_DLG_DELAY, on_show_dlg, data); g_signal_connect(job, "ask", G_CALLBACK(on_ask), data); g_signal_connect(job, "ask-rename", G_CALLBACK(on_ask_rename), data); g_signal_connect(job, "error", G_CALLBACK(on_error), data); g_signal_connect(job, "prepared", G_CALLBACK(on_prepared), data); g_signal_connect(job, "cur-file", G_CALLBACK(on_cur_file), data); g_signal_connect(job, "percent", G_CALLBACK(on_percent), data); g_signal_connect(job, "finished", G_CALLBACK(on_finished), data); g_signal_connect(job, "cancelled", G_CALLBACK(on_cancelled), data); fm_job_run_async(FM_JOB(job)); return data; }
void fm_progress_display_destroy(FmProgressDisplay* data) { if(data->job) { fm_job_cancel(FM_JOB(data->job)); g_signal_handlers_disconnect_by_func(data->job, on_ask, data); g_signal_handlers_disconnect_by_func(data->job, on_ask_rename, data); g_signal_handlers_disconnect_by_func(data->job, on_error, data); g_signal_handlers_disconnect_by_func(data->job, on_cur_file, data); g_signal_handlers_disconnect_by_func(data->job, on_percent, data); g_signal_handlers_disconnect_by_func(data->job, on_finished, data); g_object_unref(data->job); } g_free(data->cur_file); if(data->delay_timeout) g_source_remove(data->delay_timeout); if(data->update_timeout) g_source_remove(data->update_timeout); if(data->dlg) gtk_widget_destroy(data->dlg); g_slice_free(FmProgressDisplay, data); }
static FmFileInfo *_fetch_file_info_for_shortcut(const char *target, GAppLaunchContext* ctx, FmFileLauncher* launcher, gpointer user_data) { FmFileInfoJob *job; QueryErrorData data; FmFileInfo *fi; FmPath *path; job = fm_file_info_job_new(NULL, 0); /* bug #3614794: the shortcut target is a commandline argument */ path = fm_path_new_for_commandline_arg(target); fm_file_info_job_add(job, path); fm_path_unref(path); data.ctx = ctx; data.launcher = launcher; data.user_data = user_data; g_signal_connect(job, "error", G_CALLBACK(on_query_target_info_error), &data); fi = NULL; if (fm_job_run_sync_with_mainloop(FM_JOB(job))) fi = fm_file_info_ref(fm_file_info_list_peek_head(job->file_infos)); g_signal_handlers_disconnect_by_func(job, on_query_target_info_error, &data); g_object_unref(job); return fi; }
static gboolean _fm_file_ops_job_check_paths(FmFileOpsJob* job, GFile* src, GFileInfo* src_inf, GFile* dest) { GError* err = NULL; FmJob* fmjob = FM_JOB(job); if(job->type == FM_FILE_OP_MOVE && g_file_equal(src, dest)) { err = g_error_new_literal(G_IO_ERROR, G_IO_ERROR_FAILED, _("Source and destination are the same.")); } else if(g_file_info_get_file_type(src_inf) == G_FILE_TYPE_DIRECTORY && g_file_has_prefix(dest, src) ) { const char* msg = NULL; if(job->type == FM_FILE_OP_MOVE) msg = _("Cannot move a folder into its sub folder"); else if(job->type == FM_FILE_OP_COPY) msg = _("Cannot copy a folder into its sub folder"); else msg = _("Destination is a sub folder of source"); err = g_error_new_literal(G_IO_ERROR, G_IO_ERROR_FAILED, msg); } if(err) { if(!fm_job_is_cancelled(fmjob)) { fm_file_ops_job_emit_cur_file(job, g_file_info_get_display_name(src_inf)); fm_job_emit_error(fmjob, err, FM_JOB_ERROR_CRITICAL); } g_error_free(err); } return (err == NULL); }
static void fm_progress_display_destroy(FmProgressDisplay* data) { g_signal_handlers_disconnect_by_func(data->job, on_cancelled, data); fm_job_cancel(FM_JOB(data->job)); if (data->suspended) fm_job_resume(FM_JOB(data->job)); g_signal_handlers_disconnect_by_func(data->job, on_ask, data); g_signal_handlers_disconnect_by_func(data->job, on_ask_rename, data); g_signal_handlers_disconnect_by_func(data->job, on_error, data); g_signal_handlers_disconnect_by_func(data->job, on_prepared, data); g_signal_handlers_disconnect_by_func(data->job, on_cur_file, data); g_signal_handlers_disconnect_by_func(data->job, on_percent, data); g_signal_handlers_disconnect_by_func(data->job, on_finished, data); g_object_unref(data->job); if(data->timer) g_timer_destroy(data->timer); if(data->parent) g_object_unref(data->parent); g_free(data->cur_file); g_free(data->old_cur_file); if(data->delay_timeout) g_source_remove(data->delay_timeout); if(data->update_timeout) g_source_remove(data->update_timeout); if(data->dlg) { g_object_weak_unref(G_OBJECT(data->dlg), on_progress_dialog_destroy, data); g_object_unref(data->error_buf); g_object_unref(data->bold_tag); gtk_widget_destroy(GTK_WIDGET(data->dlg)); } if (data->str) g_string_free(data->str, TRUE); g_slice_free(FmProgressDisplay, data); }
static void on_response(GtkDialog* dlg, gint id, FmProgressDisplay* data) { /* cancel the job */ if(id == GTK_RESPONSE_CANCEL || id == GTK_RESPONSE_DELETE_EVENT) { if(data->job) fm_job_cancel(FM_JOB(data->job)); gtk_widget_destroy(GTK_WIDGET(dlg)); } }
static void update_vol(FmPlacesModel* model, FmPlaceItem* item, GtkTreeIter* it, FmFileInfoJob* job) { FmIcon* icon; GIcon* gicon; char* name; GdkPixbuf* pix; GMount* mount; FmPath* path; name = g_volume_get_name(item->vol); if(item->fi->icon) fm_icon_unref(item->fi->icon); gicon = g_volume_get_icon(item->vol); icon = fm_icon_from_gicon(gicon); item->fi->icon = icon; g_object_unref(gicon); mount = g_volume_get_mount(item->vol); if(mount) { GFile* gf = g_mount_get_root(mount); path = fm_path_new_for_gfile(gf); g_object_unref(gf); g_object_unref(mount); item->vol_mounted = TRUE; } else { path = NULL; item->vol_mounted = FALSE; } if(!fm_path_equal(item->fi->path, path)) { fm_file_info_set_path(item->fi, path); if(path) { if(job) fm_file_info_job_add(job, path); else { job = fm_file_info_job_new(NULL, FM_FILE_INFO_JOB_FOLLOW_SYMLINK); model->jobs = g_slist_prepend(model->jobs, job); g_signal_connect(job, "finished", G_CALLBACK(on_file_info_job_finished), model); fm_job_run_async(FM_JOB(job)); } fm_path_unref(path); } } pix = fm_icon_get_pixbuf(item->fi->icon, fm_config->pane_icon_size); gtk_list_store_set(GTK_LIST_STORE(model), it, FM_PLACES_MODEL_COL_ICON, pix, FM_PLACES_MODEL_COL_LABEL, name, -1); g_object_unref(pix); g_free(name); }
static void fm_places_model_finalize(GObject *object) { FmPlacesModel *self; GtkTreeIter it; g_return_if_fail(object != NULL); g_return_if_fail(FM_IS_PLACES_MODEL(object)); self = FM_PLACES_MODEL(object); if(self->jobs) { GSList* l; for(l = self->jobs; l; l=l->next) { fm_job_cancel(FM_JOB(l->data)); g_object_unref(l->data); } g_slist_free(self->jobs); } if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(self), &it)) { do { FmPlaceItem* item; gtk_tree_model_get(GTK_TREE_MODEL(self), &it, FM_PLACES_MODEL_COL_INFO, &item, -1); if(G_LIKELY(item)) place_item_free(item); }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(self), &it)); } gtk_tree_path_free(self->sep_tp); g_signal_handler_disconnect(gtk_icon_theme_get_default(), self->theme_change_handler); g_signal_handler_disconnect(fm_config, self->use_trash_change_handler); g_signal_handler_disconnect(fm_config, self->pane_icon_size_change_handler); g_signal_handlers_disconnect_by_func(self->vol_mon, on_vol_added, self); g_signal_handlers_disconnect_by_func(self->vol_mon, on_vol_removed, self); g_signal_handlers_disconnect_by_func(self->vol_mon, on_vol_changed, self); g_signal_handlers_disconnect_by_func(self->vol_mon, on_mount_added, self); g_object_unref(self->vol_mon); if(self->trash_monitor) { g_signal_handlers_disconnect_by_func(self->trash_monitor, on_trash_changed, self); g_object_unref(self->trash_monitor); } if(self->trash_idle) g_source_remove(self->trash_idle); G_OBJECT_CLASS(fm_places_model_parent_class)->finalize(object); }
static void on_response(GtkDialog* dlg, gint id, FmProgressDisplay* data) { /* cancel the job */ if(id == GTK_RESPONSE_CANCEL) { fm_job_cancel(FM_JOB(data->job)); if (data->suspended) { fm_job_resume(FM_JOB(data->job)); data->suspended = FALSE; } } else if(id == GTK_RESPONSE_CLOSE || id == GTK_RESPONSE_DELETE_EVENT) fm_progress_display_destroy(data); else if (id == 1 && data->suspend) { if (data->suspended) { data->suspended = FALSE; fm_job_resume(FM_JOB(data->job)); gtk_button_set_label(data->suspend, _("_Pause")); gtk_button_set_image(data->suspend, gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON)); } else if (fm_job_pause(FM_JOB(data->job))) { data->suspended = TRUE; gtk_button_set_label(data->suspend, _("_Resume")); gtk_button_set_image(data->suspend, gtk_image_new_from_stock(GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_BUTTON)); } else g_warning("FmJob failed to pause"); } }
static inline FmFileInfo *_new_info_for_native_file(FmDirListJob* job, FmPath* path, const char* path_str, GError** err) { FmFileInfo *fi; if (fm_job_is_cancelled(FM_JOB(job))) return NULL; if (!(job->flags & FM_DIR_LIST_JOB_DETAILED)) return fm_file_info_new_from_native_file(path, path_str, err); fi = fm_file_info_new(); fm_file_info_set_path(fi, path); if (fm_file_info_set_from_native_file(fi, path_str, err)) return fi; fm_file_info_unref(fi); return NULL; }
static void on_response(GtkDialog* dlg, gint id, FmProgressDisplay* data) { /* cancel the job */ if(id == GTK_RESPONSE_CANCEL || id == GTK_RESPONSE_DELETE_EVENT) { if(data->job) { fm_job_cancel(FM_JOB(data->job)); if(id != GTK_RESPONSE_CANCEL) fm_progress_display_destroy(data); } } else if(id == GTK_RESPONSE_CLOSE) fm_progress_display_destroy(data); }
static void on_bookmarks_changed(FmBookmarks* bm, gpointer user_data) { FmPlacesModel* model = FM_PLACES_MODEL(user_data); FmFileInfoJob* job = fm_file_info_job_new(NULL, FM_FILE_INFO_JOB_FOLLOW_SYMLINK); GtkTreeIter it = model->sep_it; /* remove all old bookmarks */ if(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &it)) { while(gtk_list_store_remove(GTK_LIST_STORE(model), &it)) continue; } add_bookmarks(model, job); g_signal_connect(job, "finished", G_CALLBACK(on_file_info_job_finished), model); model->jobs = g_slist_prepend(model->jobs, job); fm_job_run_async(FM_JOB(job)); }
void SidePane::initDirTree() { // TODO DirTreeModel* model = new DirTreeModel(view_); FmFileInfoJob* job = fm_file_info_job_new(NULL, FM_FILE_INFO_JOB_NONE); model->setShowHidden(showHidden_); GList* l; /* query FmFileInfo for home dir and root dir, and then, * add them to dir tree model */ fm_file_info_job_add(job, fm_path_get_home()); fm_file_info_job_add(job, fm_path_get_root()); /* FIXME: maybe it's cleaner to use run_async here? */ fm_job_run_sync_with_mainloop(FM_JOB(job)); for(l = fm_file_info_list_peek_head_link(job->file_infos); l; l = l->next) { FmFileInfo* fi = FM_FILE_INFO(l->data); model->addRoot(fi); } g_object_unref(job); static_cast<DirTreeView*>(view_)->setModel(model); }
/* unref finished job objects in main thread on idle */ static gboolean on_idle_cleanup(gpointer unused) { GSList* jobs; GSList* l; G_LOCK(idle_handler); jobs = finished; finished = NULL; idle_handler = 0; G_UNLOCK(idle_handler); for(l = jobs; l; l=l->next) { FmJob* job = FM_JOB(l->data); if(job->cancel) fm_job_emit_cancelled(job); fm_job_emit_finished(job); g_object_unref(job); } g_slist_free(jobs); return FALSE; }
void fm_folder_reload(FmFolder* folder) { /* FIXME: remove all items and re-run a dir list job. */ GSList* files_to_del = NULL; GList* l = fm_list_peek_head_link(folder->files); if(l) { for(;l;l=l->next) { FmFileInfo* fi = (FmFileInfo*)l->data; files_to_del = g_slist_prepend(files_to_del, fi); } g_signal_emit(folder, signals[FILES_REMOVED], 0, files_to_del); fm_list_clear(folder->files); /* fm_file_info_unref will be invoked. */ g_slist_free(files_to_del); } folder->job = fm_dir_list_job_new(folder->dir_path, FALSE); g_signal_connect(folder->job, "finished", G_CALLBACK(on_job_finished), folder); g_signal_connect(folder->job, "error", G_CALLBACK(on_job_err), folder); fm_job_run_async(FM_JOB(folder->job)); }
static gboolean on_timeout (FmFilePropData *data) { char size_str[128]; FmDeepCountJob *dc = (FmDeepCountJob*) data->dc_job; //gdk_threads_enter (); if (G_LIKELY (dc && !fm_job_is_cancelled (FM_JOB (dc)))) { char *str; fm_file_size_to_str (size_str, dc->total_size, TRUE); str = g_strdup_printf ("%s (%'llu %s)", size_str, dc->total_size, ngettext ("byte", "bytes", dc->total_size)); gtk_label_set_text (GTK_LABEL (data->total_size), str); g_free (str); fm_file_size_to_str (size_str, dc->total_block_size, TRUE); str = g_strdup_printf ("%s (%'llu %s)", size_str, dc->total_block_size, ngettext ("byte", "bytes", dc->total_block_size)); gtk_label_set_text (GTK_LABEL (data->size_on_disk), str); g_free (str); } //gdk_threads_leave (); return TRUE; }
void FilePropsDialog::onFileSizeTimerTimeout() { if(deepCountJob && !fm_job_is_cancelled(FM_JOB(deepCountJob))) { char size_str[128]; fm_file_size_to_str(size_str, sizeof(size_str), deepCountJob->total_size, fm_config->si_unit); // FIXME: // OMG! It's really unbelievable that Qt developers only implement // QObject::tr(... int n). GNU gettext developers are smarter and // they use unsigned long instead of int. // We cannot use Qt here to handle plural forms. So sad. :-( QString str = QString::fromUtf8(size_str) % QString(" (%1 B)").arg(deepCountJob->total_size); // tr(" (%n) byte(s)", "", deepCountJob->total_size); ui->fileSize->setText(str); fm_file_size_to_str(size_str, sizeof(size_str), deepCountJob->total_ondisk_size, fm_config->si_unit); str = QString::fromUtf8(size_str) % QString(" (%1 B)").arg(deepCountJob->total_ondisk_size); // tr(" (%n) byte(s)", "", deepCountJob->total_ondisk_size); ui->onDiskSize->setText(str); } }
static void on_finished (FmFileOpsJob *job, FmProgressDisplay *data) { GtkWidget *parent; if (data->update_timeout) { g_source_remove (data->update_timeout); data->update_timeout = 0; } parent = data->parent; if (data->dlg) { // errors happened if (data->has_error && data->dlg) { gtk_label_set_text (GTK_LABEL (data->current), ""); gtk_label_set_text (GTK_LABEL (data->remaining_time), "00:00:00"); gtk_dialog_set_response_sensitive (GTK_DIALOG (data->dlg), GTK_RESPONSE_CANCEL, FALSE); gtk_dialog_add_button (GTK_DIALOG (data->dlg), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); gtk_image_set_from_stock (GTK_IMAGE (data->icon), GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); gtk_widget_show (data->msg); if (fm_job_is_cancelled (FM_JOB (data->job))) { gtk_label_set_text (GTK_LABEL (data->msg), _("The file operation is cancelled and there are some errors.")); gtk_window_set_title (GTK_WINDOW (data->dlg), _("Cancelled")); } else { gtk_label_set_text (GTK_LABEL (data->msg), _("The file operation is finished, but there are some errors.")); gtk_window_set_title (GTK_WINDOW (data->dlg), _("Finished")); } } else fm_progress_display_destroy (data); g_debug ("file operation is finished!"); } else fm_progress_display_destroy (data); /* sepcial handling for trash * FIXME_pcm: need to refactor this to use a more elegant way later. */ if (job->type == FM_FILE_OP_TRASH) { FmPathList *unsupported = (FmPathList*)g_object_get_data (G_OBJECT (job), "trash-unsupported"); // some files cannot be trashed because underlying filesystems don't support it. // delete them instead if (unsupported) { if (fm_yes_no (GTK_WINDOW (parent), NULL, _("Some files cannot be moved to trash can because " "the underlying file systems don't support this operation.\n" "Do you want to delete them instead?"), TRUE)) { FmJob *job = fm_file_ops_job_new (FM_FILE_OP_DELETE, unsupported); fm_file_ops_job_run_with_progress (GTK_WINDOW (data->parent), (FmFileOpsJob*) job); } } } }
static void fm_file_info_job_init(FmFileInfoJob *self) { self->file_infos = fm_file_info_list_new(); fm_job_init_cancellable(FM_JOB(self)); }
static void fm_places_model_init(FmPlacesModel *self) { GType types[] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER}; GtkTreeIter it; GtkTreePath* tp; FmPlaceItem* item; GList *vols, *l; GIcon* gicon; FmIcon* icon; GFile* gf; GdkPixbuf* pix; FmFileInfoJob* job = fm_file_info_job_new(NULL, FM_FILE_INFO_JOB_FOLLOW_SYMLINK); GtkListStore* model = GTK_LIST_STORE(self); gtk_list_store_set_column_types(GTK_LIST_STORE(self), FM_PLACES_MODEL_N_COLS, types); self->theme_change_handler = g_signal_connect_swapped(gtk_icon_theme_get_default(), "changed", G_CALLBACK(update_icons), self); self->use_trash_change_handler = g_signal_connect(fm_config, "changed::use_trash", G_CALLBACK(on_use_trash_changed), self); self->pane_icon_size_change_handler = g_signal_connect(fm_config, "changed::pane_icon_size", G_CALLBACK(on_pane_icon_size_changed), self); icon = fm_icon_from_name("media-eject"); pix = fm_icon_get_pixbuf(icon, fm_config->pane_icon_size); fm_icon_unref(icon); self->eject_icon = pix; item = g_slice_new0(FmPlaceItem); item->type = FM_PLACES_ITEM_PATH; item->fi = fm_file_info_new(); item->fi->path = fm_path_ref(fm_path_get_home()); item->fi->icon = fm_icon_from_name("user-home"); gtk_list_store_append(model, &it); pix = fm_icon_get_pixbuf(item->fi->icon, fm_config->pane_icon_size); gtk_list_store_set(model, &it, FM_PLACES_MODEL_COL_ICON, pix, FM_PLACES_MODEL_COL_LABEL, item->fi->path->name, FM_PLACES_MODEL_COL_INFO, item, -1); g_object_unref(pix); fm_file_info_job_add(job, item->fi->path); /* Only show desktop in side pane when the user has a desktop dir. */ if(g_file_test(g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP), G_FILE_TEST_IS_DIR)) { item = g_slice_new0(FmPlaceItem); item->type = FM_PLACES_ITEM_PATH; item->fi = fm_file_info_new(); item->fi->path = fm_path_ref(fm_path_get_desktop()); item->fi->icon = fm_icon_from_name("user-desktop"); gtk_list_store_append(model, &it); pix = fm_icon_get_pixbuf(item->fi->icon, fm_config->pane_icon_size); gtk_list_store_set(model, &it, FM_PLACES_MODEL_COL_ICON, pix, FM_PLACES_MODEL_COL_LABEL, _("Desktop"), FM_PLACES_MODEL_COL_INFO, item, -1); g_object_unref(pix); fm_file_info_job_add(job, item->fi->path); } if(fm_config->use_trash) create_trash_item(self); /* FIXME: how to handle trash can? */ item = g_slice_new0(FmPlaceItem); item->type = FM_PLACES_ITEM_PATH; item->fi = fm_file_info_new(); item->fi->path = fm_path_ref(fm_path_get_apps_menu()); item->fi->icon = fm_icon_from_name("system-software-install"); gtk_list_store_append(model, &it); pix = fm_icon_get_pixbuf(item->fi->icon, fm_config->pane_icon_size); gtk_list_store_set(model, &it, FM_PLACES_MODEL_COL_ICON, pix, FM_PLACES_MODEL_COL_LABEL, _("Applications"), FM_PLACES_MODEL_COL_INFO, item, -1); g_object_unref(pix); /* fm_file_info_job_add(job, item->fi->path); */ /* volumes */ self->vol_mon = g_volume_monitor_get(); g_signal_connect(self->vol_mon, "volume-added", G_CALLBACK(on_vol_added), self); g_signal_connect(self->vol_mon, "volume-removed", G_CALLBACK(on_vol_removed), self); g_signal_connect(self->vol_mon, "volume-changed", G_CALLBACK(on_vol_changed), self); g_signal_connect(self->vol_mon, "mount-added", G_CALLBACK(on_mount_added), self); /* separator */ gtk_list_store_append(model, &self->sep_it); /* add volumes to side-pane */ vols = g_volume_monitor_get_volumes(self->vol_mon); for(l=vols;l;l=l->next) { GVolume* vol = G_VOLUME(l->data); add_vol(self, vol, job); g_object_unref(vol); } g_list_free(vols); /* get the path of separator */ self->sep_tp = gtk_tree_model_get_path(GTK_TREE_MODEL(self), &self->sep_it); self->bookmarks = fm_bookmarks_get(); /* bookmarks */ g_signal_connect(self->bookmarks, "changed", G_CALLBACK(on_bookmarks_changed), self); /* add bookmarks to side pane */ add_bookmarks(self, job); g_signal_connect(job, "finished", G_CALLBACK(on_file_info_job_finished), self); self->jobs = g_slist_prepend(self->jobs, job); fm_job_run_async(FM_JOB(job)); }
static void fm_deep_count_job_init(FmDeepCountJob *self) { fm_job_init_cancellable(FM_JOB(self)); }
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; }
static void on_finished(FmFileOpsJob* job, FmProgressDisplay* data) { GtkWindow* parent = NULL; /* preserve pointers that fm_progress_display_destroy() will unreference as they may be requested by trash support below */ if(data->parent) parent = g_object_ref(data->parent); g_object_ref(job); if(data->dlg) { /* errors happened */ if(data->has_error) { gtk_label_set_text(data->current, ""); gtk_label_set_text(data->remaining_time, "00:00:00"); gtk_dialog_set_response_sensitive(data->dlg, GTK_RESPONSE_CANCEL, FALSE); gtk_dialog_add_button(data->dlg, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); gtk_image_set_from_stock(data->icon, GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); gtk_widget_show(GTK_WIDGET(data->msg)); if(fm_job_is_cancelled(FM_JOB(job))) { gtk_label_set_text(data->msg, _("The file operation is cancelled and there are some errors.")); gtk_window_set_title(GTK_WINDOW(data->dlg), _("Cancelled")); } else { gtk_label_set_text(data->msg, _("The file operation is finished, but there are some errors.")); gtk_window_set_title(GTK_WINDOW(data->dlg), _("Finished")); } } else fm_progress_display_destroy(data); g_debug("file operation is finished!"); } else fm_progress_display_destroy(data); /* if it's not destroyed yet then it will be destroyed with dialog window */ /* sepcial handling for trash * FIXME: need to refactor this to use a more elegant way later. */ if(job->type == FM_FILE_OP_TRASH) /* FIXME: direct access to job struct! */ { FmPathList* unsupported = (FmPathList*)g_object_get_data(G_OBJECT(job), "trash-unsupported"); /* some files cannot be trashed because underlying filesystems don't support it. */ g_object_unref(job); if(unsupported) /* delete them instead */ { /* FIXME: parent window might be already destroyed! */ if(fm_yes_no(parent, NULL, _("Some files cannot be moved to trash can because " "the underlying file systems don't support this operation.\n" "Do you want to delete them instead?"), TRUE)) { job = fm_file_ops_job_new(FM_FILE_OP_DELETE, unsupported); fm_file_ops_job_run_with_progress(parent, job); /* it eats reference! */ } } } else g_object_unref(job); if(parent) g_object_unref(parent); }
gboolean on_idle(FmFolder* folder) { GSList* l; FmFileInfoJob* job = NULL; FmPath* path; folder->idle_handler = 0; if(folder->files_to_update || folder->files_to_add) job = (FmFileInfoJob*)fm_file_info_job_new(NULL, 0); if(folder->files_to_update) { GSList* prev = NULL; for(l=folder->files_to_update;l;) { /* if a file is already in files_to_add, remove it. */ if(g_slist_find_custom(folder->files_to_add, l->data, (GCompareFunc)strcmp)) { GSList* tmp = l; l=l->next; if(G_LIKELY(prev)) prev->next = l; g_free(tmp->data); g_slist_free_1(tmp); if(G_UNLIKELY(tmp == folder->files_to_update)) folder->files_to_update = l; continue; } path = fm_path_new_child(folder->dir_path, (char*)l->data); fm_file_info_job_add(job, path); fm_path_unref(path); g_free(l->data); prev = l; l=l->next; } g_slist_free(folder->files_to_update); folder->files_to_update = NULL; } if(folder->files_to_add) { for(l=folder->files_to_add;l;l=l->next) { path = fm_path_new_child(folder->dir_path, (char*)l->data); fm_file_info_job_add(job, path); fm_path_unref(path); g_free(l->data); } g_slist_free(folder->files_to_add); folder->files_to_add = NULL; } if(job) { g_signal_connect(job, "finished", on_file_info_finished, folder); folder->pending_jobs = g_slist_prepend(folder->pending_jobs, job); fm_job_run_async(FM_JOB(job)); } if(folder->files_to_del) { GSList* ll; for(ll=folder->files_to_del;ll;ll=ll->next) { GList* l= (GList*)ll->data; ll->data = l->data; fm_list_delete_link_nounref(folder->files , l); } g_signal_emit(folder, signals[FILES_REMOVED], 0, folder->files_to_del); g_slist_foreach(folder->files_to_del, (GFunc)fm_file_info_unref, NULL); g_slist_free(folder->files_to_del); folder->files_to_del = NULL; } return FALSE; }
static void fm_dir_list_job_init(FmDirListJob *job) { job->files = fm_file_info_list_new(); fm_job_init_cancellable(FM_JOB(job)); }
/** * fm_dir_list_job_add_found_file * @job: the job that collected listing * @file: a FmFileInfo of the newly found file * * This API may be called by the classes derived of FmDirListJob only. * Application developers should not use this API. * When a new file is found in the dir being listed, implementations * of FmDirListJob should call this API with the info of the newly found * file. The FmFileInfo will be added to the found file list. * * If emission of the #FmDirListJob::files-found signal is turned on by * fm_dir_list_job_set_incremental(), the signal will be emitted * for the newly found files after several new files are added. * See the document for the signal for more detail. * * Since: 1.0.2 */ void fm_dir_list_job_add_found_file(FmDirListJob* job, FmFileInfo* file) { fm_file_info_list_push_tail(job->files, file); if(G_UNLIKELY(job->emit_files_found)) fm_job_call_main_thread(FM_JOB(job), queue_add_file, file); }
static gboolean fm_dir_list_job_run_gio(FmDirListJob* job) { GFileEnumerator *enu; GFileInfo *inf; FmFileInfo* fi; GError *err = NULL; FmJob* fmjob = FM_JOB(job); GFile* gf; const char* query; gf = fm_path_to_gfile(job->dir_path); _retry: inf = g_file_query_info(gf, gfile_info_query_attribs, 0, fm_job_get_cancellable(fmjob), &err); if(!inf ) { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MODERATE); g_error_free(err); if( act == FM_JOB_RETRY ) { err = NULL; goto _retry; } else { g_object_unref(gf); return FALSE; } } if( g_file_info_get_file_type(inf) != G_FILE_TYPE_DIRECTORY) { char *path_str = fm_path_to_str(job->dir_path); err = g_error_new(G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, _("The specified directory '%s' is not valid"), path_str); fm_job_emit_error(fmjob, err, FM_JOB_ERROR_CRITICAL); g_free(path_str); g_error_free(err); g_object_unref(gf); g_object_unref(inf); return FALSE; } /* check if FS is R/O and set attr. into inf */ _fm_file_info_job_update_fs_readonly(gf, inf, NULL, NULL); job->dir_fi = fm_file_info_new_from_g_file_data(gf, inf, job->dir_path); g_object_unref(inf); if(G_UNLIKELY(job->flags & FM_DIR_LIST_JOB_DIR_ONLY)) { query = G_FILE_ATTRIBUTE_STANDARD_TYPE","G_FILE_ATTRIBUTE_STANDARD_NAME"," G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN","G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP"," G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK","G_FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL"," G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME"," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME","G_FILE_ATTRIBUTE_STANDARD_ICON"," G_FILE_ATTRIBUTE_STANDARD_SIZE","G_FILE_ATTRIBUTE_STANDARD_TARGET_URI"," "unix::*,time::*,access::*,id::filesystem"; } else query = gfile_info_query_attribs; enu = g_file_enumerate_children (gf, query, 0, fm_job_get_cancellable(fmjob), &err); g_object_unref(gf); if(enu) { while( ! fm_job_is_cancelled(fmjob) ) { inf = g_file_enumerator_next_file(enu, fm_job_get_cancellable(fmjob), &err); if(inf) { FmPath *dir, *sub; GFile *child; if(G_UNLIKELY(job->flags & FM_DIR_LIST_JOB_DIR_ONLY)) { /* FIXME: handle symlinks */ if(g_file_info_get_file_type(inf) != G_FILE_TYPE_DIRECTORY) { g_object_unref(inf); continue; } } /* virtual folders may return children not within them */ dir = fm_path_new_for_gfile(g_file_enumerator_get_container(enu)); if (fm_path_equal(job->dir_path, dir)) sub = fm_path_new_child(job->dir_path, g_file_info_get_name(inf)); else sub = fm_path_new_child(dir, g_file_info_get_name(inf)); child = g_file_get_child(g_file_enumerator_get_container(enu), g_file_info_get_name(inf)); if (g_file_info_get_file_type(inf) == G_FILE_TYPE_DIRECTORY) /* for dir: check if its FS is R/O and set attr. into inf */ _fm_file_info_job_update_fs_readonly(child, inf, NULL, NULL); fi = fm_file_info_new_from_g_file_data(child, inf, sub); fm_path_unref(sub); fm_path_unref(dir); g_object_unref(child); fm_dir_list_job_add_found_file(job, fi); fm_file_info_unref(fi); } else { if(err) { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); /* FM_JOB_RETRY is not supported. */ if(act == FM_JOB_ABORT) fm_job_cancel(fmjob); } /* otherwise it's EOL */ break; } g_object_unref(inf); } g_file_enumerator_close(enu, NULL, &err); g_object_unref(enu); } else { fm_job_emit_error(fmjob, err, FM_JOB_ERROR_CRITICAL); g_error_free(err); return FALSE; } return TRUE; }
static gboolean fm_dir_list_job_run_posix(FmDirListJob* job) { FmJob* fmjob = FM_JOB(job); FmFileInfo* fi; GError *err = NULL; char* path_str; GDir* dir; path_str = fm_path_to_str(job->dir_path); fi = _new_info_for_native_file(job, job->dir_path, path_str, NULL); if(fi) { if(! fm_file_info_is_dir(fi)) { err = g_error_new(G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, _("The specified directory '%s' is not valid"), path_str); fm_file_info_unref(fi); fm_job_emit_error(fmjob, err, FM_JOB_ERROR_CRITICAL); g_error_free(err); g_free(path_str); return FALSE; } job->dir_fi = fi; } else { err = g_error_new(G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, _("The specified directory '%s' is not valid"), path_str); fm_job_emit_error(fmjob, err, FM_JOB_ERROR_CRITICAL); g_error_free(err); g_free(path_str); return FALSE; } dir = g_dir_open(path_str, 0, &err); if( dir ) { const char* name; GString* fpath = g_string_sized_new(4096); int dir_len = strlen(path_str); g_string_append_len(fpath, path_str, dir_len); if(fpath->str[dir_len-1] != '/') { g_string_append_c(fpath, '/'); ++dir_len; } while( ! fm_job_is_cancelled(fmjob) && (name = g_dir_read_name(dir)) ) { FmPath* new_path; g_string_truncate(fpath, dir_len); g_string_append(fpath, name); if(job->flags & FM_DIR_LIST_JOB_DIR_ONLY) /* if we only want directories */ { struct stat st; /* FIXME: this results in an additional stat() call, which is inefficient */ if(stat(fpath->str, &st) == -1 || !S_ISDIR(st.st_mode)) continue; } new_path = fm_path_new_child(job->dir_path, name); _retry: fi = _new_info_for_native_file(job, new_path, fpath->str, &err); if (fi == NULL) /* we got a damaged file */ { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); GFile *gf; GFileInfo *inf; gchar *disp_basename; g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) goto _retry; /* bug #3615271: Damaged mountpoint isn't shown let make a simple file info then */ inf = g_file_info_new(); gf = fm_path_to_gfile(new_path); g_file_info_set_file_type(inf, G_FILE_TYPE_UNKNOWN); g_file_info_set_name(inf, name); disp_basename = g_filename_display_basename(fpath->str); g_file_info_set_display_name(inf, disp_basename); g_free(disp_basename); g_file_info_set_content_type(inf, "inode/x-corrupted"); fi = fm_file_info_new_from_g_file_data(gf, inf, new_path); g_object_unref(inf); g_object_unref(gf); } fm_dir_list_job_add_found_file(job, fi); fm_file_info_unref(fi); fm_path_unref(new_path); } g_string_free(fpath, TRUE); g_dir_close(dir); } else { fm_job_emit_error(fmjob, err, FM_JOB_ERROR_CRITICAL); g_error_free(err); } g_free(path_str); return TRUE; }
static void fm_folder_finalize(GObject *object) { FmFolder *self; g_return_if_fail(object != NULL); g_return_if_fail(FM_IS_FOLDER(object)); self = FM_FOLDER(object); if(self->job) { g_signal_handlers_disconnect_by_func(self->job, on_job_finished, self); g_signal_handlers_disconnect_by_func(self->job, on_job_err, self); fm_job_cancel(FM_JOB(self->job)); /* FIXME: is this ok? */ /* the job will be freed automatically in idle handler. */ } if(self->pending_jobs) { GSList* l; for(l = self->pending_jobs;l;l=l->next) { FmJob* job = FM_JOB(l->data); g_signal_handlers_disconnect_by_func(job, on_job_finished, self); fm_job_cancel(job); /* the job will be freed automatically in idle handler. */ } } /* remove from hash table */ g_hash_table_remove(hash, self->dir_path); if(self->dir_path) fm_path_unref(self->dir_path); if(self->dir_fi) fm_file_info_unref(self->dir_fi); if(self->gf) g_object_unref(self->gf); if(self->mon) { g_signal_handlers_disconnect_by_func(self->mon, on_folder_changed, self); g_object_unref(self->mon); } if(self->idle_handler) { g_source_remove(self->idle_handler); if(self->files_to_add) { g_slist_foreach(self->files_to_add, (GFunc)g_free, NULL); g_slist_free(self->files_to_add); } if(self->files_to_update) { g_slist_foreach(self->files_to_update, (GFunc)g_free, NULL); g_slist_free(self->files_to_update); } if(self->files_to_del) g_slist_free(self->files_to_del); } fm_list_unref(self->files); if (G_OBJECT_CLASS(fm_folder_parent_class)->finalize) (* G_OBJECT_CLASS(fm_folder_parent_class)->finalize)(object); }