r156: Fixed some compiler warnings for systems with signed char types.
[rox-filer/ma.git] / ROX-Filer / src / action.c
blobf583abc7f37aad8012eca12f757671beec1ebd2b
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 1999, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* action.c - code for handling the filer action windows.
23 * These routines generally fork() and talk to us via pipes.
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <signal.h>
35 #include <dirent.h>
37 #include "action.h"
38 #include "string.h"
39 #include "support.h"
40 #include "gui_support.h"
41 #include "filer.h"
42 #include "main.h"
44 static GdkColor red = {0, 0xffff, 0, 0};
46 typedef struct _GUIside GUIside;
47 typedef void ActionChild(gpointer data);
48 typedef gboolean ForDirCB(char *path, char *dest_path);
50 struct _GUIside
52 int from_child; /* File descriptor */
53 FILE *to_child;
54 int input_tag; /* gdk_input_add() */
55 GtkWidget *log, *window, *actions, *dir;
56 int child; /* Process ID */
57 int errors;
58 gboolean show_info; /* For Disk Usage */
60 char *next_dir; /* NULL => no timer active */
61 gint next_timer;
64 /* These don't need to be in a structure because we fork() before
65 * using them again.
67 static int from_parent = 0;
68 static FILE *to_parent = NULL;
69 static gboolean quiet = FALSE;
70 static GString *message = NULL;
71 static char *action_dest = NULL;
72 static gboolean (*action_do_func)(char *source, char *dest);
73 static size_t size_tally; /* For Disk Usage */
75 /* Static prototypes */
76 static gboolean send();
77 static gboolean send_error();
78 static gboolean send_dir(char *dir);
79 static gboolean read_exact(int source, char *buffer, ssize_t len);
81 static gboolean display_dir(gpointer data)
83 GUIside *gui_side = (GUIside *) data;
85 gtk_label_set_text(GTK_LABEL(gui_side->dir), gui_side->next_dir + 1);
86 g_free(gui_side->next_dir);
87 gui_side->next_dir = NULL;
89 return FALSE;
92 /* Called when the child sends us a message */
93 static void message_from_child(gpointer data,
94 gint source,
95 GdkInputCondition condition)
97 char buf[5];
98 GUIside *gui_side = (GUIside *) data;
99 GtkWidget *log = gui_side->log;
101 if (read_exact(source, buf, 4))
103 ssize_t message_len;
104 char *buffer;
106 buf[4] = '\0';
107 message_len = strtol(buf, NULL, 16);
108 buffer = g_malloc(message_len + 1);
109 if (message_len > 0 && read_exact(source, buffer, message_len))
111 buffer[message_len] = '\0';
112 if (*buffer == '?')
113 gtk_widget_set_sensitive(gui_side->actions,
114 TRUE);
115 else if (*buffer == '+')
117 refresh_dirs(buffer + 1);
118 g_free(buffer);
119 return;
121 else if (*buffer == '/')
123 if (gui_side->next_dir)
124 g_free(gui_side->next_dir);
125 else
126 gui_side->next_timer =
127 gtk_timeout_add(500,
128 display_dir,
129 gui_side);
130 gui_side->next_dir = buffer;
131 return;
133 else if (*buffer == '!')
134 gui_side->errors++;
136 gtk_text_insert(GTK_TEXT(log),
137 NULL,
138 *buffer == '!' ? &red : NULL,
139 NULL,
140 buffer + 1, message_len - 1);
141 g_free(buffer);
142 return;
144 g_print("Child died in the middle of a message.\n");
147 /* The child is dead */
148 gui_side->child = 0;
150 fclose(gui_side->to_child);
151 close(gui_side->from_child);
152 gdk_input_remove(gui_side->input_tag);
154 if (gui_side->errors)
156 GString *report;
157 report = g_string_new(NULL);
158 g_string_sprintf(report, "There %s %d error%s.\n",
159 gui_side->errors == 1 ? "was" : "were",
160 gui_side->errors,
161 gui_side->errors == 1 ? "" : "s");
162 gtk_text_insert(GTK_TEXT(log), NULL, &red, NULL,
163 report->str, report->len);
165 g_string_free(report, TRUE);
167 else if (gui_side->show_info == FALSE)
168 gtk_widget_destroy(gui_side->window);
171 /* Scans src_dir, updating dest_path whenever cb returns TRUE */
172 static void for_dir_contents(ForDirCB *cb, char *src_dir, char *dest_path)
174 DIR *d;
175 struct dirent *ent;
176 GSList *list = NULL, *next;
178 d = opendir(src_dir);
179 if (!d)
181 send_error();
182 return;
185 send_dir(src_dir);
187 while ((ent = readdir(d)))
189 if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0'
190 || (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
191 continue;
192 list = g_slist_append(list, g_strdup(make_path(src_dir,
193 ent->d_name)->str));
195 closedir(d);
197 if (!list)
198 return;
200 next = list;
202 while (next)
204 if (cb((char *) next->data, dest_path))
206 g_string_sprintf(message, "+%s", dest_path);
207 send();
210 g_free(next->data);
211 next = next->next;
213 g_slist_free(list);
214 return;
217 /* Read this many bytes into the buffer. TRUE on success. */
218 static gboolean read_exact(int source, char *buffer, ssize_t len)
220 while (len > 0)
222 ssize_t got;
223 got = read(source, buffer, len);
224 if (got < 1)
225 return FALSE;
226 len -= got;
227 buffer += got;
229 return TRUE;
232 /* Send 'message' to our parent process. TRUE on success. */
233 static gboolean send()
235 char len_buffer[5];
236 ssize_t len;
238 g_return_val_if_fail(message->len < 0xffff, FALSE);
240 sprintf(len_buffer, "%04x", message->len);
241 fwrite(len_buffer, 1, 4, to_parent);
242 len = fwrite(message->str, 1, message->len, to_parent);
243 fflush(to_parent);
244 return len == message->len;
247 /* Set the directory indicator at the top of the window */
248 static gboolean send_dir(char *dir)
250 g_string_sprintf(message, "/%s", dir);
251 return send();
254 static gboolean send_error()
256 g_string_sprintf(message, "!ERROR: %s\n", g_strerror(errno));
257 return send();
260 static void button_reply(GtkWidget *button, GUIside *gui_side)
262 char *text;
264 text = gtk_object_get_data(GTK_OBJECT(button), "send-code");
265 g_return_if_fail(text != NULL);
266 fputc(*text, gui_side->to_child);
267 fflush(gui_side->to_child);
269 gtk_widget_set_sensitive(gui_side->actions, FALSE);
272 /* Get one char from fd. Quit on error. */
273 static char reply(int fd)
275 ssize_t len;
276 char retval;
278 len = read(fd, &retval, 1);
279 if (len == 1)
280 return retval;
282 fprintf(stderr, "read() error: %s\n", g_strerror(errno));
283 _exit(1); /* Parent died? */
284 return '!';
287 static void destroy_action_window(GtkWidget *widget, gpointer data)
289 GUIside *gui_side = (GUIside *) data;
291 if (gui_side->child)
293 kill(gui_side->child, SIGTERM);
294 fclose(gui_side->to_child);
295 close(gui_side->from_child);
296 gdk_input_remove(gui_side->input_tag);
299 if (gui_side->next_dir)
301 gtk_timeout_remove(gui_side->next_timer);
302 g_free(gui_side->next_dir);
304 g_free(gui_side);
306 if (--number_of_windows < 1)
307 gtk_main_quit();
310 /* Create two pipes, fork() a child and return a pointer to a GUIside struct
311 * (NULL on failure). The child calls func().
313 static GUIside *start_action(gpointer data, ActionChild *func)
315 int filedes[4]; /* 0 and 2 are for reading */
316 GUIside *gui_side;
317 int child;
318 GtkWidget *vbox, *button, *control, *hbox, *scrollbar;
320 if (pipe(filedes))
322 report_error("ROX-Filer", g_strerror(errno));
323 return NULL;
326 if (pipe(filedes + 2))
328 close(filedes[0]);
329 close(filedes[1]);
330 report_error("ROX-Filer", g_strerror(errno));
331 return NULL;
334 child = fork();
335 switch (child)
337 case -1:
338 report_error("ROX-Filer", g_strerror(errno));
339 return NULL;
340 case 0:
341 /* We are the child */
342 message = g_string_new(NULL);
343 close(filedes[0]);
344 close(filedes[3]);
345 to_parent = fdopen(filedes[1], "wb");
346 from_parent = filedes[2];
347 func(data);
348 _exit(0);
351 /* We are the parent */
352 close(filedes[1]);
353 close(filedes[2]);
354 gui_side = g_malloc(sizeof(GUIside));
355 gui_side->from_child = filedes[0];
356 gui_side->to_child = fdopen(filedes[3], "wb");
357 gui_side->log = NULL;
358 gui_side->child = child;
359 gui_side->errors = 0;
360 gui_side->show_info = FALSE;
362 gui_side->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
363 gtk_window_set_default_size(GTK_WINDOW(gui_side->window), 500, 100);
364 gtk_signal_connect(GTK_OBJECT(gui_side->window), "destroy",
365 GTK_SIGNAL_FUNC(destroy_action_window), gui_side);
367 vbox = gtk_vbox_new(FALSE, 4);
368 gtk_container_add(GTK_CONTAINER(gui_side->window), vbox);
370 gui_side->dir = gtk_label_new("<dir>");
371 gui_side->next_dir = NULL;
372 gtk_misc_set_alignment(GTK_MISC(gui_side->dir), 0.5, 0.5);
373 gtk_box_pack_start(GTK_BOX(vbox), gui_side->dir, FALSE, TRUE, 0);
375 hbox = gtk_hbox_new(FALSE, 0);
376 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
378 gui_side->log = gtk_text_new(NULL, NULL);
379 gtk_box_pack_start(GTK_BOX(hbox), gui_side->log, TRUE, TRUE, 0);
380 scrollbar = gtk_vscrollbar_new(GTK_TEXT(gui_side->log)->vadj);
381 gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, TRUE, 0);
383 gui_side->actions = gtk_hbox_new(TRUE, 4);
384 gtk_box_pack_start(GTK_BOX(vbox), gui_side->actions, FALSE, TRUE, 0);
386 button = gtk_button_new_with_label("Always");
387 gtk_object_set_data(GTK_OBJECT(button), "send-code", "A");
388 gtk_box_pack_start(GTK_BOX(gui_side->actions), button, TRUE, TRUE, 0);
389 gtk_signal_connect(GTK_OBJECT(button), "clicked",
390 button_reply, gui_side);
391 button = gtk_button_new_with_label("Yes");
392 gtk_object_set_data(GTK_OBJECT(button), "send-code", "Y");
393 gtk_box_pack_start(GTK_BOX(gui_side->actions), button, TRUE, TRUE, 0);
394 gtk_signal_connect(GTK_OBJECT(button), "clicked",
395 button_reply, gui_side);
396 button = gtk_button_new_with_label("No");
397 gtk_object_set_data(GTK_OBJECT(button), "send-code", "N");
398 gtk_box_pack_start(GTK_BOX(gui_side->actions), button, TRUE, TRUE, 0);
399 gtk_signal_connect(GTK_OBJECT(button), "clicked",
400 button_reply, gui_side);
401 gtk_widget_set_sensitive(gui_side->actions, FALSE);
403 control = gtk_hbox_new(TRUE, 4);
404 gtk_box_pack_start(GTK_BOX(vbox), control, FALSE, TRUE, 0);
406 button = gtk_button_new_with_label("Suspend");
407 gtk_box_pack_start(GTK_BOX(control), button, TRUE, TRUE, 0);
409 button = gtk_button_new_with_label("Resume");
410 gtk_widget_set_sensitive(button, FALSE);
411 gtk_box_pack_start(GTK_BOX(control), button, TRUE, TRUE, 0);
413 button = gtk_button_new_with_label("Abort");
414 gtk_box_pack_start(GTK_BOX(control), button, TRUE, TRUE, 0);
415 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
416 gtk_widget_destroy, GTK_OBJECT(gui_side->window));
418 gui_side->input_tag = gdk_input_add(gui_side->from_child,
419 GDK_INPUT_READ,
420 message_from_child,
421 gui_side);
423 return gui_side;
426 /* ACTIONS ON ONE ITEM */
428 /* These may call themselves recursively, or ask questions, etc.
429 * TRUE iff the directory containing dest_path needs to be rescanned.
432 /* dest_path is the dir containing src_path.
433 * Updates the global size_tally.
435 static gboolean do_usage(char *src_path, char *dest_path)
437 struct stat info;
439 if (lstat(src_path, &info))
441 g_string_sprintf(message, "'%s:\n", src_path);
442 send();
443 send_error();
444 return FALSE;
447 if (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))
448 size_tally += info.st_size;
449 else if (S_ISDIR(info.st_mode))
451 char *safe_path;
452 safe_path = g_strdup(src_path);
453 for_dir_contents(do_usage, safe_path, safe_path);
454 g_free(safe_path);
457 return FALSE;
460 /* dest_path is the dir containing src_path */
461 static gboolean do_delete(char *src_path, char *dest_path)
463 struct stat info;
464 gboolean write_prot;
465 char rep;
467 if (lstat(src_path, &info))
469 send_error();
470 return FALSE;
473 write_prot = S_ISLNK(info.st_mode) ? FALSE
474 : access(src_path, W_OK) != 0;
475 if (quiet == 0 || write_prot)
477 g_string_sprintf(message, "?Delete %s'%s'?\n",
478 write_prot ? "WRITE-PROTECTED " : " ",
479 src_path);
480 send();
481 rep = reply(from_parent);
482 if (rep == 'A')
483 quiet = TRUE;
484 else if (rep != 'Y')
485 return FALSE;
487 if (S_ISDIR(info.st_mode))
489 char *safe_path;
490 safe_path = g_strdup(src_path);
491 for_dir_contents(do_delete, safe_path, safe_path);
492 if (rmdir(safe_path))
494 g_free(safe_path);
495 send_error();
496 return FALSE;
498 g_string_assign(message, "'Directory deleted\n");
499 send();
500 g_free(safe_path);
502 else if (unlink(src_path) == 0)
504 g_string_sprintf(message, "'Deleted '%s'\n", src_path);
505 send();
507 else
509 send_error();
510 return FALSE;
513 return TRUE;
516 static gboolean do_copy(char *path, char *dest)
518 char *dest_path;
519 char *leaf;
520 struct stat info;
521 gboolean retval = TRUE;
523 leaf = strrchr(path, '/');
524 if (!leaf)
525 leaf = path; /* Error? */
526 else
527 leaf++;
529 dest_path = make_path(dest, leaf)->str;
531 g_string_sprintf(message, "'Copying %s as %s\n", path, dest_path);
532 send();
534 if (access(dest_path, F_OK) == 0)
536 char rep;
537 g_string_sprintf(message, "?'%s' already exists - overwrite?\n",
538 dest_path);
539 send();
541 rep = reply(from_parent);
542 if (rep == 'A')
543 quiet = TRUE;
544 else if (rep != 'Y')
545 return FALSE;
548 if (lstat(path, &info))
550 send_error();
551 return FALSE;
554 if (S_ISDIR(info.st_mode))
556 char *safe_path, *safe_dest;
557 struct stat dest_info;
558 gboolean exists;
560 /* (we will do the update ourselves now, rather than
561 * afterwards)
563 retval = FALSE;
565 safe_path = g_strdup(path);
566 safe_dest = g_strdup(dest_path);
568 exists = !lstat(dest_path, &dest_info);
570 if (exists && !S_ISDIR(dest_info.st_mode))
572 g_string_sprintf(message,
573 "!ERROR: Destination already exists, "
574 "but is not a directory\n");
576 else if (exists == FALSE && mkdir(dest_path, info.st_mode))
577 send_error();
578 else
580 if (!exists)
582 /* (just been created then) */
583 g_string_sprintf(message, "+%s", dest);
584 send();
587 for_dir_contents(do_copy, safe_path, safe_dest);
588 /* Note: dest_path now invalid... */
591 g_free(safe_path);
592 g_free(safe_dest);
594 else
596 g_string_sprintf(message, "cp -af %s %s", path, dest_path);
597 if (system(message->str))
599 g_string_sprintf(message, "!ERROR: %s\n",
600 "Copy failed\n");
601 send();
602 retval = FALSE;
606 return retval;
609 static gboolean do_move(char *path, char *dest)
611 char *dest_path;
612 char *leaf;
613 gboolean retval = TRUE;
615 leaf = strrchr(path, '/');
616 if (!leaf)
617 leaf = path; /* Error? */
618 else
619 leaf++;
621 dest_path = make_path(dest, leaf)->str;
623 g_string_sprintf(message, "'Moving %s into %s...\n", path, dest);
624 send();
626 if (access(dest_path, F_OK) == 0)
628 char rep;
629 struct stat info;
631 g_string_sprintf(message, "?'%s' already exists - overwrite?\n",
632 dest_path);
633 send();
635 rep = reply(from_parent);
636 if (rep == 'A')
637 quiet = TRUE;
638 else if (rep != 'Y')
639 return FALSE;
641 if (lstat(dest_path, &info))
643 send_error();
644 return FALSE;
647 if (S_ISDIR(info.st_mode))
649 char *safe_path, *safe_dest;
651 safe_path = g_strdup(path);
652 safe_dest = g_strdup(dest_path);
653 for_dir_contents(do_move, safe_path, safe_dest);
654 g_free(safe_dest);
655 if (rmdir(safe_path))
657 g_free(safe_path);
658 send_error();
659 return FALSE;
661 g_string_assign(message, "'Directory deleted\n");
662 send();
663 g_free(safe_path);
664 g_string_sprintf(message, "+%s", path);
665 g_string_truncate(message, leaf - path);
666 send();
667 return TRUE;
671 g_string_sprintf(message, "mv -f %s %s", path, dest);
672 if (system(message->str) == 0)
674 g_string_sprintf(message, "+%s", path);
675 g_string_truncate(message, leaf - path);
676 send();
678 else
680 g_string_sprintf(message, "!ERROR: Failed to move %s as %s\n",
681 path, dest_path);
682 retval = FALSE;
684 send();
686 return retval;
689 static gboolean do_link(char *path, char *dest)
691 char *dest_path;
692 char *leaf;
694 leaf = strrchr(path, '/');
695 if (!leaf)
696 leaf = path; /* Error? */
697 else
698 leaf++;
700 dest_path = make_path(dest, leaf)->str;
702 if (symlink(path, dest_path))
704 send_error();
705 return FALSE;
707 else
709 g_string_sprintf(message, "'Symlinked %s as %s\n",
710 path, dest_path);
711 send();
714 return TRUE;
717 /* CHILD MAIN LOOPS */
719 /* After forking, the child calls one of these functions */
721 static void usage_cb(gpointer data)
723 FilerWindow *filer_window = (FilerWindow *) data;
724 Collection *collection = filer_window->collection;
725 DirItem *item;
726 int left = collection->number_selected;
727 int i = -1;
728 off_t total_size = 0;
730 send_dir(filer_window->path);
732 while (left > 0)
734 i++;
735 if (!collection->items[i].selected)
736 continue;
737 item = (DirItem *) collection->items[i].data;
738 size_tally = 0;
739 do_usage(make_path(filer_window->path,
740 item->leafname)->str,
741 filer_window->path);
742 g_string_sprintf(message, "'%s: %s\n",
743 item->leafname,
744 format_size((unsigned long) size_tally));
745 send();
746 total_size += size_tally;
747 left--;
750 g_string_sprintf(message, "'\nTotal: %s\n",
751 format_size((unsigned long) total_size));
752 send();
755 #ifdef DO_MOUNT_POINTS
756 static void mount_cb(gpointer data)
758 FilerWindow *filer_window = (FilerWindow *) data;
759 Collection *collection = filer_window->collection;
760 DirItem *item;
761 int i;
762 char *command;
763 gboolean mount_points = FALSE;
765 send_dir(filer_window->path);
767 for (i = 0; i < collection->number_of_items; i++)
769 if (!collection->items[i].selected)
770 continue;
771 item = (DirItem *) collection->items[i].data;
772 if (!(item->flags & ITEM_FLAG_MOUNT_POINT))
773 continue;
774 mount_points = TRUE;
776 command = g_strdup_printf("%smount %s",
777 item->flags & ITEM_FLAG_MOUNTED ? "u" : "",
778 make_path(filer_window->path, item->leafname)->str);
779 g_string_sprintf(message, "'> %s\n", command);
780 send();
781 if (system(command) == 0)
783 g_string_sprintf(message, "+%s", filer_window->path);
784 send();
786 else
788 g_string_sprintf(message, "!Operation failed.\n");
789 send();
791 g_free(command);
794 if (!mount_points)
796 g_string_sprintf(message, "!No mount points selected!\n");
797 send();
800 g_string_sprintf(message, "'\nDone\n");
801 send();
803 #endif
805 static void delete_cb(gpointer data)
807 FilerWindow *filer_window = (FilerWindow *) data;
808 Collection *collection = filer_window->collection;
809 DirItem *item;
810 int left = collection->number_selected;
811 int i = -1;
813 send_dir(filer_window->path);
815 while (left > 0)
817 i++;
818 if (!collection->items[i].selected)
819 continue;
820 item = (DirItem *) collection->items[i].data;
821 if (do_delete(make_path(filer_window->path,
822 item->leafname)->str,
823 filer_window->path))
825 g_string_sprintf(message, "+%s", filer_window->path);
826 send();
828 left--;
831 g_string_sprintf(message, "'\nDone\n");
832 send();
835 static void list_cb(gpointer data)
837 GSList *paths = (GSList *) data;
839 while (paths)
841 send_dir((char *) paths->data);
843 if (action_do_func((char *) paths->data, action_dest))
845 g_string_sprintf(message, "+%s", action_dest);
846 send();
849 paths = paths->next;
852 g_string_sprintf(message, "'\nDone\n");
853 send();
856 /* EXTERNAL INTERFACE */
858 /* Count disk space used by selected items */
859 void action_usage(FilerWindow *filer_window)
861 GUIside *gui_side;
862 Collection *collection;
864 collection = filer_window->collection;
866 if (collection->number_selected < 1)
868 report_error("ROX-Filer", "You need to select some items "
869 "to count");
870 return;
873 gui_side = start_action(filer_window, usage_cb);
874 if (!gui_side)
875 return;
877 gui_side->show_info = TRUE;
879 gtk_window_set_title(GTK_WINDOW(gui_side->window), "Disk Usage");
880 number_of_windows++;
881 gtk_widget_show_all(gui_side->window);
884 /* Mount/unmount all selected mount points */
885 void action_mount(FilerWindow *filer_window)
887 #ifdef DO_MOUNT_POINTS
888 GUIside *gui_side;
889 Collection *collection;
891 collection = filer_window->collection;
893 if (collection->number_selected < 1)
895 report_error("ROX-Filer", "You need to select some items "
896 "to mount or unmount");
897 return;
900 gui_side = start_action(filer_window, mount_cb);
901 if (!gui_side)
902 return;
904 gtk_window_set_title(GTK_WINDOW(gui_side->window), "Mount / Unmount");
905 number_of_windows++;
906 gtk_widget_show_all(gui_side->window);
907 #else
908 report_error("ROX-Filer",
909 "ROX-Filer does not yet support mount points on your "
910 "system. Sorry.");
911 #endif /* DO_MOUNT_POINTS */
914 /* Deletes all selected items in the window */
915 void action_delete(FilerWindow *filer_window)
917 GUIside *gui_side;
918 Collection *collection;
920 collection = filer_window->collection;
922 if (collection->number_selected < 1)
924 report_error("ROX-Filer", "You need to select some items "
925 "to delete");
926 return;
929 gui_side = start_action(filer_window, delete_cb);
930 if (!gui_side)
931 return;
933 gtk_window_set_title(GTK_WINDOW(gui_side->window), "Delete");
934 number_of_windows++;
935 gtk_widget_show_all(gui_side->window);
938 void action_copy(GSList *paths, char *dest)
940 GUIside *gui_side;
942 action_dest = dest;
943 action_do_func = do_copy;
944 gui_side = start_action(paths, list_cb);
945 if (!gui_side)
946 return;
948 gtk_window_set_title(GTK_WINDOW(gui_side->window), "Copy");
949 number_of_windows++;
950 gtk_widget_show_all(gui_side->window);
953 void action_move(GSList *paths, char *dest)
955 GUIside *gui_side;
957 action_dest = dest;
958 action_do_func = do_move;
959 gui_side = start_action(paths, list_cb);
960 if (!gui_side)
961 return;
963 gtk_window_set_title(GTK_WINDOW(gui_side->window), "Move");
964 number_of_windows++;
965 gtk_widget_show_all(gui_side->window);
968 void action_link(GSList *paths, char *dest)
970 GUIside *gui_side;
972 action_dest = dest;
973 action_do_func = do_link;
974 gui_side = start_action(paths, list_cb);
975 if (!gui_side)
976 return;
978 gtk_window_set_title(GTK_WINDOW(gui_side->window), "Link");
979 number_of_windows++;
980 gtk_widget_show_all(gui_side->window);