static void remove_items(gpointer data, guint action, GtkWidget *widget) { IconClass *iclass; if (menu_icon) { if (menu_icon->locked) { delayed_error(_("You must unlock '%s' before removing it"), menu_icon->item->leafname); return; } icon_set_selected(menu_icon, TRUE); } if (!icon_selection) { delayed_error( _("You must first select some items to remove")); return; } if (any_selected_item_is_locked()) { delayed_error(_("An item must be unlocked before it can be removed.")); return; } iclass = (IconClass *) G_OBJECT_GET_CLASS(G_OBJECT(icon_selection->data)); iclass->remove_items(); }
/* Load a file, open a directory or run an application. Or, if 'edit' is set: * edit a file, open an application, follow a symlink or mount a device. * * filer_window is the window to use for displaying a directory. * NULL will always use a new directory when needed. * src_window is the window to copy options from, or NULL. * * Returns TRUE on success. */ gboolean run_diritem(const guchar *full_path, DirItem *item, FilerWindow *filer_window, FilerWindow *src_window, gboolean edit) { if (item->flags & ITEM_FLAG_SYMLINK && edit) return follow_symlink(full_path, filer_window, src_window); switch (item->base_type) { case TYPE_DIRECTORY: if (item->flags & ITEM_FLAG_APPDIR && !edit) { run_app(full_path); return TRUE; } if (item->flags & ITEM_FLAG_MOUNT_POINT) { open_mountpoint(full_path, item, filer_window, src_window, edit); } else if (filer_window) filer_change_to(filer_window, full_path, NULL); else filer_opendir(full_path, src_window, NULL); return TRUE; case TYPE_FILE: if (EXECUTABLE_FILE(item) && !edit) { const char *argv[] = {NULL, NULL}; guchar *dir = filer_window ? filer_window->sym_path : NULL; if (item->mime_type == application_x_desktop) return run_desktop(full_path, NULL, dir); else argv[0] = full_path; return rox_spawn(dir, argv) != 0; } return open_file(full_path, edit ? text_plain : item->mime_type); case TYPE_ERROR: delayed_error(_("File doesn't exist, or I can't " "access it: %s"), full_path); return FALSE; default: delayed_error( _("I don't know how to open '%s'"), full_path); return FALSE; } }
static void drop_box_drag_data_received(GtkWidget *drop_box, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint drag_info, guint32 time) { GList *uris = NULL; guchar *path = NULL; gboolean success = FALSE; if (!selection_data->data) goto err; /* Timeout? */ uris = uri_list_to_glist(selection_data->data); if (g_list_length(uris) != 1) { delayed_error(_("Sorry, you need to drop exactly one file " "onto the drop area.")); goto err; } path = get_local_path((EscapedPath *) uris->data); if (!path) { delayed_error( _("Sorry, I can't use '%s' because it's not a local " "file."), (guchar *) uris->data); goto err; } if (!file_exists(path)) { delayed_error(_("Can't access '%s':\n%s"), path, g_strerror(errno)); goto err; } g_signal_emit_by_name(drop_box, "path_dropped", path); success = TRUE; err: if (path) g_free(path); if (uris) g_list_free(uris); gtk_drag_finish(context, success, FALSE, time); /* Failure */ }
static void open_dir_clicked(GtkWidget *button, DropBox *drop_box) { if (drop_box->path) open_to_show(drop_box->path); else delayed_error(_("I can't show you the currently set item, " "because nothing is currently set. Drag " "something onto me!")); }
/* Execute this program, passing all the URIs in the list as arguments. * URIs that are files on the local machine will be passed as simple * pathnames. The uri_list should be freed after this function returns. */ void run_with_files(const char *path, GList *uri_list) { const char **argv; int argc = 0, i; struct stat info; MIME_type *type; if (stat(path, &info)) { delayed_error(_("Program %s not found - deleted?"), path); return; } argv = g_malloc(sizeof(char *) * (g_list_length(uri_list) + 2)); if (S_ISDIR(info.st_mode)) argv[argc++] = make_path(path, "AppRun"); else argv[argc++] = path; while (uri_list) { const EscapedPath *uri = uri_list->data; char *local; local = get_local_path(uri); if (local) argv[argc++] = local; else argv[argc++] = unescape_uri(uri); uri_list = uri_list->next; } argv[argc++] = NULL; type = type_from_path(argv[0]); if (type && type == application_x_desktop) { run_desktop(argv[0], argv + 1, home_dir); } else { rox_spawn(home_dir, argv); } for (i = 1; i < argc; i++) g_free((gchar *) argv[i]); g_free(argv); }
/* Splits args into an argument vector, and runs the program. Must be * executable. */ void run_with_args(const char *path, DirItem *item, const char *args) { GError *error = NULL; gchar **argv = NULL; int n_args = 0; if (item->base_type != TYPE_DIRECTORY && item->base_type != TYPE_FILE) { delayed_error("Arguments (%s) given for non-executable item %s", args, path); return; } if (!g_shell_parse_argv(args, &n_args, &argv, &error)) { delayed_error("Failed to parse argument string '%s':\n%s", args, error->message); g_error_free(error); return; } g_return_if_fail(argv != NULL); g_return_if_fail(error == NULL); argv = g_realloc(argv, (n_args + 2) * sizeof(gchar *)); memmove(argv + 1, argv, (n_args + 1) * sizeof(gchar *)); if (item->base_type == TYPE_DIRECTORY) argv[0] = g_strconcat(path, "/AppRun", NULL); else argv[0] = g_strdup(path); rox_spawn(home_dir, (const gchar **) argv); g_strfreev(argv); }
static void get_shortcut(GtkWidget *button, GtkWidget *label) { GtkWidget *popup, *frame, *msg; Window xid; Display *dpy = GDK_DISPLAY(); popup = gtk_window_new(GTK_WINDOW_POPUP); gtk_window_set_position(GTK_WINDOW(popup), GTK_WIN_POS_CENTER); frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(popup), frame); msg = gtk_label_new(_("Press the desired shortcut (eg, Control+F1)")); gtk_misc_set_padding(GTK_MISC(msg), 20, 20); gtk_container_add(GTK_CONTAINER(frame), msg); gtk_window_set_modal(GTK_WINDOW(popup), TRUE); gtk_widget_add_events(popup, GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK); g_signal_connect(popup, "destroy", G_CALLBACK(may_set_shortcut), label); gtk_widget_show_all(popup); gdk_window_add_filter(popup->window, filter_get_key, popup); xid = gdk_x11_drawable_get_xid(popup->window); if (XGrabKeyboard(dpy, xid, False, GrabModeAsync, GrabModeAsync, gtk_get_current_event_time()) != Success) { delayed_error(_("Failed to get keyboard grab!")); gtk_widget_destroy(popup); } if (XGrabPointer(dpy, xid, False, ButtonPressMask, GrabModeAsync, GrabModeAsync, xid, None, gtk_get_current_event_time()) != Success) { g_warning("Failed to get mouse grab"); } }
static void file_op(gpointer data, guint action, GtkWidget *widget) { if (!menu_icon) { delayed_error(_("You must open the menu over an item")); return; } switch (action) { case ACTION_SHIFT: run_diritem(menu_icon->path, menu_icon->item, NULL, NULL, TRUE); break; case ACTION_EDIT: show_rename_box(menu_icon); break; case ACTION_LOCATION: open_to_show(menu_icon->path); break; case ACTION_PROPERTIES: infobox_new(menu_icon->path); break; case ACTION_RUN_ACTION: if (can_set_run_action(menu_icon->item)) type_set_handler_dialog( menu_icon->item->mime_type); else report_error( _("You can only set the run action for a " "regular file")); break; case ACTION_SET_ICON: icon_set_handler_dialog(menu_icon->item, menu_icon->path); break; } }
/* Read in this .gmo format file; all translations found override * any existing translations for future calls to rox_gettext(). */ void rox_add_translations(char *path) { guint32 magic; char *data, *from_base, *to_base; long size; gboolean swap; /* TRUE => reverse byte-order of ints */ int n, n_total; #ifdef GTK2 char *charset = NULL; #endif if (load_file(path, &data, &size) == FALSE) goto out; if (size < 20) { delayed_error(_("Invalid .gmo translation file " "(too short): %s"), path); goto out; } magic = *((guint *) data); if (magic == 0x950412de) swap = FALSE; else if (magic == 0xde120495) swap = TRUE; else { delayed_error(_("Invalid .gmo translation file " "(GNU magic number not found): %s"), path); goto out; } if (WORD(data + 4) != 0) g_warning("rox_add_translations: expected format revision 0"); if (!translate) { #ifdef GTK2 translate = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); #else translate = g_hash_table_new(g_str_hash, g_str_equal); #endif } n_total = WORD(data + 8); from_base = data + WORD(data + 12); to_base = data + WORD(data + 16); #ifdef GTK2 /* Find the charset used, so we can convert to UTF-8 */ for (n = 0; n < n_total; n++) { char *from = data + WORD(from_base + (n << 3) + 4); char *to_raw = data + WORD(to_base + (n << 3) + 4); if (*from) continue; charset = strstr(to_raw, "charset="); if (charset) { char *tmp; charset += 8; tmp = strchr(charset, '\n'); if (tmp) charset = g_strndup(charset, tmp - charset); else charset = g_strdup(charset); } break; } if (!charset) { g_warning("Missing charset=... in translation!"); charset = g_strdup("ISO8859-1"); } #endif for (n = 0; n < n_total; n++) { char *from = data + WORD(from_base + (n << 3) + 4); char *to_raw = data + WORD(to_base + (n << 3) + 4); #ifdef GTK2 char *to; to = g_convert_with_fallback(to_raw, -1, "UTF-8", charset, "#", NULL, NULL, NULL); if (!to) to = g_strdup(to_raw); g_hash_table_insert(translate, g_strdup(from), to); #else g_hash_table_insert(translate, from, to_raw); #endif } out: ; /* (some compilers complain otherwise) */ #ifdef GTK2 g_free(data); g_free(charset); #endif }
/* Run the program as '<path> -', piping the data to it via stdin. * You can g_free() the data as soon as this returns. */ void run_with_data(const char *path, gpointer data, gulong length) { const char *argv[] = {NULL, "-", NULL}; struct stat info; int fds[2]; PipedData *pd; if (stat(path, &info)) { delayed_error(_("Program %s not found - deleted?"), path); return; } if (S_ISDIR(info.st_mode)) argv[0] = make_path(path, "AppRun"); else argv[0] = path; if (pipe(fds)) { delayed_error("pipe: %s", g_strerror(errno)); return; } close_on_exec(fds[1], TRUE); close_on_exec(fds[0], TRUE); switch (fork()) { case -1: delayed_error("fork: %s", g_strerror(errno)); close(fds[1]); break; case 0: /* We are the child */ chdir(home_dir); if (dup2(fds[0], 0) == -1) g_warning("dup2() failed: %s\n", g_strerror(errno)); else { close_on_exec(0, FALSE); if (execv(argv[0], (char **) argv)) g_warning("execv(%s) failed: %s\n", argv[0], g_strerror(errno)); } _exit(1); default: /* We are the parent */ set_blocking(fds[1], FALSE); pd = g_new(PipedData, 1); pd->data = g_malloc(length); memcpy(pd->data, data, length); pd->length = length; pd->sent = 0; pd->tag = gdk_input_add_full(fds[1], GDK_INPUT_WRITE, write_data, pd, NULL); break; } close(fds[0]); }
/* Load image 'path' in the background and insert into pixmap_cache. * Call callback(data, path) when done (path is NULL => error). * If the image is already uptodate, or being created already, calls the * callback right away. */ void pixmap_background_thumb(const gchar *path, GFunc callback, gpointer data) { gboolean found = FALSE; MaskedPixmap* image = g_fscache_lookup_full(pixmap_cache, path, FSCACHE_LOOKUP_ONLY_NEW, &found); if (found) { dbg(0, "found"); // Thumbnail is known, or being created if (image) g_object_unref(image); callback(data, NULL); return; } dbg(0, "FIXME not found"); #if 0 pid_t child; ChildThumbnail *info; g_return_if_fail(image == NULL); GdkPixbuf* pixbuf = get_thumbnail_for(path); if (!pixbuf) { struct stat info1, info2; char *dir; dir = g_path_get_dirname(path); // If the image itself is in ~/.thumbnails, load it now (ie, don't create thumbnails for thumbnails!). if (stat(dir, &info1) != 0) { callback(data, NULL); g_free(dir); return; } g_free(dir); if (stat(make_path(home_dir, ".thumbnails/normal"), &info2) == 0 && info1.st_dev == info2.st_dev && info1.st_ino == info2.st_ino) { pixbuf = rox_pixbuf_new_from_file_at_scale(path, PIXMAP_THUMB_SIZE, PIXMAP_THUMB_SIZE, TRUE, NULL); if (!pixbuf) { g_fscache_insert(pixmap_cache, path, NULL, TRUE); callback(data, NULL); return; } } } if (pixbuf) { MaskedPixmap *image; image = masked_pixmap_new(pixbuf); gdk_pixbuf_unref(pixbuf); g_fscache_insert(pixmap_cache, path, image, TRUE); callback(data, (gchar *) path); g_object_unref(G_OBJECT(image)); return; } MIME_type* type = type_from_path(path); if (!type) type = text_plain; // Add an entry, set to NULL, so no-one else tries to load this image. g_fscache_insert(pixmap_cache, path, NULL, TRUE); gchar* thumb_prog = thumbnail_program(type); // Only attempt to load 'images' types ourselves if (thumb_prog == NULL && strcmp(type->media_type, "image") != 0) { callback(data, NULL); return; // Don't know how to handle this type } child = fork(); if (child == -1) { g_free(thumb_prog); delayed_error("fork(): %s", g_strerror(errno)); callback(data, NULL); return; } if (child == 0) { // We are the child process. (We are sloppy with freeing memory, but since we go away very quickly, that's ok.) if (thumb_prog) { DirItem *item; item = diritem_new(g_basename(thumb_prog)); diritem_restat(thumb_prog, item, NULL); if (item->flags & ITEM_FLAG_APPDIR) thumb_prog = g_strconcat(thumb_prog, "/AppRun", NULL); execl(thumb_prog, thumb_prog, path, thumbnail_path(path), g_strdup_printf("%d", PIXMAP_THUMB_SIZE), NULL); _exit(1); } child_create_thumbnail(path); _exit(0); } g_free(thumb_prog); info = g_new(ChildThumbnail, 1); info->path = g_strdup(path); info->callback = callback; info->data = data; on_child_death(child, (CallbackFn) thumbnail_child_done, info); #endif }