4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
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>
41 #include "gui_support.h"
45 #include "modechange.h"
50 static GtkWidget
*create_options();
51 static void update_options();
52 static void set_options();
53 static void save_options();
54 static char *action_auto_quiet(char *data
);
56 static OptionsSection options
=
58 N_("Action window options"),
65 static gboolean o_auto_copy
= TRUE
;
66 static gboolean o_auto_move
= TRUE
;
67 static gboolean o_auto_link
= TRUE
;
68 static gboolean o_auto_delete
= FALSE
;
69 static gboolean o_auto_mount
= TRUE
;
71 static GtkWidget
*w_auto_copy
= NULL
;
72 static GtkWidget
*w_auto_move
= NULL
;
73 static GtkWidget
*w_auto_link
= NULL
;
74 static GtkWidget
*w_auto_delete
= NULL
;
75 static GtkWidget
*w_auto_mount
= NULL
;
77 /* Parent->Child messages are one character each:
79 * Q/Y/N Quiet/Yes/No button clicked
80 * F Force deletion of non-writeable items
83 #define SENSITIVE_YESNO(gui_side, state) \
85 gtk_widget_set_sensitive((gui_side)->yes, state); \
86 gtk_widget_set_sensitive((gui_side)->no, state); \
87 if ((gui_side)->entry) \
88 gtk_widget_set_sensitive((gui_side)->entry, state);\
91 typedef struct _GUIside GUIside
;
92 typedef void ActionChild(gpointer data
);
93 typedef gboolean
ForDirCB(char *path
, char *dest_path
);
97 int from_child
; /* File descriptor */
99 int input_tag
; /* gdk_input_add() */
100 GtkWidget
*vbox
, *log
, *window
, *dir
, *log_hbox
;
101 GtkWidget
*quiet
, *yes
, *no
;
102 int child
; /* Process ID */
104 gboolean show_info
; /* For Disk Usage */
106 GtkWidget
*entry
; /* May be NULL */
107 guchar
**default_string
; /* Changed when the entry changes */
109 char *next_dir
; /* NULL => no timer active */
113 FilerWindow
*preview
;
117 /* These don't need to be in a structure because we fork() before
120 static int from_parent
= 0;
121 static FILE *to_parent
= NULL
;
122 static gboolean quiet
= FALSE
;
123 static GString
*message
= NULL
;
124 static char *action_dest
= NULL
;
125 static char *action_leaf
= NULL
;
126 static gboolean (*action_do_func
)(char *source
, char *dest
);
127 static size_t size_tally
; /* For Disk Usage */
129 static struct mode_change
*mode_change
= NULL
; /* For Permissions */
130 static FindCondition
*find_condition
= NULL
; /* For Find */
132 static gboolean o_force
= FALSE
;
133 static gboolean o_brief
= FALSE
;
134 static gboolean o_recurse
= FALSE
;
136 /* Whenever the text in these boxes is changed we store a copy of the new
137 * string to be used as the default next time.
139 static guchar
*last_chmod_string
= NULL
;
140 static guchar
*last_find_string
= NULL
;
142 /* Set to one of the above before forking. This may change over a call to
143 * reply(). It is reset to NULL once the text is parsed.
145 static guchar
*new_entry_string
= NULL
;
147 /* Static prototypes */
148 static gboolean
send();
149 static gboolean
send_error();
150 static gboolean
send_dir(char *dir
);
151 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
);
152 static void do_mount(guchar
*path
, gboolean mount
);
153 static void add_toggle(GUIside
*gui_side
, guchar
*label
, guchar
*code
);
154 static gboolean
reply(int fd
, gboolean ignore_quiet
);
158 /* Build up some option widgets to go in the options dialog, but don't
161 static GtkWidget
*create_options()
163 GtkWidget
*vbox
, *hbox
, *label
;
165 vbox
= gtk_vbox_new(FALSE
, 0);
166 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
168 label
= gtk_label_new(_("Auto-start (Quiet) these actions:"));
169 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, TRUE
, 0);
171 hbox
= gtk_hbox_new(TRUE
, 0);
172 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
174 w_auto_copy
= gtk_check_button_new_with_label(_("Copy"));
175 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_copy
, FALSE
, TRUE
, 0);
176 w_auto_move
= gtk_check_button_new_with_label(_("Move"));
177 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_move
, FALSE
, TRUE
, 0);
178 w_auto_link
= gtk_check_button_new_with_label(_("Link"));
179 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_link
, FALSE
, TRUE
, 0);
180 w_auto_delete
= gtk_check_button_new_with_label(_("Delete"));
181 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_delete
, FALSE
, TRUE
, 0);
182 w_auto_mount
= gtk_check_button_new_with_label(_("Mount"));
183 gtk_box_pack_start(GTK_BOX(hbox
), w_auto_mount
, FALSE
, TRUE
, 0);
188 /* Reflect current state by changing the widgets in the options box */
189 static void update_options()
191 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_copy
),
193 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_move
),
195 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_link
),
197 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_delete
),
199 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_auto_mount
),
203 /* Set current values by reading the states of the widgets in the options box */
204 static void set_options()
206 o_auto_copy
= gtk_toggle_button_get_active(
207 GTK_TOGGLE_BUTTON(w_auto_copy
));
208 o_auto_move
= gtk_toggle_button_get_active(
209 GTK_TOGGLE_BUTTON(w_auto_move
));
210 o_auto_link
= gtk_toggle_button_get_active(
211 GTK_TOGGLE_BUTTON(w_auto_link
));
212 o_auto_delete
= gtk_toggle_button_get_active(
213 GTK_TOGGLE_BUTTON(w_auto_delete
));
214 o_auto_mount
= gtk_toggle_button_get_active(
215 GTK_TOGGLE_BUTTON(w_auto_mount
));
218 static void save_options()
220 guchar str
[] = "cmldt";
233 option_write("action_auto_quiet", str
);
236 static char *action_auto_quiet(char *data
)
257 o_auto_delete
= state
;
260 o_auto_mount
= state
;
263 return _("Unknown flag");
272 static void preview_closed(GtkWidget
*window
, GUIside
*gui_side
)
274 gui_side
->preview
= NULL
;
277 static void select_row_callback(GtkWidget
*widget
,
278 gint row
, gint column
,
279 GdkEventButton
*event
,
284 gtk_clist_get_text(GTK_CLIST(gui_side
->results
), row
, 0, &leaf
);
285 gtk_clist_get_text(GTK_CLIST(gui_side
->results
), row
, 1, &dir
);
287 gtk_clist_unselect_row(GTK_CLIST(gui_side
->results
), row
, column
);
289 if (gui_side
->preview
)
291 if (strcmp(gui_side
->preview
->path
, dir
) == 0)
292 display_set_autoselect(gui_side
->preview
, leaf
);
294 filer_change_to(gui_side
->preview
, dir
, leaf
);
298 gui_side
->preview
= filer_opendir(dir
);
299 if (gui_side
->preview
)
301 display_set_autoselect(gui_side
->preview
, leaf
);
302 gtk_signal_connect(GTK_OBJECT(gui_side
->preview
->window
),
304 GTK_SIGNAL_FUNC(preview_closed
), gui_side
);
309 /* This is called whenever the user edits the entry box (if any) - send the
312 static void entry_changed(GtkEntry
*entry
, GUIside
*gui_side
)
316 g_return_if_fail(gui_side
->default_string
!= NULL
);
318 text
= gtk_entry_get_text(entry
);
320 g_free(*(gui_side
->default_string
));
321 *(gui_side
->default_string
) = g_strdup(text
);
323 if (!gui_side
->to_child
)
326 fputc('E', gui_side
->to_child
);
327 fputs(text
, gui_side
->to_child
);
328 fputc('\n', gui_side
->to_child
);
329 fflush(gui_side
->to_child
);
332 void show_condition_help(gpointer data
)
334 static GtkWidget
*help
= NULL
;
338 GtkWidget
*text
, *vbox
, *button
, *hbox
, *frame
;
340 help
= gtk_window_new(GTK_WINDOW_DIALOG
);
341 gtk_container_set_border_width(GTK_CONTAINER(help
), 10);
342 gtk_window_set_title(GTK_WINDOW(help
),
343 _("Find expression reference"));
345 vbox
= gtk_vbox_new(FALSE
, 0);
346 gtk_container_add(GTK_CONTAINER(help
), vbox
);
348 frame
= gtk_frame_new(_("Quick Start"));
349 text
= gtk_label_new(
350 _("Just put the name of the file you're looking for in single quotes:\n"
351 "'index.html' (to find a file called 'index.html')"));
352 gtk_misc_set_padding(GTK_MISC(text
), 4, 4);
353 gtk_label_set_justify(GTK_LABEL(text
), GTK_JUSTIFY_LEFT
);
354 gtk_container_add(GTK_CONTAINER(frame
), text
);
355 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 4);
357 frame
= gtk_frame_new(_("Examples"));
358 text
= gtk_label_new(
359 _("'*.htm', '*.html' (finds HTML files)\n"
360 "IsDir 'lib' (finds directories called 'lib')\n"
361 "IsReg 'core' (finds a regular file called 'core')\n"
362 "! (IsDir, IsReg) (is neither a directory nor a regular file)\n"
363 "mtime after 1 day ago and size > 1Mb (big, and recently modified)\n"
364 "'CVS' prune, isreg (a regular file not in CVS)\n"
365 "IsReg system(grep -q fred \"%\") (contains the word 'fred')"));
366 gtk_widget_set_style(text
, fixed_style
);
367 gtk_misc_set_padding(GTK_MISC(text
), 4, 4);
368 gtk_label_set_justify(GTK_LABEL(text
), GTK_JUSTIFY_LEFT
);
369 gtk_container_add(GTK_CONTAINER(frame
), text
);
370 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 4);
372 frame
= gtk_frame_new(_("Simple Tests"));
373 text
= gtk_label_new(
374 _("IsReg, IsLink, IsDir, IsChar, IsBlock, IsDev, IsPipe, IsSocket (types)\n"
375 "IsSUID, IsSGID, IsSticky, IsReadable, IsWriteable, IsExecutable (permissions)"
379 "A pattern in single quotes is a shell-style wildcard pattern to match. If it\n"
380 "contains a slash then the match is against the full path; otherwise it is \n"
381 "against the leafname only."));
382 gtk_misc_set_padding(GTK_MISC(text
), 4, 4);
383 gtk_label_set_justify(GTK_LABEL(text
), GTK_JUSTIFY_LEFT
);
384 gtk_container_add(GTK_CONTAINER(frame
), text
);
385 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 4);
387 frame
= gtk_frame_new(_("Comparisons"));
388 text
= gtk_label_new(
389 _("<, <=, =, !=, >, >=, After, Before (compare two values)\n"
390 "5 bytes, 1Kb, 2Mb, 3Gb (file sizes)\n"
391 "2 secs|mins|hours|days|weeks|years ago|hence (times)\n"
392 "atime, ctime, mtime, now, size, inode, nlinks, uid, gid, blocks (values)"));
393 gtk_misc_set_padding(GTK_MISC(text
), 4, 4);
394 gtk_label_set_justify(GTK_LABEL(text
), GTK_JUSTIFY_LEFT
);
395 gtk_container_add(GTK_CONTAINER(frame
), text
);
396 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 4);
398 frame
= gtk_frame_new(_("Specials"));
399 text
= gtk_label_new(
400 _("system(command) (true if 'command' returns with a zero exit status; a % \n"
401 "in 'command' is replaced with the path of the current file)\n"
402 "prune (false, and prevents searching the contents of a directory).")
404 gtk_misc_set_padding(GTK_MISC(text
), 4, 4);
405 gtk_label_set_justify(GTK_LABEL(text
), GTK_JUSTIFY_LEFT
);
406 gtk_container_add(GTK_CONTAINER(frame
), text
);
407 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 4);
409 hbox
= gtk_hbox_new(FALSE
, 20);
410 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, TRUE
, TRUE
, 0);
412 text
= gtk_label_new(
413 _("See the ROX-Filer manual for full details."));
414 gtk_box_pack_start(GTK_BOX(hbox
), text
, TRUE
, TRUE
, 0);
415 button
= gtk_button_new_with_label(_("Close"));
416 gtk_box_pack_start(GTK_BOX(hbox
), button
, FALSE
, TRUE
, 0);
417 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
418 gtk_widget_hide
, GTK_OBJECT(help
));
420 gtk_signal_connect_object(GTK_OBJECT(help
), "delete_event",
421 gtk_widget_hide
, GTK_OBJECT(help
));
424 if (GTK_WIDGET_VISIBLE(help
))
425 gtk_widget_hide(help
);
426 gtk_widget_show_all(help
);
429 static void show_chmod_help(gpointer data
)
431 static GtkWidget
*help
= NULL
;
435 GtkWidget
*text
, *vbox
, *button
, *hbox
, *sep
;
437 help
= gtk_window_new(GTK_WINDOW_DIALOG
);
438 gtk_container_set_border_width(GTK_CONTAINER(help
), 10);
439 gtk_window_set_title(GTK_WINDOW(help
),
440 _("Permissions command reference"));
442 vbox
= gtk_vbox_new(FALSE
, 0);
443 gtk_container_add(GTK_CONTAINER(help
), vbox
);
445 text
= gtk_label_new(
446 _("Normally, you can just select a command from the menu (click \n"
447 "on the arrow beside the command box). Sometimes, you need more...\n"
449 "The format of a command is:\n"
450 "CHANGE, CHANGE, ...\n"
452 "WHO HOW PERMISSIONS\n"
453 "WHO is some combination of u, g and o which determines whether to\n"
454 "change the permissions for the User (owner), Group or Others.\n"
455 "HOW is +, - or = to add, remove or set exactly the permissions.\n"
456 "PERMISSIONS is some combination of the letters 'rwxXstugo'\n\n"
458 "Bracketed text and spaces are ignored.\n\n"
461 "u+rw (the file owner gains read and write permission)\n"
462 "g=u (the group permissions are set to be the same as the user's)\n"
463 "o=u-w (others get the same permissions as the owner, but without "
464 "write permission)\n"
465 "a+x (everyone gets execute/access permission - same as 'ugo+x')\n"
466 "a+X (directories become accessable by everyone; files which were\n"
467 "executable by anyone become executable by everyone)\n"
468 "u+rw, go+r (two commands at once!)\n"
469 "u+s (set the SetUID bit - often has no effect on script files)\n"
470 "755 (set the permissions directly)\n"
472 "\nSee the chmod(1) man page for full details."));
473 gtk_label_set_justify(GTK_LABEL(text
), GTK_JUSTIFY_LEFT
);
474 gtk_box_pack_start(GTK_BOX(vbox
), text
, TRUE
, TRUE
, 0);
476 hbox
= gtk_hbox_new(FALSE
, 20);
477 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
479 sep
= gtk_hseparator_new();
480 gtk_box_pack_start(GTK_BOX(hbox
), sep
, TRUE
, TRUE
, 0);
481 button
= gtk_button_new_with_label(_("Close"));
482 gtk_box_pack_start(GTK_BOX(hbox
), button
, FALSE
, TRUE
, 0);
483 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
484 gtk_widget_hide
, GTK_OBJECT(help
));
486 gtk_signal_connect_object(GTK_OBJECT(help
), "delete_event",
487 gtk_widget_hide
, GTK_OBJECT(help
));
490 if (GTK_WIDGET_VISIBLE(help
))
491 gtk_widget_hide(help
);
492 gtk_widget_show_all(help
);
495 /* TRUE iff `sub' is (or would be) an object inside the directory `parent',
496 * (or the two are the same directory)
498 static gboolean
is_sub_dir(char *sub
, char *parent
)
501 guchar
*real_sub
, *real_parent
;
504 real_sub
= pathdup(sub
);
505 real_parent
= pathdup(parent
);
507 parent_len
= strlen(real_parent
);
508 if (strncmp(real_parent
, real_sub
, parent_len
))
512 /* real_sub is at least as long as real_parent and all
513 * characters upto real_parent's length match.
516 retval
= real_sub
[parent_len
] == '\0' ||
517 real_sub
[parent_len
] == '/';
526 static gboolean
display_dir(gpointer data
)
528 GUIside
*gui_side
= (GUIside
*) data
;
530 gtk_label_set_text(GTK_LABEL(gui_side
->dir
), gui_side
->next_dir
+ 1);
531 g_free(gui_side
->next_dir
);
532 gui_side
->next_dir
= NULL
;
537 static void add_to_results(GUIside
*gui_side
, gchar
*path
)
539 gchar
*row
[] = {"Leaf", "Dir"};
543 slash
= strrchr(path
, '/');
544 g_return_if_fail(slash
!= NULL
);
547 row
[1] = g_strndup(path
, MAX(len
, 1));
550 gtk_clist_append(GTK_CLIST(gui_side
->results
), row
);
555 /* Called when the child sends us a message */
556 static void message_from_child(gpointer data
,
558 GdkInputCondition condition
)
561 GUIside
*gui_side
= (GUIside
*) data
;
562 GtkWidget
*log
= gui_side
->log
;
564 if (read_exact(source
, buf
, 4))
570 message_len
= strtol(buf
, NULL
, 16);
571 buffer
= g_malloc(message_len
+ 1);
572 if (message_len
> 0 && read_exact(source
, buffer
, message_len
))
574 buffer
[message_len
] = '\0';
577 SENSITIVE_YESNO(gui_side
, TRUE
);
578 gtk_window_set_focus(
579 GTK_WINDOW(gui_side
->window
),
580 gui_side
->entry
? gui_side
->entry
583 else if (*buffer
== '+')
585 refresh_dirs(buffer
+ 1);
589 else if (*buffer
== '=')
591 add_to_results(gui_side
, buffer
+ 1);
595 else if (*buffer
== 'm')
597 filer_check_mounted(buffer
+ 1);
601 else if (*buffer
== '/')
603 if (gui_side
->next_dir
)
604 g_free(gui_side
->next_dir
);
606 gui_side
->next_timer
=
610 gui_side
->next_dir
= buffer
;
613 else if (*buffer
== '!')
616 gtk_text_insert(GTK_TEXT(log
),
618 *buffer
== '!' ? &red
: NULL
,
620 buffer
+ 1, message_len
- 1);
624 g_printerr("Child died in the middle of a message.\n");
627 /* The child is dead */
630 fclose(gui_side
->to_child
);
631 gui_side
->to_child
= NULL
;
632 close(gui_side
->from_child
);
633 gdk_input_remove(gui_side
->input_tag
);
634 gtk_widget_set_sensitive(gui_side
->quiet
, FALSE
);
636 if (gui_side
->errors
)
640 if (gui_side
->errors
== 1)
641 report
= g_strdup(_("There was one error.\n"));
643 report
= g_strdup_printf(_("There were %d errors.\n"),
646 gtk_text_insert(GTK_TEXT(log
), NULL
, &red
, NULL
,
651 else if (gui_side
->show_info
== FALSE
)
652 gtk_widget_destroy(gui_side
->window
);
655 /* Scans src_dir, updating dest_path whenever cb returns TRUE */
656 static void for_dir_contents(ForDirCB
*cb
, char *src_dir
, char *dest_path
)
660 GSList
*list
= NULL
, *next
;
662 d
= mc_opendir(src_dir
);
665 /* Message displayed is "ERROR reading 'path': message" */
666 g_string_sprintf(message
, "!%s '%s': %s\n",
668 src_dir
, g_strerror(errno
));
675 while ((ent
= mc_readdir(d
)))
677 if (ent
->d_name
[0] == '.' && (ent
->d_name
[1] == '\0'
678 || (ent
->d_name
[1] == '.' && ent
->d_name
[2] == '\0')))
680 list
= g_slist_append(list
, g_strdup(make_path(src_dir
,
692 if (cb((char *) next
->data
, dest_path
))
694 g_string_sprintf(message
, "+%s", dest_path
);
705 /* Read this many bytes into the buffer. TRUE on success. */
706 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
)
711 got
= read(source
, buffer
, len
);
720 /* Send 'message' to our parent process. TRUE on success. */
721 static gboolean
send()
726 g_return_val_if_fail(message
->len
< 0xffff, FALSE
);
728 sprintf(len_buffer
, "%04x", message
->len
);
729 fwrite(len_buffer
, 1, 4, to_parent
);
730 len
= fwrite(message
->str
, 1, message
->len
, to_parent
);
732 return len
== message
->len
;
735 /* Set the directory indicator at the top of the window */
736 static gboolean
send_dir(char *dir
)
738 g_string_sprintf(message
, "/%s", dir
);
742 static gboolean
send_error()
744 g_string_sprintf(message
, "!%s: %s\n", _("ERROR"), g_strerror(errno
));
748 static void button_reply(GtkWidget
*button
, GUIside
*gui_side
)
752 if (!gui_side
->to_child
)
755 text
= gtk_object_get_data(GTK_OBJECT(button
), "send-code");
756 g_return_if_fail(text
!= NULL
);
757 fputc(*text
, gui_side
->to_child
);
758 fflush(gui_side
->to_child
);
760 if (*text
== 'Y' || *text
== 'N' || *text
== 'Q')
761 SENSITIVE_YESNO(gui_side
, FALSE
);
764 static void process_flag(char flag
)
775 o_recurse
= !o_recurse
;
781 g_string_sprintf(message
,
782 "!ERROR: Bad message '%c'\n", flag
);
788 /* If the parent has sent any flag toggles, read them */
789 static void check_flags(void)
800 FD_SET(from_parent
, &set
);
803 got
= select(from_parent
+ 1, &set
, NULL
, NULL
, &tv
);
806 g_error("select() failed: %s\n", g_strerror(errno
));
810 got
= read(from_parent
, &retval
, 1);
812 g_error("read() error: %s\n", g_strerror(errno
));
814 process_flag(retval
);
818 static void read_new_entry_text(void)
824 new = g_string_new(NULL
);
828 len
= read(from_parent
, &c
, 1);
831 fprintf(stderr
, "read() error: %s\n",
833 _exit(1); /* Parent died? */
838 g_string_append_c(new, c
);
841 g_free(new_entry_string
);
842 new_entry_string
= new->str
;
843 g_string_free(new, FALSE
);
846 /* Read until the user sends a reply. If ignore_quiet is TRUE then
847 * the user MUST click Yes or No, else treat quiet on as Yes.
848 * If the user needs prompting then does send().
850 static gboolean
reply(int fd
, gboolean ignore_quiet
)
854 gboolean asked
= FALSE
;
856 while (ignore_quiet
|| !quiet
)
864 len
= read(fd
, &retval
, 1);
867 fprintf(stderr
, "read() error: %s\n",
869 _exit(1); /* Parent died? */
878 g_string_assign(message
, "?");
883 g_string_sprintf(message
, "' %s\n", _("Yes"));
887 g_string_sprintf(message
, "' %s\n", _("No"));
891 read_new_entry_text();
894 process_flag(retval
);
901 g_string_sprintf(message
, "' %s\n", _("Quiet"));
907 static void destroy_action_window(GtkWidget
*widget
, gpointer data
)
909 GUIside
*gui_side
= (GUIside
*) data
;
913 kill(gui_side
->child
, SIGTERM
);
914 fclose(gui_side
->to_child
);
915 close(gui_side
->from_child
);
916 gdk_input_remove(gui_side
->input_tag
);
919 if (gui_side
->next_dir
)
921 gtk_timeout_remove(gui_side
->next_timer
);
922 g_free(gui_side
->next_dir
);
925 if (gui_side
->preview
)
927 gtk_signal_disconnect_by_data(
928 GTK_OBJECT(gui_side
->preview
->window
),
930 gui_side
->preview
= NULL
;
935 if (--number_of_windows
< 1)
939 /* Create two pipes, fork() a child and return a pointer to a GUIside struct
940 * (NULL on failure). The child calls func().
942 * If autoq then automatically selects 'Quiet'.
944 static GUIside
*start_action(gpointer data
, ActionChild
*func
, gboolean autoq
)
946 int filedes
[4]; /* 0 and 2 are for reading */
949 GtkWidget
*vbox
, *button
, *scrollbar
, *actions
;
950 struct sigaction act
;
954 report_error(PROJECT
, g_strerror(errno
));
958 if (pipe(filedes
+ 2))
962 report_error(PROJECT
, g_strerror(errno
));
970 report_error(PROJECT
, g_strerror(errno
));
973 /* We are the child */
975 dup2(to_error_log
, STDOUT_FILENO
);
976 close_on_exec(STDOUT_FILENO
, FALSE
);
977 dup2(to_error_log
, STDERR_FILENO
);
978 close_on_exec(STDERR_FILENO
, FALSE
);
982 /* Reset the SIGCHLD handler */
983 act
.sa_handler
= SIG_DFL
;
984 sigemptyset(&act
.sa_mask
);
986 sigaction(SIGCHLD
, &act
, NULL
);
988 message
= g_string_new(NULL
);
991 to_parent
= fdopen(filedes
[1], "wb");
992 from_parent
= filedes
[2];
998 /* We are the parent */
1001 gui_side
= g_malloc(sizeof(GUIside
));
1002 gui_side
->from_child
= filedes
[0];
1003 gui_side
->to_child
= fdopen(filedes
[3], "wb");
1004 gui_side
->log
= NULL
;
1005 gui_side
->child
= child
;
1006 gui_side
->errors
= 0;
1007 gui_side
->show_info
= FALSE
;
1008 gui_side
->preview
= NULL
;
1009 gui_side
->results
= NULL
;
1010 gui_side
->entry
= NULL
;
1011 gui_side
->default_string
= NULL
;
1013 gui_side
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
1014 gtk_container_set_border_width(GTK_CONTAINER(gui_side
->window
), 2);
1015 gtk_window_set_default_size(GTK_WINDOW(gui_side
->window
), 450, 200);
1016 gtk_signal_connect(GTK_OBJECT(gui_side
->window
), "destroy",
1017 GTK_SIGNAL_FUNC(destroy_action_window
), gui_side
);
1019 gui_side
->vbox
= vbox
= gtk_vbox_new(FALSE
, 0);
1020 gtk_container_add(GTK_CONTAINER(gui_side
->window
), vbox
);
1022 gui_side
->dir
= gtk_label_new(_("<dir>"));
1023 gui_side
->next_dir
= NULL
;
1024 gtk_misc_set_alignment(GTK_MISC(gui_side
->dir
), 0.5, 0.5);
1025 gtk_box_pack_start(GTK_BOX(vbox
), gui_side
->dir
, FALSE
, TRUE
, 0);
1027 gui_side
->log_hbox
= gtk_hbox_new(FALSE
, 0);
1028 gtk_box_pack_start(GTK_BOX(vbox
), gui_side
->log_hbox
, TRUE
, TRUE
, 4);
1030 gui_side
->log
= gtk_text_new(NULL
, NULL
);
1031 gtk_widget_set_usize(gui_side
->log
, 400, 100);
1032 gtk_box_pack_start(GTK_BOX(gui_side
->log_hbox
),
1033 gui_side
->log
, TRUE
, TRUE
, 0);
1034 scrollbar
= gtk_vscrollbar_new(GTK_TEXT(gui_side
->log
)->vadj
);
1035 gtk_box_pack_start(GTK_BOX(gui_side
->log_hbox
),
1036 scrollbar
, FALSE
, TRUE
, 0);
1038 actions
= gtk_hbox_new(TRUE
, 4);
1039 gtk_box_pack_start(GTK_BOX(vbox
), actions
, FALSE
, TRUE
, 0);
1041 gui_side
->quiet
= button
= gtk_toggle_button_new_with_label(_("Quiet"));
1042 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button
), autoq
);
1043 gtk_object_set_data(GTK_OBJECT(button
), "send-code", "Q");
1044 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
1045 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1046 button_reply
, gui_side
);
1047 gui_side
->yes
= button
= gtk_button_new_with_label(_("Yes"));
1048 gtk_object_set_data(GTK_OBJECT(button
), "send-code", "Y");
1049 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
1050 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1051 button_reply
, gui_side
);
1052 gui_side
->no
= button
= gtk_button_new_with_label(_("No"));
1053 gtk_object_set_data(GTK_OBJECT(button
), "send-code", "N");
1054 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
1055 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1056 button_reply
, gui_side
);
1057 SENSITIVE_YESNO(gui_side
, FALSE
);
1059 button
= gtk_button_new_with_label(_("Abort"));
1060 gtk_box_pack_start(GTK_BOX(actions
), button
, TRUE
, TRUE
, 0);
1061 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
1062 gtk_widget_destroy
, GTK_OBJECT(gui_side
->window
));
1064 gui_side
->input_tag
= gdk_input_add(gui_side
->from_child
,
1072 /* ACTIONS ON ONE ITEM */
1074 /* These may call themselves recursively, or ask questions, etc.
1075 * TRUE iff the directory containing dest_path needs to be rescanned.
1078 /* dest_path is the dir containing src_path.
1079 * Updates the global size_tally.
1081 static gboolean
do_usage(char *src_path
, char *dest_path
)
1087 if (mc_lstat(src_path
, &info
))
1089 g_string_sprintf(message
, "'%s:\n", src_path
);
1095 if (S_ISREG(info
.st_mode
) || S_ISLNK(info
.st_mode
))
1096 size_tally
+= info
.st_size
;
1097 else if (S_ISDIR(info
.st_mode
))
1099 g_string_sprintf(message
, _("?Count contents of %s?"),
1101 if (reply(from_parent
, FALSE
))
1104 safe_path
= g_strdup(src_path
);
1105 for_dir_contents(do_usage
, safe_path
, safe_path
);
1113 /* dest_path is the dir containing src_path */
1114 static gboolean
do_delete(char *src_path
, char *dest_path
)
1117 gboolean write_prot
;
1121 if (mc_lstat(src_path
, &info
))
1127 write_prot
= S_ISLNK(info
.st_mode
) ? FALSE
1128 : access(src_path
, W_OK
) != 0;
1129 if (write_prot
|| !quiet
)
1131 g_string_sprintf(message
, _("?Delete %s'%s'?"),
1132 write_prot
? _("WRITE-PROTECTED ") : " ",
1134 if (!reply(from_parent
, write_prot
&& !o_force
))
1139 g_string_sprintf(message
, _("'Deleting '%s'\n"), src_path
);
1143 if (S_ISDIR(info
.st_mode
))
1146 safe_path
= g_strdup(src_path
);
1147 for_dir_contents(do_delete
, safe_path
, safe_path
);
1148 if (rmdir(safe_path
))
1154 g_string_sprintf(message
, _("'Directory '%s' deleted\n"),
1157 g_string_sprintf(message
, "m%s", safe_path
);
1161 else if (unlink(src_path
))
1170 /* path is the item to check. If is is a directory then we may recurse
1171 * (unless prune is used).
1173 static gboolean
do_find(char *path
, char *dummy
)
1182 g_string_sprintf(message
, _("?Check '%s'?"), path
);
1183 if (!reply(from_parent
, FALSE
))
1189 if (new_entry_string
)
1192 find_condition_free(find_condition
);
1193 find_condition
= find_compile(new_entry_string
);
1194 g_free(new_entry_string
);
1195 new_entry_string
= NULL
;
1201 g_string_assign(message
, _("!Invalid find condition - "
1202 "change it and try again\n"));
1204 g_string_sprintf(message
, _("?Check '%s'?"), path
);
1205 if (!reply(from_parent
, TRUE
))
1209 if (mc_lstat(path
, &info
.stats
))
1212 g_string_sprintf(message
, _("'(while checking '%s')\n"), path
);
1217 info
.fullpath
= path
;
1218 time(&info
.now
); /* XXX: Not for each check! */
1220 slash
= strrchr(path
, '/');
1221 info
.leaf
= slash
? slash
+ 1 : path
;
1223 if (find_test_condition(find_condition
, &info
))
1225 g_string_sprintf(message
, "=%s", path
);
1229 if (S_ISDIR(info
.stats
.st_mode
) && !info
.prune
)
1232 safe_path
= g_strdup(path
);
1233 for_dir_contents(do_find
, safe_path
, safe_path
);
1240 /* Like mode_compile(), but ignores spaces and bracketed bits */
1241 struct mode_change
*nice_mode_compile(const char *mode_string
,
1242 unsigned int masked_ops
)
1246 struct mode_change
*retval
= NULL
;
1248 new = g_string_new(NULL
);
1250 for (; *mode_string
; mode_string
++)
1252 if (*mode_string
== '(')
1254 if (*mode_string
== ')')
1262 if (brackets
== 0 && *mode_string
!= ' ')
1263 g_string_append_c(new, *mode_string
);
1267 retval
= mode_compile(new->str
, masked_ops
);
1268 g_string_free(new, TRUE
);
1272 static gboolean
do_chmod(char *path
, char *dummy
)
1279 if (mc_lstat(path
, &info
))
1284 if (S_ISLNK(info
.st_mode
))
1289 g_string_sprintf(message
,
1290 _("?Change permissions of '%s'?"), path
);
1291 if (!reply(from_parent
, FALSE
))
1296 g_string_sprintf(message
,
1297 _("'Changing permissions of '%s'\n"),
1304 if (new_entry_string
)
1307 mode_free(mode_change
);
1308 mode_change
= nice_mode_compile(new_entry_string
,
1310 g_free(new_entry_string
);
1311 new_entry_string
= NULL
;
1317 g_string_assign(message
,
1318 _("!Invalid mode command - change it and try again\n"));
1320 g_string_sprintf(message
,
1321 _("?Change permissions of '%s'?"), path
);
1322 if (!reply(from_parent
, TRUE
))
1326 if (mc_lstat(path
, &info
))
1331 if (S_ISLNK(info
.st_mode
))
1334 new_mode
= mode_adjust(info
.st_mode
, mode_change
);
1335 if (chmod(path
, new_mode
))
1341 if (o_recurse
&& S_ISDIR(info
.st_mode
))
1344 safe_path
= g_strdup(path
);
1345 for_dir_contents(do_chmod
, safe_path
, safe_path
);
1352 /* We want to copy 'object' into directory 'dir'. If 'action_leaf'
1353 * is set then that is the new leafname, otherwise the leafname stays
1356 static char *make_dest_path(char *object
, char *dir
)
1364 leaf
= strrchr(object
, '/');
1366 leaf
= object
; /* Error? */
1371 return make_path(dir
, leaf
)->str
;
1374 /* If action_leaf is not NULL it specifies the new leaf name */
1375 static gboolean
do_copy2(char *path
, char *dest
)
1379 struct stat dest_info
;
1380 gboolean retval
= TRUE
;
1384 dest_path
= make_dest_path(path
, dest
);
1386 if (mc_lstat(path
, &info
))
1392 if (mc_lstat(dest_path
, &dest_info
) == 0)
1397 merge
= S_ISDIR(info
.st_mode
) && S_ISDIR(dest_info
.st_mode
);
1399 g_string_sprintf(message
, _("?'%s' already exists - %s?"),
1401 merge
? _("merge contents") : _("overwrite"));
1403 if (!reply(from_parent
, TRUE
))
1408 if (S_ISDIR(dest_info
.st_mode
))
1409 err
= rmdir(dest_path
);
1411 err
= unlink(dest_path
);
1416 if (errno
!= ENOENT
)
1418 g_string_sprintf(message
,
1419 _("'Trying copy anyway...\n"));
1426 g_string_sprintf(message
,
1427 _("?Copy %s as %s?"), path
, dest_path
);
1428 if (!reply(from_parent
, FALSE
))
1433 g_string_sprintf(message
, _("'Copying %s as %s\n"), path
,
1438 if (S_ISDIR(info
.st_mode
))
1440 char *safe_path
, *safe_dest
;
1441 struct stat dest_info
;
1444 /* (we will do the update ourselves now, rather than
1449 safe_path
= g_strdup(path
);
1450 safe_dest
= g_strdup(dest_path
);
1452 exists
= !mc_lstat(dest_path
, &dest_info
);
1454 if (exists
&& !S_ISDIR(dest_info
.st_mode
))
1456 g_string_sprintf(message
,
1457 _("!ERROR: Destination already exists, "
1458 "but is not a directory\n"));
1460 else if (exists
== FALSE
&& mkdir(dest_path
, info
.st_mode
))
1466 /* (just been created then) */
1467 g_string_sprintf(message
, "+%s", dest
);
1472 for_dir_contents(do_copy2
, safe_path
, safe_dest
);
1473 /* Note: dest_path now invalid... */
1479 else if (S_ISLNK(info
.st_mode
))
1481 char target
[MAXPATHLEN
+ 1];
1484 /* Not all versions of cp(1) can make symlinks,
1485 * so we special-case it.
1488 count
= readlink(path
, target
, sizeof(target
) - 1);
1496 target
[count
] = '\0';
1497 if (symlink(target
, dest_path
))
1508 error
= copy_file(path
, dest_path
);
1512 g_string_sprintf(message
, _("!ERROR: %s\n"), error
);
1521 /* If action_leaf is not NULL it specifies the new leaf name */
1522 static gboolean
do_move2(char *path
, char *dest
)
1525 gboolean retval
= TRUE
;
1526 char *argv
[] = {"mv", "-f", NULL
, NULL
, NULL
};
1532 dest_path
= make_dest_path(path
, dest
);
1534 is_dir
= mc_lstat(path
, &info2
) == 0 && S_ISDIR(info2
.st_mode
);
1536 if (access(dest_path
, F_OK
) == 0)
1541 g_string_sprintf(message
,
1542 _("?'%s' already exists - overwrite?"),
1544 if (!reply(from_parent
, TRUE
))
1547 if (mc_lstat(dest_path
, &info
))
1553 if (S_ISDIR(info
.st_mode
))
1554 err
= rmdir(dest_path
);
1556 err
= unlink(dest_path
);
1561 if (errno
!= ENOENT
)
1563 g_string_sprintf(message
,
1564 _("'Trying move anyway...\n"));
1570 g_string_sprintf(message
,
1571 _("?Move %s as %s?"), path
, dest_path
);
1572 if (!reply(from_parent
, FALSE
))
1577 g_string_sprintf(message
, _("'Moving %s as %s\n"), path
,
1583 argv
[3] = dest_path
;
1585 if (fork_exec_wait(argv
) == 0)
1589 leaf
= strrchr(dest_path
, '/');
1591 leaf
= dest_path
; /* Error? */
1595 g_string_sprintf(message
, "+%s", path
);
1596 g_string_truncate(message
, leaf
- dest_path
);
1599 g_string_sprintf(message
, "m%s", path
);
1605 g_string_sprintf(message
,
1606 _("!ERROR: Failed to move %s as %s\n"),
1615 /* Copy path to dest.
1616 * Check that path not copied into itself.
1618 static gboolean
do_copy(char *path
, char *dest
)
1620 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1622 g_string_sprintf(message
,
1623 _("!ERROR: Can't copy object into itself\n"));
1627 return do_copy2(path
, dest
);
1630 /* Move path to dest.
1631 * Check that path not moved into itself.
1633 static gboolean
do_move(char *path
, char *dest
)
1635 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1637 g_string_sprintf(message
,
1638 _("!ERROR: Can't move/rename object into itself\n"));
1642 return do_move2(path
, dest
);
1645 static gboolean
do_link(char *path
, char *dest
)
1652 leaf
= strrchr(path
, '/');
1654 leaf
= path
; /* Error? */
1658 dest_path
= make_path(dest
, leaf
)->str
;
1662 g_string_sprintf(message
, _("'Linking %s as %s\n"), path
,
1668 g_string_sprintf(message
,
1669 _("?Link %s as %s?"), path
, dest_path
);
1670 if (!reply(from_parent
, FALSE
))
1674 if (symlink(path
, dest_path
))
1683 /* Mount/umount this item (depending on 'mount') */
1684 static void do_mount(guchar
*path
, gboolean mount
)
1686 char *argv
[3] = {NULL
, NULL
, NULL
};
1690 argv
[0] = mount
? "mount" : "umount";
1695 g_string_sprintf(message
,
1696 mount
? _("'Mounting %s\n")
1697 : _("'Unmounting %s\n"),
1703 g_string_sprintf(message
,
1704 mount
? _("?Mount %s?\n")
1705 : _("?Unmount %s?\n"),
1707 if (!reply(from_parent
, FALSE
))
1711 if (fork_exec_wait(argv
) == 0)
1713 g_string_sprintf(message
, "m%s", path
);
1718 g_string_sprintf(message
, _("!ERROR: Mount failed\n"));
1723 /* CHILD MAIN LOOPS */
1725 /* After forking, the child calls one of these functions */
1727 static void usage_cb(gpointer data
)
1729 FilerWindow
*filer_window
= (FilerWindow
*) data
;
1730 Collection
*collection
= filer_window
->collection
;
1732 int left
= collection
->number_selected
;
1734 off_t total_size
= 0;
1736 send_dir(filer_window
->path
);
1741 if (!collection
->items
[i
].selected
)
1743 item
= (DirItem
*) collection
->items
[i
].data
;
1745 do_usage(make_path(filer_window
->path
,
1746 item
->leafname
)->str
,
1747 filer_window
->path
);
1748 g_string_sprintf(message
, "'%s: %s\n",
1750 format_size((unsigned long) size_tally
));
1752 total_size
+= size_tally
;
1756 g_string_sprintf(message
, _("'\nTotal: %s\n"),
1757 format_size((unsigned long) total_size
));
1761 #ifdef DO_MOUNT_POINTS
1762 static void mount_cb(gpointer data
)
1764 GList
*paths
= (GList
*) data
;
1765 gboolean mount_points
= FALSE
;
1767 for (; paths
; paths
= paths
->next
)
1769 guchar
*path
= (guchar
*) paths
->data
;
1771 if (g_hash_table_lookup(mtab_mounts
, path
))
1772 do_mount(path
, FALSE
); /* Unmount */
1773 else if (g_hash_table_lookup(fstab_mounts
, path
))
1774 do_mount(path
, TRUE
); /* Mount */
1778 mount_points
= TRUE
;
1781 g_string_sprintf(message
,
1782 mount_points
? _("'\nDone\n")
1783 : _("!No mount points selected!\n"));
1788 static void delete_cb(gpointer data
)
1790 FilerWindow
*filer_window
= (FilerWindow
*) data
;
1791 Collection
*collection
= filer_window
->collection
;
1793 int left
= collection
->number_selected
;
1796 send_dir(filer_window
->path
);
1801 if (!collection
->items
[i
].selected
)
1803 item
= (DirItem
*) collection
->items
[i
].data
;
1804 if (do_delete(make_path(filer_window
->path
,
1805 item
->leafname
)->str
,
1806 filer_window
->path
))
1808 g_string_sprintf(message
, "+%s", filer_window
->path
);
1814 g_string_sprintf(message
, _("'\nDone\n"));
1818 static void find_cb(gpointer data
)
1820 FilerWindow
*filer_window
= (FilerWindow
*) data
;
1821 Collection
*collection
= filer_window
->collection
;
1823 int left
= collection
->number_selected
;
1826 send_dir(filer_window
->path
);
1831 if (!collection
->items
[i
].selected
)
1833 item
= (DirItem
*) collection
->items
[i
].data
;
1834 do_find(make_path(filer_window
->path
,
1835 item
->leafname
)->str
,
1840 g_string_sprintf(message
, _("'\nDone\n"));
1844 static void chmod_cb(gpointer data
)
1846 FilerWindow
*filer_window
= (FilerWindow
*) data
;
1847 Collection
*collection
= filer_window
->collection
;
1849 int left
= collection
->number_selected
;
1852 send_dir(filer_window
->path
);
1857 if (!collection
->items
[i
].selected
)
1859 item
= (DirItem
*) collection
->items
[i
].data
;
1860 if (item
->flags
& ITEM_FLAG_SYMLINK
)
1862 g_string_sprintf(message
,
1863 _("!'%s' is a symbolic link\n"),
1867 else if (do_chmod(make_path(filer_window
->path
,
1868 item
->leafname
)->str
, NULL
))
1870 g_string_sprintf(message
, "+%s", filer_window
->path
);
1876 g_string_sprintf(message
, _("'\nDone\n"));
1880 static void list_cb(gpointer data
)
1882 GSList
*paths
= (GSList
*) data
;
1886 send_dir((char *) paths
->data
);
1888 if (action_do_func((char *) paths
->data
, action_dest
))
1890 g_string_sprintf(message
, "+%s", action_dest
);
1894 paths
= paths
->next
;
1897 g_string_sprintf(message
, _("'\nDone\n"));
1901 static void add_toggle(GUIside
*gui_side
, guchar
*label
, guchar
*code
)
1905 check
= gtk_check_button_new_with_label(label
);
1906 gtk_object_set_data(GTK_OBJECT(check
), "send-code", code
);
1907 gtk_signal_connect(GTK_OBJECT(check
), "clicked",
1908 button_reply
, gui_side
);
1909 gtk_box_pack_start(GTK_BOX(gui_side
->vbox
), check
, FALSE
, TRUE
, 0);
1913 /* EXTERNAL INTERFACE */
1915 void action_find(FilerWindow
*filer_window
)
1918 Collection
*collection
;
1919 GtkWidget
*hbox
, *label
, *scroller
;
1922 titles
[0] = _("Name");
1923 titles
[1] = _("Directory");
1925 collection
= filer_window
->collection
;
1927 if (collection
->number_selected
< 1)
1929 report_error(PROJECT
, _("You need to select some items "
1930 "to search through"));
1934 if (!last_find_string
)
1935 last_find_string
= g_strdup("'core'");
1937 new_entry_string
= last_find_string
;
1938 gui_side
= start_action(filer_window
, find_cb
, FALSE
);
1942 gui_side
->show_info
= TRUE
;
1944 scroller
= gtk_scrolled_window_new(NULL
, NULL
);
1945 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller
),
1946 GTK_POLICY_NEVER
, GTK_POLICY_ALWAYS
);
1947 gtk_box_pack_start(GTK_BOX(gui_side
->vbox
), scroller
, TRUE
, TRUE
, 4);
1948 gui_side
->results
= gtk_clist_new_with_titles(
1949 sizeof(titles
) / sizeof(*titles
), titles
);
1950 gtk_clist_column_titles_passive(GTK_CLIST(gui_side
->results
));
1951 gtk_widget_set_usize(gui_side
->results
, 100, 100);
1952 gtk_clist_set_column_width(GTK_CLIST(gui_side
->results
), 0, 100);
1953 gtk_clist_set_selection_mode(GTK_CLIST(gui_side
->results
),
1954 GTK_SELECTION_SINGLE
);
1955 gtk_container_add(GTK_CONTAINER(scroller
), gui_side
->results
);
1956 gtk_box_set_child_packing(GTK_BOX(gui_side
->vbox
),
1957 gui_side
->log_hbox
, FALSE
, TRUE
, 4, GTK_PACK_START
);
1958 gtk_signal_connect(GTK_OBJECT(gui_side
->results
), "select_row",
1959 GTK_SIGNAL_FUNC(select_row_callback
), gui_side
);
1961 hbox
= gtk_hbox_new(FALSE
, 0);
1962 label
= gtk_label_new(_("Expression:"));
1963 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, TRUE
, 4);
1964 gui_side
->default_string
= &last_find_string
;
1965 gui_side
->entry
= gtk_entry_new();
1966 gtk_widget_set_style(gui_side
->entry
, fixed_style
);
1967 gtk_entry_set_text(GTK_ENTRY(gui_side
->entry
), last_find_string
);
1968 gtk_editable_select_region(GTK_EDITABLE(gui_side
->entry
), 0, -1);
1969 gtk_widget_set_sensitive(gui_side
->entry
, FALSE
);
1970 gtk_box_pack_start(GTK_BOX(hbox
), gui_side
->entry
, TRUE
, TRUE
, 4);
1971 gtk_signal_connect(GTK_OBJECT(gui_side
->entry
), "changed",
1972 entry_changed
, gui_side
);
1973 gtk_box_pack_start(GTK_BOX(gui_side
->vbox
), hbox
, FALSE
, TRUE
, 4);
1974 gtk_box_pack_start(GTK_BOX(hbox
),
1975 new_help_button(show_condition_help
, NULL
),
1978 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), _("Find"));
1979 gtk_window_set_focus(GTK_WINDOW(gui_side
->window
), gui_side
->entry
);
1980 gtk_signal_connect_object(GTK_OBJECT(gui_side
->entry
), "activate",
1981 gtk_button_clicked
, GTK_OBJECT(gui_side
->quiet
));
1982 number_of_windows
++;
1983 gtk_widget_show_all(gui_side
->window
);
1986 /* Count disk space used by selected items */
1987 void action_usage(FilerWindow
*filer_window
)
1990 Collection
*collection
;
1992 collection
= filer_window
->collection
;
1994 if (collection
->number_selected
< 1)
1996 report_error(PROJECT
,
1997 _("You need to select some items to count"));
2001 gui_side
= start_action(filer_window
, usage_cb
, TRUE
);
2005 gui_side
->show_info
= TRUE
;
2007 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), _("Disk Usage"));
2008 number_of_windows
++;
2009 gtk_widget_show_all(gui_side
->window
);
2012 /* Mount/unmount listed items (paths).
2013 * Free the list after this function returns.
2015 void action_mount(GList
*paths
)
2017 #ifdef DO_MOUNT_POINTS
2020 gui_side
= start_action(paths
, mount_cb
, o_auto_mount
);
2024 gtk_window_set_title(GTK_WINDOW(gui_side
->window
),
2025 _("Mount / Unmount"));
2026 number_of_windows
++;
2027 gtk_widget_show_all(gui_side
->window
);
2029 report_error(PROJECT
,
2030 _("ROX-Filer does not yet support mount points on your "
2032 #endif /* DO_MOUNT_POINTS */
2035 /* Deletes all selected items in the window */
2036 void action_delete(FilerWindow
*filer_window
)
2039 Collection
*collection
;
2041 collection
= filer_window
->collection
;
2043 if (collection
->number_selected
< 1)
2045 report_error(PROJECT
,
2046 _("You need to select some items to delete"));
2050 gui_side
= start_action(filer_window
, delete_cb
, o_auto_delete
);
2054 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), _("Delete"));
2055 add_toggle(gui_side
,
2056 _("Force - don't confirm deletion of non-writeable items"),
2058 add_toggle(gui_side
,
2059 _("Brief - only log directories being deleted"),
2062 number_of_windows
++;
2063 gtk_widget_show_all(gui_side
->window
);
2066 /* Change the permissions of the selected items */
2067 void action_chmod(FilerWindow
*filer_window
)
2070 Collection
*collection
;
2071 GtkWidget
*hbox
, *label
, *combo
;
2072 static GList
*presets
= NULL
;
2074 collection
= filer_window
->collection
;
2076 if (collection
->number_selected
< 1)
2078 report_error(PROJECT
,
2079 _("You need to select the items "
2080 "whose permissions you want to change"));
2086 presets
= g_list_append(presets
,
2087 _("a+x (Make executable/searchable)"));
2088 presets
= g_list_append(presets
,
2089 _("a-x (Make non-executable/non-searchable)"));
2090 presets
= g_list_append(presets
,
2091 _("u+rw (Give owner read+write)"));
2092 presets
= g_list_append(presets
,
2093 _("go-rwx (Private - owner access only)"));
2094 presets
= g_list_append(presets
,
2095 _("go=u-w (Public access, not write)"));
2098 if (!last_chmod_string
)
2099 last_chmod_string
= g_strdup((guchar
*) presets
->data
);
2100 new_entry_string
= last_chmod_string
;
2101 gui_side
= start_action(filer_window
, chmod_cb
, FALSE
);
2105 add_toggle(gui_side
,
2106 _("Brief - don't list processed files"), "B");
2107 add_toggle(gui_side
,
2108 _("Recurse - also change contents of subdirectories"), "R");
2110 hbox
= gtk_hbox_new(FALSE
, 0);
2111 label
= gtk_label_new(_("Command:"));
2112 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, TRUE
, 4);
2113 gui_side
->default_string
= &last_chmod_string
;
2115 combo
= gtk_combo_new();
2116 gtk_combo_disable_activate(GTK_COMBO(combo
));
2117 gtk_combo_set_use_arrows_always(GTK_COMBO(combo
), TRUE
);
2118 gtk_combo_set_popdown_strings(GTK_COMBO(combo
), presets
);
2120 gui_side
->entry
= GTK_COMBO(combo
)->entry
;
2121 gtk_entry_set_text(GTK_ENTRY(gui_side
->entry
), last_chmod_string
);
2122 gtk_editable_select_region(GTK_EDITABLE(gui_side
->entry
), 0, -1);
2123 gtk_widget_set_sensitive(gui_side
->entry
, FALSE
);
2124 gtk_box_pack_start(GTK_BOX(hbox
), combo
, TRUE
, TRUE
, 4);
2125 gtk_signal_connect(GTK_OBJECT(gui_side
->entry
), "changed",
2126 entry_changed
, gui_side
);
2127 gtk_box_pack_start(GTK_BOX(gui_side
->vbox
), hbox
, FALSE
, TRUE
, 0);
2128 gtk_box_pack_start(GTK_BOX(hbox
),
2129 new_help_button(show_chmod_help
, NULL
),
2132 gtk_window_set_focus(GTK_WINDOW(gui_side
->window
), gui_side
->entry
);
2133 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), _("Permissions"));
2134 gtk_signal_connect_object(GTK_OBJECT(gui_side
->entry
), "activate",
2135 gtk_button_clicked
, GTK_OBJECT(gui_side
->yes
));
2137 number_of_windows
++;
2138 gtk_widget_show_all(gui_side
->window
);
2141 /* If leaf is NULL then the copy has the same name as the original */
2142 void action_copy(GSList
*paths
, char *dest
, char *leaf
)
2148 action_do_func
= do_copy
;
2149 gui_side
= start_action(paths
, list_cb
, o_auto_copy
);
2153 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), _("Copy"));
2154 number_of_windows
++;
2155 gtk_widget_show_all(gui_side
->window
);
2158 /* If leaf is NULL then the file is not renamed */
2159 void action_move(GSList
*paths
, char *dest
, char *leaf
)
2165 action_do_func
= do_move
;
2166 gui_side
= start_action(paths
, list_cb
, o_auto_move
);
2170 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), _("Move"));
2171 number_of_windows
++;
2172 gtk_widget_show_all(gui_side
->window
);
2175 void action_link(GSList
*paths
, char *dest
)
2180 action_do_func
= do_link
;
2181 gui_side
= start_action(paths
, list_cb
, o_auto_link
);
2185 gtk_window_set_title(GTK_WINDOW(gui_side
->window
), _("Link"));
2186 number_of_windows
++;
2187 gtk_widget_show_all(gui_side
->window
);
2190 void action_init(void)
2192 options_sections
= g_slist_prepend(options_sections
, &options
);
2193 option_register("action_auto_quiet", action_auto_quiet
);