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)
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
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.
31 #include <sys/param.h>
34 #include <sys/types.h>
43 #include "gui_support.h"
49 static GtkWidget
*create_options();
50 static void update_options();
51 static void set_options();
52 static void save_options();
53 static char *action_auto_quiet(char *data
);
55 static OptionsSection options
=
57 "Action window options",
64 static gboolean o_auto_copy
= TRUE
;
65 static gboolean o_auto_move
= TRUE
;
66 static gboolean o_auto_link
= TRUE
;
67 static gboolean o_auto_delete
= FALSE
;
68 static gboolean o_auto_mount
= TRUE
;
70 static GtkWidget
*w_auto_copy
= NULL
;
71 static GtkWidget
*w_auto_move
= NULL
;
72 static GtkWidget
*w_auto_link
= NULL
;
73 static GtkWidget
*w_auto_delete
= NULL
;
74 static GtkWidget
*w_auto_mount
= NULL
;
76 static GdkColor red
= {0, 0xffff, 0, 0};
78 /* Parent->Child messages are one character each:
80 * Q/Y/N Quiet/Yes/No button clicked
81 * F Force deletion of non-writeable items
84 #define SENSITIVE_YESNO(gui_side, state) \
86 gtk_widget_set_sensitive((gui_side)->yes, state); \
87 gtk_widget_set_sensitive((gui_side)->no, state); \
90 #define ON(flag) ((flag) ? "on" : "off")
92 typedef struct _GUIside GUIside
;
93 typedef void ActionChild(gpointer data
);
94 typedef gboolean
ForDirCB(char *path
, char *dest_path
);
98 int from_child
; /* File descriptor */
100 int input_tag
; /* gdk_input_add() */
101 GtkWidget
*vbox
, *log
, *window
, *dir
;
102 GtkWidget
*quiet
, *yes
, *no
;
103 int child
; /* Process ID */
105 gboolean show_info
; /* For Disk Usage */
107 char *next_dir
; /* NULL => no timer active */
111 /* These don't need to be in a structure because we fork() before
114 static int from_parent
= 0;
115 static FILE *to_parent
= NULL
;
116 static gboolean quiet
= FALSE
;
117 static GString
*message
= NULL
;
118 static char *action_dest
= NULL
;
119 static gboolean (*action_do_func
)(char *source
, char *dest
);
120 static size_t size_tally
; /* For Disk Usage */
121 static DirItem
*mount_item
;
123 static gboolean o_force
= FALSE
;
125 /* Static prototypes */
126 static gboolean
send();
127 static gboolean
send_error();
128 static gboolean
send_dir(char *dir
);
129 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
);
130 static void do_mount(FilerWindow
*filer_window
, DirItem
*item
);
131 static void add_toggle(GUIside
*gui_side
, guchar
*label
, guchar
*code
);
132 static gboolean
reply(int fd
, gboolean ignore_quiet
);
136 /* Build up some option widgets to go in the options dialog, but don't
139 static GtkWidget
*create_options()
141 GtkWidget
*vbox
, *hbox
, *label
;
143 vbox
= gtk_vbox_new(FALSE
, 0);
144 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
146 label
= gtk_label_new("Auto-start (Quiet) these actions:");
147 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, TRUE
, 0);
149 hbox
= gtk_hbox_new(TRUE
, 0);
150 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
152 w_auto_copy
= gtk_check_button_new_with_label("Copy");
153 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_copy
, FALSE
, TRUE
, 0);
154 w_auto_move
= gtk_check_button_new_with_label("Move");
155 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_move
, FALSE
, TRUE
, 0);
156 w_auto_link
= gtk_check_button_new_with_label("Link");
157 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_link
, FALSE
, TRUE
, 0);
158 w_auto_delete
= gtk_check_button_new_with_label("Delete");
159 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_delete
, FALSE
, TRUE
, 0);
160 w_auto_mount
= gtk_check_button_new_with_label("Mount");
161 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_mount
, FALSE
, TRUE
, 0);
166 /* Reflect current state by changing the widgets in the options box */
167 static void update_options()
169 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_copy
),
171 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_move
),
173 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_link
),
175 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_delete
),
177 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_mount
),
181 /* Set current values by reading the states of the widgets in the options box */
182 static void set_options()
184 o_auto_copy
= gtk_toggle_button_get_active(
185 GTK_TOGGLE_BUTTON(w_auto_copy
));
186 o_auto_move
= gtk_toggle_button_get_active(
187 GTK_TOGGLE_BUTTON(w_auto_move
));
188 o_auto_link
= gtk_toggle_button_get_active(
189 GTK_TOGGLE_BUTTON(w_auto_link
));
190 o_auto_delete
= gtk_toggle_button_get_active(
191 GTK_TOGGLE_BUTTON(w_auto_delete
));
192 o_auto_mount
= gtk_toggle_button_get_active(
193 GTK_TOGGLE_BUTTON(w_auto_mount
));
196 static void save_options()
198 guchar str
[] = "cmldt";
211 option_write("action_auto_quiet", str
);
214 static char *action_auto_quiet(char *data
)
235 o_auto_delete
= state
;
238 o_auto_mount
= state
;
241 return "Unknown flag";
250 static gboolean
display_dir(gpointer data
)
252 GUIside
*gui_side
= (GUIside
*) data
;
254 gtk_label_set_text(GTK_LABEL(gui_side
->dir
), gui_side
->next_dir
+ 1);
255 g_free(gui_side
->next_dir
);
256 gui_side
->next_dir
= NULL
;
261 /* Called when the child sends us a message */
262 static void message_from_child(gpointer data
,
264 GdkInputCondition condition
)
267 GUIside
*gui_side
= (GUIside
*) data
;
268 GtkWidget
*log
= gui_side
->log
;
270 if (read_exact(source
, buf
, 4))
276 message_len
= strtol(buf
, NULL
, 16);
277 buffer
= g_malloc(message_len
+ 1);
278 if (message_len
> 0 && read_exact(source
, buffer
, message_len
))
280 buffer
[message_len
] = '\0';
282 SENSITIVE_YESNO(gui_side
, TRUE
);
283 else if (*buffer
== '+')
285 refresh_dirs(buffer
+ 1);
289 else if (*buffer
== 'm')
291 filer_check_mounted(buffer
+ 1);
295 else if (*buffer
== '/')
297 if (gui_side
->next_dir
)
298 g_free(gui_side
->next_dir
);
300 gui_side
->next_timer
=
304 gui_side
->next_dir
= buffer
;
307 else if (*buffer
== '!')
310 gtk_text_insert(GTK_TEXT(log
),
312 *buffer
== '!' ? &red
: NULL
,
314 buffer
+ 1, message_len
- 1);
318 g_print("Child died in the middle of a message.\n");
321 /* The child is dead */
324 fclose(gui_side
->to_child
);
325 gui_side
->to_child
= NULL
;
326 close(gui_side
->from_child
);
327 gdk_input_remove(gui_side
->input_tag
);
328 gtk_widget_set_sensitive(gui_side
->quiet
, FALSE
);
330 if (gui_side
->errors
)
333 report
= g_string_new(NULL
);
334 g_string_sprintf(report
, "There %s %d error%s.\n",
335 gui_side
->errors
== 1 ? "was" : "were",
337 gui_side
->errors
== 1 ? "" : "s");
338 gtk_text_insert(GTK_TEXT(log
), NULL
, &red
, NULL
,
339 report
->str
, report
->len
);
341 g_string_free(report
, TRUE
);
343 else if (gui_side
->show_info
== FALSE
)
344 gtk_widget_destroy(gui_side
->window
);
347 /* Scans src_dir, updating dest_path whenever cb returns TRUE */
348 static void for_dir_contents(ForDirCB
*cb
, char *src_dir
, char *dest_path
)
352 GSList
*list
= NULL
, *next
;
354 d
= opendir(src_dir
);
363 while ((ent
= readdir(d
)))
365 if (ent
->d_name
[0] == '.' && (ent
->d_name
[1] == '\0'
366 || (ent
->d_name
[1] == '.' && ent
->d_name
[2] == '\0')))
368 list
= g_slist_append(list
, g_strdup(make_path(src_dir
,
380 if (cb((char *) next
->data
, dest_path
))
382 g_string_sprintf(message
, "+%s", dest_path
);
393 /* Read this many bytes into the buffer. TRUE on success. */
394 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
)
399 got
= read(source
, buffer
, len
);
408 /* Send 'message' to our parent process. TRUE on success. */
409 static gboolean
send()
414 g_return_val_if_fail(message
->len
< 0xffff, FALSE
);
416 sprintf(len_buffer
, "%04x", message
->len
);
417 fwrite(len_buffer
, 1, 4, to_parent
);
418 len
= fwrite(message
->str
, 1, message
->len
, to_parent
);
420 return len
== message
->len
;
423 /* Set the directory indicator at the top of the window */
424 static gboolean
send_dir(char *dir
)
426 g_string_sprintf(message
, "/%s", dir
);
430 static gboolean
send_error()
432 g_string_sprintf(message
, "!ERROR: %s\n", g_strerror(errno
));
436 static void button_reply(GtkWidget
*button
, GUIside
*gui_side
)
440 if (!gui_side
->to_child
)
443 text
= gtk_object_get_data(GTK_OBJECT(button
), "send-code");
444 g_return_if_fail(text
!= NULL
);
445 fputc(*text
, gui_side
->to_child
);
446 fflush(gui_side
->to_child
);
448 if (*text
== 'Y' || *text
== 'N' || *text
== 'Q')
449 SENSITIVE_YESNO(gui_side
, FALSE
);
452 static void process_flag(char flag
)
463 g_string_sprintf(message
,
464 "!ERROR: Bad message '%c'\n", flag
);
470 /* If the parent has sent any flag toggles, read them */
471 static void check_flags(void)
482 FD_SET(from_parent
, &set
);
485 got
= select(from_parent
+ 1, &set
, NULL
, NULL
, &tv
);
488 g_error("select() failed: %s\n", g_strerror(errno
));
492 got
= read(from_parent
, &retval
, 1);
494 g_error("read() error: %s\n", g_strerror(errno
));
496 process_flag(retval
);
500 /* Read until the user sends a reply. If ignore_quiet is TRUE then
501 * the user MUST click Yes or No, else treat quiet on as Yes.
502 * If the user needs prompting then does send().
504 static gboolean
reply(int fd
, gboolean ignore_quiet
)
508 gboolean asked
= FALSE
;
510 while (ignore_quiet
|| !quiet
)
518 len
= read(fd
, &retval
, 1);
521 fprintf(stderr
, "read() error: %s\n",
523 _exit(1); /* Parent died? */
532 g_string_assign(message
, "?");
537 g_string_assign(message
, "' Yes\n");
541 g_string_assign(message
, "' No\n");
545 process_flag(retval
);
552 g_string_assign(message
, "' Quiet\n");
558 static void destroy_action_window(GtkWidget
*widget
, gpointer data
)
560 GUIside
*gui_side
= (GUIside
*) data
;
564 kill(gui_side
->child
, SIGTERM
);
565 fclose(gui_side
->to_child
);
566 close(gui_side
->from_child
);
567 gdk_input_remove(gui_side
->input_tag
);
570 if (gui_side
->next_dir
)
572 gtk_timeout_remove(gui_side
->next_timer
);
573 g_free(gui_side
->next_dir
);
577 if (--number_of_windows
< 1)
581 /* Create two pipes, fork() a child and return a pointer to a GUIside struct
582 * (NULL on failure). The child calls func().
584 * If autoq then automatically selects 'Quiet'.
586 static GUIside
*start_action(gpointer data
, ActionChild
*func
, gboolean autoq
)
588 int filedes
[4]; /* 0 and 2 are for reading */
591 GtkWidget
*vbox
, *button
, *hbox
, *scrollbar
, *actions
;
592 struct sigaction act
;
596 report_error("ROX-Filer", g_strerror(errno
));
600 if (pipe(filedes
+ 2))
604 report_error("ROX-Filer", g_strerror(errno
));
612 report_error("ROX-Filer", g_strerror(errno
));
615 /* We are the child */
619 /* Reset the SIGCHLD handler */
620 act
.sa_handler
= SIG_DFL
;
621 sigemptyset(&act
.sa_mask
);
623 sigaction(SIGCHLD
, &act
, NULL
);
625 message
= g_string_new(NULL
);
628 to_parent
= fdopen(filedes
[1], "wb");
629 from_parent
= filedes
[2];
634 /* We are the parent */
637 gui_side
= g_malloc(sizeof(GUIside
));
638 gui_side
->from_child
= filedes
[0];
639 gui_side
->to_child
= fdopen(filedes
[3], "wb");
640 gui_side
->log
= NULL
;
641 gui_side
->child
= child
;
642 gui_side
->errors
= 0;
643 gui_side
->show_info
= FALSE
;
645 gui_side
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
646 gtk_container_set_border_width(GTK_CONTAINER(gui_side
->window
), 2);
647 gtk_window_set_default_size(GTK_WINDOW(gui_side
->window
), 450, 200);
648 gtk_signal_connect(GTK_OBJECT(gui_side
->window
), "destroy",
649 GTK_SIGNAL_FUNC(destroy_action_window
), gui_side
);
651 gui_side
->vbox
= vbox
= gtk_vbox_new(FALSE
, 4);
652 gtk_container_add(GTK_CONTAINER(gui_side
->window
), vbox
);
654 gui_side
->dir
= gtk_label_new("<dir>");
655 gui_side
->next_dir
= NULL
;
656 gtk_misc_set_alignment(GTK_MISC(gui_side
->dir
), 0.5, 0.5);
657 gtk_box_pack_start(GTK_BOX(vbox
), gui_side
->dir
, FALSE
, TRUE
, 0);
659 hbox
= gtk_hbox_new(FALSE
, 0);
660 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, TRUE
, TRUE
, 0);
662 gui_side
->log
= gtk_text_new(NULL
, NULL
);
663 gtk_widget_set_usize(gui_side
->log
, 400, 100);
664 gtk_box_pack_start(GTK_BOX(hbox
), gui_side
->log
, TRUE
, TRUE
, 0);
665 scrollbar
= gtk_vscrollbar_new(GTK_TEXT(gui_side
->log
)->vadj
);
666 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
668 actions
= gtk_hbox_new(TRUE
, 4);
669 gtk_box_pack_start(GTK_BOX(vbox
), actions
, FALSE
, TRUE
, 0);
671 gui_side
->quiet
= button
= gtk_toggle_button_new_with_label("Quiet");
672 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button
), autoq
);
673 gtk_object_set_data(GTK_OBJECT(button
), "send-code", "Q");
674 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
675 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
676 button_reply
, gui_side
);
677 gui_side
->yes
= button
= gtk_button_new_with_label("Yes");
678 gtk_object_set_data(GTK_OBJECT(button
), "send-code", "Y");
679 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
680 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
681 button_reply
, gui_side
);
682 gui_side
->no
= button
= gtk_button_new_with_label("No");
683 gtk_object_set_data(GTK_OBJECT(button
), "send-code", "N");
684 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
685 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
686 button_reply
, gui_side
);
687 SENSITIVE_YESNO(gui_side
, FALSE
);
689 button
= gtk_button_new_with_label("Abort");
690 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
691 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
692 gtk_widget_destroy
, GTK_OBJECT(gui_side
->window
));
694 gui_side
->input_tag
= gdk_input_add(gui_side
->from_child
,
702 /* ACTIONS ON ONE ITEM */
704 /* These may call themselves recursively, or ask questions, etc.
705 * TRUE iff the directory containing dest_path needs to be rescanned.
708 /* dest_path is the dir containing src_path.
709 * Updates the global size_tally.
711 static gboolean
do_usage(char *src_path
, char *dest_path
)
717 if (lstat(src_path
, &info
))
719 g_string_sprintf(message
, "'%s:\n", src_path
);
725 if (S_ISREG(info
.st_mode
) || S_ISLNK(info
.st_mode
))
726 size_tally
+= info
.st_size
;
727 else if (S_ISDIR(info
.st_mode
))
729 g_string_sprintf(message
, "?Count contents of %s?",
731 if (reply(from_parent
, FALSE
))
734 safe_path
= g_strdup(src_path
);
735 for_dir_contents(do_usage
, safe_path
, safe_path
);
743 /* dest_path is the dir containing src_path */
744 static gboolean
do_delete(char *src_path
, char *dest_path
)
751 if (lstat(src_path
, &info
))
757 write_prot
= S_ISLNK(info
.st_mode
) ? FALSE
758 : access(src_path
, W_OK
) != 0;
759 g_string_sprintf(message
, "?Delete %s'%s'?",
760 write_prot
? "WRITE-PROTECTED " : " ",
762 if (!reply(from_parent
, write_prot
&& !o_force
))
765 if (S_ISDIR(info
.st_mode
))
768 safe_path
= g_strdup(src_path
);
769 for_dir_contents(do_delete
, safe_path
, safe_path
);
770 if (rmdir(safe_path
))
776 g_string_assign(message
, "'Directory deleted\n");
780 else if (unlink(src_path
) == 0)
782 g_string_sprintf(message
, "'Deleted '%s'\n", src_path
);
794 static gboolean
do_copy(char *path
, char *dest
)
799 struct stat dest_info
;
800 gboolean retval
= TRUE
;
804 leaf
= strrchr(path
, '/');
806 leaf
= path
; /* Error? */
810 dest_path
= make_path(dest
, leaf
)->str
;
812 if (lstat(path
, &info
))
818 if (lstat(dest_path
, &dest_info
) == 0)
823 merge
= S_ISDIR(info
.st_mode
) && S_ISDIR(dest_info
.st_mode
);
825 g_string_sprintf(message
, "?'%s' already exists - %s?",
827 merge
? "merge contents" : "overwrite");
829 if (!reply(from_parent
, TRUE
))
834 if (S_ISDIR(dest_info
.st_mode
))
835 err
= rmdir(dest_path
);
837 err
= unlink(dest_path
);
844 g_string_sprintf(message
,
845 "'Trying copy anyway...\n");
852 g_string_sprintf(message
, "?Copy %s as %s?", path
, dest_path
);
853 if (!reply(from_parent
, FALSE
))
858 g_string_sprintf(message
, "'Copying %s as %s\n", path
,
863 if (S_ISDIR(info
.st_mode
))
865 char *safe_path
, *safe_dest
;
866 struct stat dest_info
;
869 /* (we will do the update ourselves now, rather than
874 safe_path
= g_strdup(path
);
875 safe_dest
= g_strdup(dest_path
);
877 exists
= !lstat(dest_path
, &dest_info
);
879 if (exists
&& !S_ISDIR(dest_info
.st_mode
))
881 g_string_sprintf(message
,
882 "!ERROR: Destination already exists, "
883 "but is not a directory\n");
885 else if (exists
== FALSE
&& mkdir(dest_path
, info
.st_mode
))
891 /* (just been created then) */
892 g_string_sprintf(message
, "+%s", dest
);
896 for_dir_contents(do_copy
, safe_path
, safe_dest
);
897 /* Note: dest_path now invalid... */
903 else if (S_ISLNK(info
.st_mode
))
905 char target
[MAXPATHLEN
+ 1];
908 /* Not all versions of cp(1) can make symlinks,
909 * so we special-case it.
912 count
= readlink(path
, target
, sizeof(target
) - 1);
920 target
[count
] = '\0';
921 if (symlink(target
, dest_path
))
930 char *argv
[] = {"cp", "-pRf", NULL
, NULL
, NULL
};
935 if (fork_exec_wait(argv
))
937 g_string_sprintf(message
, "!ERROR: %s\n",
947 static gboolean
do_move(char *path
, char *dest
)
951 gboolean retval
= TRUE
;
952 char *argv
[] = {"mv", "-f", NULL
, NULL
, NULL
};
956 leaf
= strrchr(path
, '/');
958 leaf
= path
; /* Error? */
962 dest_path
= make_path(dest
, leaf
)->str
;
964 if (access(dest_path
, F_OK
) == 0)
969 g_string_sprintf(message
, "?'%s' already exists - overwrite?",
971 if (!reply(from_parent
, TRUE
))
974 if (lstat(dest_path
, &info
))
980 if (S_ISDIR(info
.st_mode
))
981 err
= rmdir(dest_path
);
983 err
= unlink(dest_path
);
990 g_string_sprintf(message
,
991 "'Trying move anyway...\n");
997 g_string_sprintf(message
, "?Move %s as %s?", path
, dest_path
);
998 if (!reply(from_parent
, FALSE
))
1003 g_string_sprintf(message
, "'Moving %s as %s\n", path
,
1011 if (fork_exec_wait(argv
) == 0)
1013 g_string_sprintf(message
, "+%s", path
);
1014 g_string_truncate(message
, leaf
- path
);
1019 g_string_sprintf(message
, "!ERROR: Failed to move %s as %s\n",
1028 static gboolean
do_link(char *path
, char *dest
)
1035 leaf
= strrchr(path
, '/');
1037 leaf
= path
; /* Error? */
1041 dest_path
= make_path(dest
, leaf
)->str
;
1045 g_string_sprintf(message
, "'Linking %s as %s\n", path
,
1051 g_string_sprintf(message
, "?Link %s as %s?", path
, dest_path
);
1052 if (!reply(from_parent
, FALSE
))
1056 if (symlink(path
, dest_path
))
1065 /* Mount/umount this item */
1066 static void do_mount(FilerWindow
*filer_window
, DirItem
*item
)
1068 char *argv
[3] = {NULL
, NULL
, NULL
};
1072 argv
[0] = item
->flags
& ITEM_FLAG_MOUNTED
? "umount" : "mount";
1073 argv
[1] = make_path(filer_window
->path
, item
->leafname
)->str
;
1077 g_string_sprintf(message
, "'%sing %s\n", argv
[0], argv
[1]);
1082 g_string_sprintf(message
, "?%s %s?", argv
[0], argv
[1]);
1083 if (!reply(from_parent
, FALSE
))
1087 if (fork_exec_wait(argv
) == 0)
1089 g_string_sprintf(message
, "+%s", filer_window
->path
);
1091 g_string_sprintf(message
, "m%s", argv
[1]);
1096 g_string_sprintf(message
, "!ERROR: %s failed\n", argv
[0]);
1101 /* CHILD MAIN LOOPS */
1103 /* After forking, the child calls one of these functions */
1105 static void usage_cb(gpointer data
)
1107 FilerWindow
*filer_window
= (FilerWindow
*) data
;
1108 Collection
*collection
= filer_window
->collection
;
1110 int left
= collection
->number_selected
;
1112 off_t total_size
= 0;
1114 send_dir(filer_window
->path
);
1119 if (!collection
->items
[i
].selected
)
1121 item
= (DirItem
*) collection
->items
[i
].data
;
1123 do_usage(make_path(filer_window
->path
,
1124 item
->leafname
)->str
,
1125 filer_window
->path
);
1126 g_string_sprintf(message
, "'%s: %s\n",
1128 format_size((unsigned long) size_tally
));
1130 total_size
+= size_tally
;
1134 g_string_sprintf(message
, "'\nTotal: %s\n",
1135 format_size((unsigned long) total_size
));
1139 #ifdef DO_MOUNT_POINTS
1140 static void mount_cb(gpointer data
)
1142 FilerWindow
*filer_window
= (FilerWindow
*) data
;
1143 Collection
*collection
= filer_window
->collection
;
1146 gboolean mount_points
= FALSE
;
1148 send_dir(filer_window
->path
);
1151 do_mount(filer_window
, mount_item
);
1154 for (i
= 0; i
< collection
->number_of_items
; i
++)
1156 if (!collection
->items
[i
].selected
)
1158 item
= (DirItem
*) collection
->items
[i
].data
;
1159 if (!(item
->flags
& ITEM_FLAG_MOUNT_POINT
))
1161 mount_points
= TRUE
;
1163 do_mount(filer_window
, item
);
1168 g_string_sprintf(message
,
1169 "!No mount points selected!\n");
1174 g_string_sprintf(message
, "'\nDone\n");
1179 static void delete_cb(gpointer data
)
1181 FilerWindow
*filer_window
= (FilerWindow
*) data
;
1182 Collection
*collection
= filer_window
->collection
;
1184 int left
= collection
->number_selected
;
1187 send_dir(filer_window
->path
);
1192 if (!collection
->items
[i
].selected
)
1194 item
= (DirItem
*) collection
->items
[i
].data
;
1195 if (do_delete(make_path(filer_window
->path
,
1196 item
->leafname
)->str
,
1197 filer_window
->path
))
1199 g_string_sprintf(message
, "+%s", filer_window
->path
);
1205 g_string_sprintf(message
, "'\nDone\n");
1209 static void list_cb(gpointer data
)
1211 GSList
*paths
= (GSList
*) data
;
1215 send_dir((char *) paths
->data
);
1217 if (action_do_func((char *) paths
->data
, action_dest
))
1219 g_string_sprintf(message
, "+%s", action_dest
);
1223 paths
= paths
->next
;
1226 g_string_sprintf(message
, "'\nDone\n");
1230 static void add_toggle(GUIside
*gui_side
, guchar
*label
, guchar
*code
)
1234 check
= gtk_check_button_new_with_label(label
);
1235 gtk_object_set_data(GTK_OBJECT(check
), "send-code", code
);
1236 gtk_signal_connect(GTK_OBJECT(check
), "clicked",
1237 button_reply
, gui_side
);
1238 gtk_box_pack_start(GTK_BOX(gui_side
->vbox
), check
, FALSE
, TRUE
, 0);
1242 /* EXTERNAL INTERFACE */
1244 /* Count disk space used by selected items */
1245 void action_usage(FilerWindow
*filer_window
)
1248 Collection
*collection
;
1250 collection
= filer_window
->collection
;
1252 if (collection
->number_selected
< 1)
1254 report_error("ROX-Filer", "You need to select some items "
1259 gui_side
= start_action(filer_window
, usage_cb
, TRUE
);
1263 gui_side
->show_info
= TRUE
;
1265 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), "Disk Usage");
1266 number_of_windows
++;
1267 gtk_widget_show_all(gui_side
->window
);
1270 /* Mount/unmount 'item', or all selected mount points if NULL. */
1271 void action_mount(FilerWindow
*filer_window
, DirItem
*item
)
1273 #ifdef DO_MOUNT_POINTS
1275 Collection
*collection
;
1277 collection
= filer_window
->collection
;
1279 if (item
== NULL
&& collection
->number_selected
< 1)
1281 report_error("ROX-Filer", "You need to select some items "
1282 "to mount or unmount");
1287 gui_side
= start_action(filer_window
, mount_cb
, o_auto_mount
);
1291 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), "Mount / Unmount");
1292 number_of_windows
++;
1293 gtk_widget_show_all(gui_side
->window
);
1295 report_error("ROX-Filer",
1296 "ROX-Filer does not yet support mount points on your "
1298 #endif /* DO_MOUNT_POINTS */
1301 /* Deletes all selected items in the window */
1302 void action_delete(FilerWindow
*filer_window
)
1305 Collection
*collection
;
1307 collection
= filer_window
->collection
;
1309 if (collection
->number_selected
< 1)
1311 report_error("ROX-Filer", "You need to select some items "
1316 gui_side
= start_action(filer_window
, delete_cb
, o_auto_delete
);
1320 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), "Delete");
1321 add_toggle(gui_side
,
1322 "Don't confirm deletion of non-writeable items", "F");
1324 number_of_windows
++;
1325 gtk_widget_show_all(gui_side
->window
);
1328 void action_copy(GSList
*paths
, char *dest
)
1333 action_do_func
= do_copy
;
1334 gui_side
= start_action(paths
, list_cb
, o_auto_copy
);
1338 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), "Copy");
1339 number_of_windows
++;
1340 gtk_widget_show_all(gui_side
->window
);
1343 void action_move(GSList
*paths
, char *dest
)
1348 action_do_func
= do_move
;
1349 gui_side
= start_action(paths
, list_cb
, o_auto_move
);
1353 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), "Move");
1354 number_of_windows
++;
1355 gtk_widget_show_all(gui_side
->window
);
1358 void action_link(GSList
*paths
, char *dest
)
1363 action_do_func
= do_link
;
1364 gui_side
= start_action(paths
, list_cb
, o_auto_link
);
1368 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), "Link");
1369 number_of_windows
++;
1370 gtk_widget_show_all(gui_side
->window
);
1373 void action_init(void)
1375 options_sections
= g_slist_prepend(options_sections
, &options
);
1376 option_register("action_auto_quiet", action_auto_quiet
);