// FIXME_pcm: maybe we can support different encoding for different mount points? char *fm_path_display_basename (FmPath *path) { if (G_UNLIKELY (!path->parent)) // root_path element { if (!fm_path_is_native (path) && fm_path_is_virtual (path)) { if (fm_path_is_root (path) && fm_path_is_trash (path)) return g_strdup (_("Trash Can")); //~ if (g_str_has_prefix (path->name, "computer:/")) //~ return g_strdup (_("My Computer")); if (fm_path_is_computer (path)) return g_strdup (_("My Computer")); if (g_str_has_prefix (path->name, "menu:/")) { // FIXME_pcm: this should be more flexible const char *p = path->name + 5; while (p[0] == '/') ++p; if (g_str_has_prefix (p, "applications.menu")) return g_strdup (_("Applications")); } if (g_str_has_prefix (path->name, "network:/")) return g_strdup (_("Network")); } } return g_filename_display_name (path->name); }
static gboolean fm_dir_list_job_run(FmJob* fmjob) { gboolean ret; FmDirListJob* job = FM_DIR_LIST_JOB(fmjob); g_return_val_if_fail(job->dir_path != NULL, FALSE); if(fm_path_is_native(job->dir_path)) /* if this is a native file on real file system */ ret = fm_dir_list_job_run_posix(job); else /* this is a virtual path or remote file system path */ ret = fm_dir_list_job_run_gio(job); return ret; }
GFile* fm_path_to_gfile(FmPath* path) { GFile* gf; char* str; str = fm_path_to_str(path); if(fm_path_is_native(path)) gf = g_file_new_for_path(str); else gf = g_file_new_for_uri(str); g_free(str); return gf; }
inline static gboolean cache_src_file_infos(FmDndDest* dd, GtkWidget *dest_widget, gint x, gint y, GdkDragContext *drag_context) { GdkAtom target; target = gtk_drag_dest_find_target( dest_widget, drag_context, NULL ); if( target != GDK_NONE ) { GdkDragAction action; gboolean ret; /* treat X direct save as a special case. */ if( target == gdk_atom_intern_static_string("XdndDirectSave0") ) { /* FIXME: need a better way to handle this. */ action = drag_context->suggested_action; g_signal_emit(dd, signals[QUERY_INFO], 0, x, y, &action, &ret); gdk_drag_status(drag_context, action, time); return TRUE; } /* g_debug("try to cache src_files"); */ dd->mainloop = g_main_loop_new(NULL, TRUE); gtk_drag_get_data(dest_widget, drag_context, target, time); /* run the main loop to block here waiting for * 'drag-data-received' signal being handled first. */ /* it's possible that g_main_loop_quit is called before we really run the loop. */ if(g_main_loop_is_running(dd->mainloop)) g_main_loop_run(dd->mainloop); g_main_loop_unref(dd->mainloop); dd->mainloop = NULL; /* g_debug("src_files cached: %p", dd->src_files); */ /* dd->src_files should be set now */ if( dd->src_files && fm_list_is_file_info_list(dd->src_files) ) { /* cache file system id of source files */ if( fm_file_info_list_is_same_fs(dd->src_files) ) { FmFileInfo* fi = (FmFileInfo*)fm_list_peek_head(dd->src_files); if(fm_path_is_native(fi->path)) dd->src_dev = fi->dev; else dd->src_fs_id = fi->fs_id; } } } return FALSE; }
static void add_bookmarks(FmPlacesModel* model, FmFileInfoJob* job) { FmPlaceItem* item; GList *bms, *l; FmIcon* icon = fm_icon_from_name("folder"); FmIcon* remote_icon = NULL; GdkPixbuf* folder_pix = fm_icon_get_pixbuf(icon, fm_config->pane_icon_size); GdkPixbuf* remote_pix = NULL; bms = fm_bookmarks_list_all(model->bookmarks); for(l=bms;l;l=l->next) { FmBookmarkItem* bm = (FmBookmarkItem*)l->data; GtkTreeIter it; GdkPixbuf* pix; item = g_slice_new0(FmPlaceItem); item->type = FM_PLACES_ITEM_PATH; item->fi = fm_file_info_new(); item->fi->path = fm_path_ref(bm->path); fm_file_info_job_add(job, item->fi->path); if(fm_path_is_native(item->fi->path)) { item->fi->icon = fm_icon_ref(icon); pix = folder_pix; } else { if(G_UNLIKELY(!remote_icon)) { remote_icon = fm_icon_from_name("folder-remote"); remote_pix = fm_icon_get_pixbuf(remote_icon, fm_config->pane_icon_size); } item->fi->icon = fm_icon_ref(remote_icon); pix = remote_pix; } item->bm_item = bm; gtk_list_store_append(GTK_LIST_STORE(model), &it); gtk_list_store_set(GTK_LIST_STORE(model), &it, FM_PLACES_MODEL_COL_ICON, pix, FM_PLACES_MODEL_COL_LABEL, bm->name, FM_PLACES_MODEL_COL_INFO, item, -1); } g_object_unref(folder_pix); fm_icon_unref(icon); if(remote_icon) { fm_icon_unref(remote_icon); if(remote_pix) g_object_unref(remote_pix); } }
/* 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_deep_count_job_run(FmJob* job) { FmDeepCountJob* dc = (FmDeepCountJob*)job; GList* l; l = fm_list_peek_head_link(dc->paths); for(; !fm_job_is_cancelled(job) && l; l=l->next) { FmPath* path = FM_PATH(l->data); if(fm_path_is_native(path)) /* if it's a native file, use posix APIs */ deep_count_posix( dc, path ); else { GFile* gf = fm_path_to_gfile(path); deep_count_gio( dc, NULL, gf ); g_object_unref(gf); } } return TRUE; }
GFile *fm_path_to_gfile (FmPath *path) { GFile *gf; char *str = fm_path_to_str (path); if (fm_path_is_native (path)) { gf = g_file_new_for_path (str); } else { // Escape the path so that it supports spaces and special characters like accentuated ones... char *tmp_str = g_uri_escape_string (str, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE); gf = g_file_new_for_uri (tmp_str); g_free (tmp_str); } g_free (str); return gf; }
/** * fm_path_new_child_len * @parent: a parent path * @basename: basename of a direct child of @parent directory in glib * filename encoding. (can be non-UTF-8). * @len: length of basename * * Returns: a newly created FmPath for the path. You have to call * fm_path_unref () when it's no longer needed. */ FmPath *fm_path_new_child_len (FmPath *parent, const char *basename, int name_len) { FmPath *path; gboolean append_slash = FALSE; int flags; // skip empty basename if (G_UNLIKELY (!basename || name_len == 0)) return parent ? fm_path_ref (path) : NULL; if (G_LIKELY (parent)) // remove slashes if needed. { #if 0 // This saves some memory, but it's too inefficient. // Optimization: reuse existing FmPaths if (fm_path_is_native (parent)) { path = _fm_path_reuse_existing_paths (parent, basename, name_len); if (G_UNLIKELY (path)) return path; } #endif // Inherit of parent flags without the root flag... flags = parent->flags & (~FM_PATH_IS_ROOT); while (basename[0] == '/') { ++basename; --name_len; } while (name_len > 0 && basename[name_len-1] == '/') --name_len; // special case for . and .. if (basename[0] == '.' && (name_len == 1 || (name_len == 2 && basename[1] == '.'))) { if (name_len == 1) // . return parent ? fm_path_ref (parent) : NULL; else // .. { if (parent) return parent->parent ? fm_path_ref (parent->parent) : fm_path_ref (parent); else return NULL; } } } else // this basename is root of the fs (no parent), it can be "/" or something like "ftp://user@host/" { // remove duplicated leading slashes and treat them as one / if (G_UNLIKELY (basename[0] == '/')) // this is a posix path return fm_path_ref (root_path); else // This is something like: trash:///, computer:/// sftp://user@host/ return _fm_path_new_uri_root (basename, name_len, NULL, FALSE); } // remove tailing slashes while (name_len > 0 && basename[name_len-1] == '/') --name_len; if (name_len == 0) return parent ? fm_path_ref (parent) : NULL; path = _fm_path_alloc (parent, (G_UNLIKELY (append_slash) ? name_len + 1 : name_len), flags); memcpy (path->name, basename, name_len); if (G_UNLIKELY (append_slash)) { path->name [name_len] = '/'; path->name [name_len + 1] = '\0'; } else path->name [name_len] = '\0'; return path; }
static gboolean fm_file_info_job_run(FmJob* fmjob) { GList* l; FmFileInfoJob* job = (FmFileInfoJob*)fmjob; GError* err = NULL; if(job->file_infos == NULL) return FALSE; for(l = fm_file_info_list_peek_head_link(job->file_infos); !fm_job_is_cancelled(fmjob) && l;) { FmFileInfo* fi = (FmFileInfo*)l->data; GList* next = l->next; FmPath* path = fm_file_info_get_path(fi); if(job->current) fm_path_unref(job->current); job->current = fm_path_ref(path); if(fm_path_is_native(path)) { char* path_str = fm_path_to_str(path); if(!_fm_file_info_job_get_info_for_native_file(fmjob, fi, path_str, &err)) { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) { g_free(path_str); continue; /* retry */ } fm_file_info_list_delete_link(job->file_infos, l); /* also calls unref */ } else if(G_UNLIKELY(job->flags & FM_FILE_INFO_JOB_EMIT_FOR_EACH_FILE)) fm_job_call_main_thread(fmjob, _emit_current_file, fi); g_free(path_str); /* recursively set display names for path parents */ _check_native_display_names(fm_path_get_parent(path)); } else { GFile* gf; gf = fm_path_to_gfile(path); if(!_fm_file_info_job_get_info_for_gfile(fmjob, fi, gf, &err)) { if(err->domain == G_IO_ERROR && err->code == G_IO_ERROR_NOT_MOUNTED) { GFileInfo *inf; /* location by link isn't mounted; unfortunately we cannot launch a target if we don't know what kind of target we have; lets make a simplest directory-kind GFIleInfo */ /* FIXME: this may be dirty a bit */ g_error_free(err); err = NULL; inf = g_file_info_new(); g_file_info_set_file_type(inf, G_FILE_TYPE_DIRECTORY); g_file_info_set_name(inf, fm_path_get_basename(path)); g_file_info_set_display_name(inf, fm_path_get_basename(path)); fm_file_info_set_from_g_file_data(fi, gf, inf); g_object_unref(inf); } else { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) { g_object_unref(gf); continue; /* retry */ } fm_file_info_list_delete_link(job->file_infos, l); /* also calls unref */ goto _next; } } else if(G_UNLIKELY(job->flags & FM_FILE_INFO_JOB_EMIT_FOR_EACH_FILE)) fm_job_call_main_thread(fmjob, _emit_current_file, fi); /* recursively set display names for path parents */ _check_gfile_display_names(fm_path_get_parent(path), gf); _next: g_object_unref(gf); } l = next; } return TRUE; }
gboolean fm_launch_files(GAppLaunchContext* ctx, GList* file_infos, FmFileLauncher* launcher, gpointer user_data) { GList* l; GHashTable* hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); GList* folders = NULL; FmFileInfo* fi; GError* err = NULL; GAppInfo* app; for(l = file_infos; l; l=l->next) { GList* fis; fi = (FmFileInfo*)l->data; if(fm_file_info_is_dir(fi)) folders = g_list_prepend(folders, fi); else { /* FIXME: handle shortcuts, such as the items in menu:// */ if(fm_path_is_native(fi->path)) { char* filename; if(fm_file_info_is_desktop_entry(fi)) { /* if it's a desktop entry file, directly launch it. */ filename = fm_path_to_str(fi->path); if(!fm_launch_desktop_entry(ctx, filename, NULL, &err)) { if(launcher->error) launcher->error(ctx, err, user_data); g_error_free(err); err = NULL; } continue; } else if(fm_file_info_is_executable_type(fi)) { /* if it's an executable file, directly execute it. */ filename = fm_path_to_str(fi->path); /* FIXME: we need to use eaccess/euidaccess here. */ if(g_file_test(filename, G_FILE_TEST_IS_EXECUTABLE)) { app = g_app_info_create_from_commandline(filename, NULL, 0, NULL); if(app) { if(!g_app_info_launch(app, NULL, ctx, &err)) { if(launcher->error) launcher->error(ctx, err, user_data); g_error_free(err); err = NULL; } g_object_unref(app); continue; } } g_free(filename); } } else /* not a native path */ { if(fm_file_info_is_shortcut(fi) && !fm_file_info_is_dir(fi)) { /* FIXME: special handling for shortcuts */ if(fm_path_is_xdg_menu(fi->path) && fi->target) { if(!fm_launch_desktop_entry(ctx, fi->target, NULL, &err)) { if(launcher->error) launcher->error(ctx, err, user_data); g_error_free(err); err = NULL; } continue; } } } if(fi->type && fi->type->type) { fis = g_hash_table_lookup(hash, fi->type->type); fis = g_list_prepend(fis, fi); g_hash_table_insert(hash, fi->type->type, fis); } } } if(g_hash_table_size(hash) > 0) { GHashTableIter it; const char* type; GList* fis; g_hash_table_iter_init(&it, hash); while(g_hash_table_iter_next(&it, &type, &fis)) { GAppInfo* app = g_app_info_get_default_for_type(type, FALSE); if(!app) { if(launcher->get_app) { FmMimeType* mime_type = ((FmFileInfo*)fis->data)->type; app = launcher->get_app(fis, mime_type, user_data, NULL); } } if(app) { for(l=fis; l; l=l->next) { char* uri; fi = (FmFileInfo*)l->data; uri = fm_path_to_uri(fi->path); l->data = uri; } fis = g_list_reverse(fis); g_app_info_launch_uris(app, fis, ctx, err); /* free URI strings */ g_list_foreach(fis, (GFunc)g_free, NULL); g_object_unref(app); } g_list_free(fis); } } g_hash_table_destroy(hash); if(folders) { folders = g_list_reverse(folders); if(launcher->open_folder) { launcher->open_folder(ctx, folders, user_data, &err); if(err) { if(launcher->error) launcher->error(ctx, err, user_data); g_error_free(err); err = NULL; } } g_list_free(folders); } return TRUE; }
/** * 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; }
gboolean fm_dnd_dest_drag_data_received(FmDndDest* dd, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *sel_data, guint info, guint time) { FmList* files = NULL; GtkWidget *dest_widget = dd->widget; if(info == FM_DND_DEST_TARGET_FM_LIST) { if((sel_data->length >= 0) && (sel_data->format==8)) { /* get the pointer */ memcpy(&files, sel_data->data, sel_data->length); if(files) fm_list_ref(files); if(files) { FmFileInfo* fi = FM_FILE_INFO(fm_list_peek_head(files)); /* get the device of the first dragged source file */ if(fm_path_is_native(fi->path)) dd->src_dev = fi->dev; else dd->src_fs_id = fi->fs_id; } } } else if(info == FM_DND_DEST_TARGET_URI_LIST) { if((sel_data->length >= 0) && (sel_data->format==8)) { gchar **uris; uris = gtk_selection_data_get_uris( sel_data ); files = fm_path_list_new_from_uris((const char **)uris); g_free(uris); if(files) { GFileInfo* inf; FmPath* path = FM_PATH(fm_list_peek_head(files)); GFile* gf = fm_path_to_gfile(path); const char* attr = fm_path_is_native(path) ? G_FILE_ATTRIBUTE_UNIX_DEVICE : G_FILE_ATTRIBUTE_ID_FILESYSTEM; inf = g_file_query_info(gf, attr, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); g_object_unref(gf); if(fm_path_is_native(path)) dd->src_dev = g_file_info_get_attribute_uint32(inf, G_FILE_ATTRIBUTE_UNIX_DEVICE); else dd->src_fs_id = g_intern_string(g_file_info_get_attribute_string(inf, G_FILE_ATTRIBUTE_ID_FILESYSTEM)); g_object_unref(inf); } } } else if(info == FM_DND_DEST_TARGET_XDS) /* X direct save */ { if( sel_data->format == 8 && sel_data->length == 1 && sel_data->data[0] == 'F') { gdk_property_change(GDK_DRAWABLE(drag_context->source_window), xds_target_atom, gdk_atom_intern_static_string("text/plain"), 8, GDK_PROP_MODE_REPLACE, (const guchar *)"", 0); } else if(sel_data->format == 8 && sel_data->length == 1 && sel_data->data[0] == 'S') { /* XDS succeeds */ } gtk_drag_finish(drag_context, TRUE, FALSE, time); return TRUE; } else return FALSE; /* remove previously cached source files. */ if(G_UNLIKELY(dd->src_files)) { fm_list_unref(dd->src_files); dd->src_files = NULL; } dd->src_files = files; dd->waiting_data = FALSE; dd->info_type = info; return TRUE; }
/** * fm_launch_files * @ctx: (allow-none): a launch context * @file_infos: (element-type FmFileInfo): 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_files(GAppLaunchContext* ctx, GList* file_infos, FmFileLauncher* launcher, gpointer user_data) { GList* l; GHashTable* hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); GList *folders = NULL; FmFileInfo* fi; GList *targets = NULL; GError* err = NULL; GAppInfo* app; const char* type; for(l = file_infos; l; l=l->next) { GList* fis; char *filename, *scheme; const char *target = NULL; fi = (FmFileInfo*)l->data; /* special handling for shortcuts */ if (!fm_file_info_is_symlink(fi)) /* symlinks also has fi->target, but we only handle shortcuts here. */ target = fm_file_info_get_target(fi); if (launcher->open_folder && fm_file_info_is_dir(fi)) { /* special handling for shortcuts */ if(target) { fi = _fetch_file_info_for_shortcut(fm_file_info_get_target(fi), ctx, launcher, user_data); if (fi == NULL) /* error was shown by job already */ continue; targets = g_list_prepend(targets, fi); } folders = g_list_prepend(folders, fi); } else if (fm_file_info_is_desktop_entry(fi)) { _launch_desktop_entry: if (!target) filename = fm_path_to_str(fm_file_info_get_path(fi)); fm_launch_desktop_entry(ctx, target ? target : filename, NULL, launcher, user_data); if (!target) g_free(filename); continue; } else { FmPath* path = fm_file_info_get_path(fi); FmMimeType* mime_type = NULL; if(fm_path_is_native(path)) { /* special handling for shortcuts */ if (target) { if (fm_file_info_get_mime_type(fi) == _fm_mime_type_get_inode_x_shortcut()) /* if we already know MIME type then use it instead */ { scheme = g_uri_parse_scheme(target); if (scheme) { /* FIXME: this is rough! */ if (strcmp(scheme, "file") != 0 && strcmp(scheme, "trash") != 0 && strcmp(scheme, "network") != 0 && strcmp(scheme, "computer") != 0 && strcmp(scheme, "menu") != 0) { /* we don't support this URI internally, try GIO */ app = g_app_info_get_default_for_uri_scheme(scheme); if (app) { fis = g_list_prepend(NULL, (char *)target); fm_app_info_launch_uris(app, fis, ctx, &err); g_list_free(fis); g_object_unref(app); } else if (launcher->error) g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED, _("No default application is set to launch URIs %s://"), scheme); if (err) { launcher->error(ctx, err, NULL, user_data); g_clear_error(&err); } g_free(scheme); continue; } g_free(scheme); } } else mime_type = fm_file_info_get_mime_type(fi); /* retrieve file info for target otherwise and handle it */ fi = _fetch_file_info_for_shortcut(target, ctx, launcher, user_data); if (fi == NULL) /* error was shown by job already */ continue; targets = g_list_prepend(targets, fi); path = fm_file_info_get_path(fi); /* special handling for desktop entries */ if (fm_file_info_is_desktop_entry(fi)) goto _launch_desktop_entry; } if(fm_file_info_is_executable_type(fi)) { /* if it's an executable file, directly execute it. */ filename = fm_path_to_str(path); /* FIXME: we need to use eaccess/euidaccess here. */ if(g_file_test(filename, G_FILE_TEST_IS_EXECUTABLE)) { if(launcher->exec_file) { FmFileLauncherExecAction act = launcher->exec_file(fi, user_data); GAppInfoCreateFlags flags = 0; switch(act) { case FM_FILE_LAUNCHER_EXEC_IN_TERMINAL: flags |= G_APP_INFO_CREATE_NEEDS_TERMINAL; /* NOTE: no break here */ case FM_FILE_LAUNCHER_EXEC: { /* filename may contain spaces. Fix #3143296 */ char* quoted = g_shell_quote(filename); app = fm_app_info_create_from_commandline(quoted, NULL, flags, NULL); g_free(quoted); if(app) { char* run_path = g_path_get_dirname(filename); char* cwd = NULL; /* bug #3589641: scripts are ran from $HOME. since GIO launcher is kinda ugly - it has no means to set running directory so we do workaround - change directory to it */ if(run_path && strcmp(run_path, ".")) { cwd = g_get_current_dir(); if(chdir(run_path) != 0) { g_free(cwd); cwd = NULL; if (launcher->error) { g_set_error(&err, G_IO_ERROR, g_io_error_from_errno(errno), _("Cannot set working directory to '%s': %s"), run_path, g_strerror(errno)); launcher->error(ctx, err, NULL, user_data); g_clear_error(&err); } } } g_free(run_path); if(!fm_app_info_launch(app, NULL, ctx, &err)) { if(launcher->error) launcher->error(ctx, err, NULL, user_data); g_error_free(err); err = NULL; } if(cwd) /* return back */ { if(chdir(cwd) != 0) g_warning("fm_launch_files(): chdir() failed"); g_free(cwd); } g_object_unref(app); continue; } break; } case FM_FILE_LAUNCHER_EXEC_OPEN: break; case FM_FILE_LAUNCHER_EXEC_CANCEL: continue; } } } g_free(filename); } } if (mime_type == NULL) mime_type = fm_file_info_get_mime_type(fi); if(mime_type && (type = fm_mime_type_get_type(mime_type))) { fis = g_hash_table_lookup(hash, type); fis = g_list_prepend(fis, fi); g_hash_table_insert(hash, (gpointer)type, fis); } else if (launcher->error) { g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED, _("Could not determine content type of file '%s' to launch it"), fm_file_info_get_disp_name(fi)); launcher->error(ctx, err, NULL, user_data); g_clear_error(&err); } } } if(g_hash_table_size(hash) > 0) { GHashTableIter it; GList* fis; g_hash_table_iter_init(&it, hash); while(g_hash_table_iter_next(&it, (void**)&type, (void**)&fis)) { GAppInfo* app = g_app_info_get_default_for_type(type, FALSE); if(!app) { if(launcher->get_app) { FmMimeType* mime_type = fm_file_info_get_mime_type((FmFileInfo*)fis->data); app = launcher->get_app(fis, mime_type, user_data, NULL); } } if(app) { for(l=fis; l; l=l->next) { char* uri; fi = (FmFileInfo*)l->data; /* special handling for shortcuts */ if (fm_file_info_is_shortcut(fi)) uri = g_strdup(fm_file_info_get_target(fi)); else uri = fm_path_to_uri(fm_file_info_get_path(fi)); l->data = uri; } fis = g_list_reverse(fis); fm_app_info_launch_uris(app, fis, ctx, &err); /* free URI strings */ g_list_foreach(fis, (GFunc)g_free, NULL); g_object_unref(app); } else if (launcher->error) g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED, _("No default application is set for MIME type %s"), type); if (err) { launcher->error(ctx, err, NULL, user_data); g_clear_error(&err); } g_list_free(fis); } } g_hash_table_destroy(hash); if(folders) { folders = g_list_reverse(folders); if(launcher->open_folder) { launcher->open_folder(ctx, folders, user_data, &err); if(err) { if(launcher->error) launcher->error(ctx, err, NULL, user_data); g_error_free(err); err = NULL; } } g_list_free(folders); } g_list_free_full(targets, (GDestroyNotify)fm_file_info_unref); return TRUE; }
/********************************************************************* * ... * * ********************************************************************/ gboolean fm_file_info_job_run (FmJob *fmjob) { FmFileInfoJob *job = (FmFileInfoJob*) fmjob; GError *err = NULL; GList *l; for (l = fm_list_peek_head_link (job->file_infos); !fm_job_is_cancelled (fmjob) && l; ) { FmFileInfo *file_info = (FmFileInfo*) l->data; GList *next = l->next; job->current = file_info->path; if (fm_path_is_native (file_info->path)) { char *path_str = fm_path_to_str (file_info->path); // FileInfo rework: new function for testing... // this one is not cancellable and doesn't handle errors... // if (!fm_file_info_job_get_info_for_native_file (FM_JOB (job), file_info, path_str, &err)) if (!fm_file_info_set_for_native_file (file_info, path_str)) { //~ FmJobErrorAction act = fm_job_emit_error (FM_JOB(job), err, FM_JOB_ERROR_MILD); //~ //~ g_error_free (err); //~ err = NULL; //~ //~ if (act == FM_JOB_RETRY) //~ continue; DEBUG ("fm_file_info_set_for_native_file: error reading %s\n", path_str); next = l->next; fm_list_delete_link (job->file_infos, l); // Also calls unref... } g_free (path_str); } else { GFile *gf; if (fm_path_is_virtual (file_info->path)) { // This is a xdg menu if (fm_path_is_xdg_menu (file_info->path)) { MenuCache *mc; MenuCacheDir *dir; char *path_str = fm_path_to_str (file_info->path); char *menu_name = path_str + 5, ch; char *dir_name; while (*menu_name == '/') ++menu_name; dir_name = menu_name; while (*dir_name && *dir_name != '/') ++dir_name; ch = *dir_name; *dir_name = '\0'; menu_name = g_strconcat (menu_name, ".menu", NULL); mc = menu_cache_lookup_sync (menu_name); g_free (menu_name); if (*dir_name && !(*dir_name == '/' && dir_name[1] == '\0')) { char *tmp = g_strconcat ("/", menu_cache_item_get_id (MENU_CACHE_ITEM(menu_cache_get_root_dir (mc))), dir_name, NULL); dir = menu_cache_get_dir_from_path (mc, tmp); g_free (tmp); } else { dir = menu_cache_get_root_dir (mc); } if (dir) { fm_file_info_set_from_menu_cache_item (file_info, (MenuCacheItem*) dir); } else { next = l->next; fm_list_delete_link (job->file_infos, l); // Also calls unref... } g_free (path_str); menu_cache_unref (mc); l = l->next; continue; } } gf = fm_path_to_gfile (file_info->path); if (!fm_file_info_job_get_info_for_gfile (FM_JOB (job), file_info, gf, &err)) { FmJobErrorAction act = fm_job_emit_error (FM_JOB (job), err, FM_JOB_ERROR_MILD); g_error_free (err); err = NULL; if (act == FM_JOB_RETRY) continue; next = l->next; fm_list_delete_link (job->file_infos, l); // Also calls unref... } g_object_unref (gf); } l = next; } return TRUE; }
// FIXME_pcm: this is too dirty. Need some refactor later. static void update_permissions (FmFilePropData *data) { FmFileInfo *file_info = (FmFileInfo*)fm_list_peek_head (data->files); GList *l; int sel; char *tmp; mode_t owner_perm = (file_info->mode & S_IRWXU); mode_t group_perm = (file_info->mode & S_IRWXG); mode_t other_perm = (file_info->mode & S_IRWXO); mode_t exec_perm = (file_info->mode & (S_IXUSR|S_IXGRP|S_IXOTH)); uid_t uid = file_info->uid; gid_t gid = file_info->gid; struct group *grp = NULL; struct passwd *pw = NULL; data->all_native = fm_path_is_native (fm_file_info_get_path (file_info)); data->has_dir = S_ISDIR (file_info->mode) != FALSE; for (l=fm_list_peek_head_link (data->files)->next; l; l=l->next) { FmFileInfo *file_info = (FmFileInfo*)l->data; if ( !fm_path_is_native (fm_file_info_get_path (file_info)) ) data->all_native = FALSE; if (S_ISDIR (file_info->mode)) data->has_dir = TRUE; if ( uid != file_info->uid ) uid = -1; if ( gid != file_info->gid ) gid = -1; if ( owner_perm != -1 && owner_perm != (file_info->mode & S_IRWXU) ) owner_perm = -1; if ( group_perm != -1 && group_perm != (file_info->mode & S_IRWXG) ) group_perm = -1; if ( other_perm != -1 && other_perm != (file_info->mode & S_IRWXO) ) other_perm = -1; if ( exec_perm != (file_info->mode & (S_IXUSR|S_IXGRP|S_IXOTH)) ) exec_perm = -1; } if ( data->all_native ) { if ( uid >= 0 ) { pw = getpwuid (uid); if (pw) gtk_entry_set_text (GTK_ENTRY (data->owner), pw->pw_name); } if ( gid >= 0 ) { grp = getgrgid (gid); if (grp) gtk_entry_set_text (GTK_ENTRY (data->group), grp->gr_name); } } if ( uid >=0 && !pw ) { tmp = g_strdup_printf ("%u", uid); gtk_entry_set_text (GTK_ENTRY (data->owner), tmp); g_free (tmp); } if ( gid >=0 && !grp ) { tmp = g_strdup_printf ("%u", gid); gtk_entry_set_text (GTK_ENTRY (data->group), tmp); g_free (tmp); } data->orig_owner = g_strdup (gtk_entry_get_text (GTK_ENTRY (data->owner))); data->orig_group = g_strdup (gtk_entry_get_text (GTK_ENTRY (data->group))); // on local filesystems, only root can do chown. if ( data->all_native && geteuid () != 0 ) { gtk_editable_set_editable (GTK_EDITABLE (data->owner), FALSE); gtk_editable_set_editable (GTK_EDITABLE (data->group), FALSE); } sel = NO_CHANGE; if (owner_perm != -1) { if ( (owner_perm & (S_IRUSR|S_IWUSR)) == (S_IRUSR|S_IWUSR) ) sel = READ_WRITE; else if ( (owner_perm & (S_IRUSR|S_IWUSR)) == S_IRUSR ) sel = READ_ONLY; else if ( (owner_perm & (S_IRUSR|S_IWUSR)) == S_IWUSR ) sel = WRITE_ONLY; else sel = NONE; } gtk_combo_box_set_active (GTK_COMBO_BOX (data->owner_perm), sel); data->owner_perm_sel = sel; sel = NO_CHANGE; if (group_perm != -1) { if ( (group_perm & (S_IRGRP|S_IWGRP)) == (S_IRGRP|S_IWGRP) ) sel = READ_WRITE; else if ( (group_perm & (S_IRGRP|S_IWGRP)) == S_IRGRP ) sel = READ_ONLY; else if ( (group_perm & (S_IRGRP|S_IWGRP)) == S_IWGRP ) sel = WRITE_ONLY; else sel = NONE; } gtk_combo_box_set_active (GTK_COMBO_BOX (data->group_perm), sel); data->group_perm_sel = sel; sel = NO_CHANGE; if (other_perm != -1) { if ( (other_perm & (S_IROTH|S_IWOTH)) == (S_IROTH|S_IWOTH) ) sel = READ_WRITE; else if ( (other_perm & (S_IROTH|S_IWOTH)) == S_IROTH ) sel = READ_ONLY; else if ( (other_perm & (S_IROTH|S_IWOTH)) == S_IWOTH ) sel = WRITE_ONLY; else sel = NONE; } gtk_combo_box_set_active (GTK_COMBO_BOX (data->other_perm), sel); data->other_perm_sel = sel; if (data->has_dir) gtk_widget_hide ( data->exec ); if ( exec_perm != -1 ) { gboolean xusr = (exec_perm & S_IXUSR) != 0; gboolean xgrp = (exec_perm & S_IXGRP) != 0; gboolean xoth = (exec_perm & S_IXOTH) != 0; if ( xusr == xgrp && xusr == xoth ) // executable { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->exec), xusr); data->exec_state = xusr; } else // inconsistent { gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (data->exec), TRUE); g_signal_connect (data->exec, "toggled", G_CALLBACK (on_exec_toggled), data); data->exec_state = -1; } } else // inconsistent { gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (data->exec), TRUE); g_signal_connect (data->exec, "toggled", G_CALLBACK (on_exec_toggled), data); data->exec_state = -1; } }