1 #ifdef COPYRIGHT_INFORMATION
2 #include "gplv3.h"
3 #endif
4 #include "primary-internal.h"
5 /*
6  * Copyright (C) 2002-2012 Edscott Wilson Garcia
7  * EMail: edscott@users.sf.net
8  *
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program;
22  */
23 
24 // All these functions are thread called. GDK mutex must be
25 // locked if instruction set requires this mutex.
26 
27 
28 // XXX duplicate and symlink could be multiple selection
29 
30 
31 
32 // These callbacks will be processed by keybindings and showed in the
33 // keybindings listing. If a menu option is not listed here, then it will
34 // not be subject to a keybinding, nor a keybinding modification.
35 static
36 RodentCallback menu_callback_v[]={
37     // F keys
38  HELP_CALLBACK,
39  SETTINGS_CALLBACK,
40  MENU_CALLBACK,
41  TERMINAL_CALLBACK,
42  RELOAD_CALLBACK,
43  RUN_CALLBACK,
44  SEARCH_CALLBACK,
45  DIFFERENCES_CALLBACK,
46 // ADD_BOOKMARK_CALLBACK,
47 // REMOVE_BOOKMARK_CALLBACK,
48  CASE_SORT_CALLBACK,
49  TOGGLE_BOOKMARK_CALLBACK,
50  // ctrl F keys
51  SORT_ASCENDING_CALLBACK,
52  SORT_DESCENDING_CALLBACK,
53  NAME_SORT_CALLBACK,
54  TYPE_SORT_CALLBACK,
55  DATE_SORT_CALLBACK,
56  SIZE_SORT_CALLBACK,
57  OWNER_SORT_CALLBACK,
58  GROUP_SORT_CALLBACK,
59  MODE_SORT_CALLBACK,
60  KEYBINDINGS_CALLBACK,
61 //
62  NEW_FILE_CALLBACK,
63  NEWDIR_CALLBACK,
64  BCRYPT_CALLBACK,
65  RENAME_CALLBACK,
66  DUPLICATE_CALLBACK,
67  SYMLINK_CALLBACK,
68  TOUCH_CALLBACK,
69  PROPERTIES_CALLBACK,
70  SELECT_ALL_CALLBACK,
71  SELECT_INVERT_CALLBACK,
72  SELECT_BYFILTER_CALLBACK,
73  UNSELECT_BYFILTER_CALLBACK,
74  UNSELECT_ALL_CALLBACK,
75  NEW_TAB_CALLBACK,
76  NEW_WINDOW_CALLBACK,
77  SHOW_HIDDEN_CALLBACK,
78  SHOW_BACKUP_CALLBACK,
79  PREVIEW_IMAGES_CALLBACK,
80  COMPACT_ICONSIZE_CALLBACK,
81  TINY_ICONSIZE_CALLBACK,
82  NORMAL_ICONSIZE_CALLBACK,
83  BIG_ICONSIZE_CALLBACK,
84  HUGE_ICONSIZE_CALLBACK,
85  PLUS_ICONSIZE_CALLBACK,
86  MINUS_ICONSIZE_CALLBACK,
87  ABOUT_CALLBACK,
88  JUMP_TO_CALLBACK,
89  GOTO_HOST_CALLBACK,
90  GOTO_HOME_CALLBACK,
91  GO_UP_CALLBACK,
92  GO_BACK_CALLBACK,
93  GO_FORWARD_CALLBACK,
94  CUT_CALLBACK,
95  COPY_CALLBACK,
96  PASTE_CALLBACK,
97  REMOVE_CALLBACK,
98 // AUTOTYPE_CALLBACK,
99 // AUTOTYPE_R_CALLBACK,
100  OPEN_WITH_CALLBACK,
101  FIND_CALLBACK,
102  MOUNT_CALLBACK,
103  UNMOUNT_CALLBACK,
104  CLOSE_CALLBACK,
105  LS_CALLBACK,
106  NULL_CALLBACK
107 };
108 
109 static RodentCallback*
get_menu_callback_p(gint menu_enum)110 get_menu_callback_p(gint menu_enum){
111     gint i;
112     // Check if menu_enum is defined in menu_callback_v
113     for (i=0; menu_callback_v[i].function_id >= 0; i++){
114 	if (menu_enum==menu_callback_v[i].function_id) {
115             // Now check whether function_id is valid
116             if (menu_callback_v[i].function_id >= ENUM_CALLBACKS) return NULL;
117 	    return &(menu_callback_v[i]);
118 	}
119     }
120     return NULL;
121 }
122 
123 static gboolean
is_valid_view_entry(widgets_t * widgets_p,gint menu_enum)124 is_valid_view_entry(widgets_t *widgets_p, gint menu_enum){
125     view_t *view_p = widgets_p->view_p;
126     if (!rfm_entry_available(widgets_p, view_p->en)) {
127 	RodentCallback *menu_callback_p = get_menu_callback_p(menu_enum);
128 	rfm_show_text(widgets_p);
129 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-warning", NULL);
130 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/blue",
131 		g_strconcat(
132 		    (menu_callback_p->string)?_(menu_callback_p->string):".",
133 		": ", _( "Could not validate the transaction"), "\n",NULL));
134 	NOOP("callback_enter(): view entry is no longer valid\n");
135 	return FALSE;
136     }
137     return TRUE;
138 }
139 
140 static gboolean
is_single_selection(widgets_t * widgets_p,gint menu_enum)141 is_single_selection(widgets_t *widgets_p, gint menu_enum){
142     view_t *view_p = widgets_p->view_p;
143     if (g_slist_length(view_p->selection_list) != 1){
144 	RodentCallback *menu_callback_p = get_menu_callback_p(menu_enum);
145 	rfm_threaded_show_text(widgets_p);
146 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-warning",NULL);
147 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/blue",
148 		g_strconcat((menu_callback_p->string)?_(menu_callback_p->string):".",
149 		": ", _( "No selection available"), "\n",NULL));
150 	return FALSE;
151     }
152     return TRUE;
153 }
154 
155 
156 static gboolean
is_multiple_selection(widgets_t * widgets_p,gint menu_enum)157 is_multiple_selection(widgets_t *widgets_p, gint menu_enum){
158     view_t *view_p = widgets_p->view_p;
159     if (g_slist_length(view_p->selection_list) == 0){
160 	RodentCallback *menu_callback_p = get_menu_callback_p(menu_enum);
161 	rfm_threaded_show_text(widgets_p);
162 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-warning",NULL);
163 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/blue",
164 		g_strconcat(
165 		(menu_callback_p->string)?_(menu_callback_p->string):".",
166 		": ", _( "No group selected"), "\n",NULL));
167 	return FALSE;
168     }
169     return TRUE;
170 }
171 static void
time_out_message(widgets_t * widgets_p,const gchar * path)172 time_out_message(widgets_t *widgets_p, const gchar *path){
173     rfm_threaded_show_text(widgets_p);
174     rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-error",  g_strconcat(path, ": ", NULL));
175     rfm_threaded_diagnostics(widgets_p, "xffm_tag/stderr", g_strconcat(_(strerror(ETIMEDOUT)), "\n", NULL));
176     rfm_global_t *rfm_global_p = rfm_global();
177     rfm_threaded_cursor_reset(rfm_global_p->window);
178     return;
179 }
180 ///////////////////////////////////////////////////////////////////////////////////
181 ///******************************************************************************/
182 //////////////////////////////////////////////////////////////////////////////////
183 static void jump_to (widgets_t *widgets_p);
184 static void open_x(widgets_t *widgets_p);
185 static void
open_with(widgets_t * widgets_p,record_entry_t * en)186 open_with (widgets_t *widgets_p, record_entry_t * en) {
187     /* open with */
188     gchar *command=NULL;
189     gchar *command_fmt=NULL;
190     NOOP ("open_with()... \n");
191 
192     if(!en || !en->path) {
193         NOOP ("OPEN: open_with !en || !en->path\n");
194         return;
195     }
196 
197     gchar *wd = g_path_get_dirname (en->path);
198     if (!rfm_g_file_test_with_wait (wd, G_FILE_TEST_EXISTS)){
199 	 time_out_message(widgets_p, wd);
200 	 g_free(wd);
201 	 wd = g_strdup(g_get_home_dir());
202      }
203 
204     g_free (widgets_p->workdir);
205     widgets_p->workdir = wd;
206 
207     // Here we take special consideration for shell scripts.
208     // Shell scripts will be editable files, therefore will
209     // have an associated mime_command to open the editor.
210     // tests
211 
212     if (!en->mimetype) en->mimetype=MIME_type (en->path, en->st);
213     if(!en->mimemagic){
214 	if (IS_LOCAL_TYPE(en->type) && !en->mimemagic) {
215 	    en->mimemagic = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_magic", "mime_function");
216 	    if (!en->mimemagic) en->mimemagic = g_strdup(_("unknown"));
217 	}
218 	else en->mimemagic = g_strdup(_("unknown"));
219     }
220 
221     if(!en->filetype) {
222 	if (IS_LOCAL_TYPE(en->type)) {
223 	    en->filetype = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_file", "mime_function");
224 	    if (!en->filetype) en->filetype = g_strdup(_("unknown"));
225 	}
226 	else en->filetype = g_strdup(_("unknown"));
227     }
228 
229     command_fmt = MIME_command (en->mimetype);
230     NOOP ("OPEN: command_fmt(%s) = %s\n", en->mimetype, command_fmt);
231     if(!command_fmt) {
232         command_fmt = MIME_command (en->mimemagic);
233     }
234 
235     gboolean is_script= ((en->mimetype && strstr (en->mimetype, "/x-sh")) ||
236 			 (en->mimemagic && strstr (en->mimemagic, "/x-sh")) ||
237 		 (en->mimetype && strstr (en->mimetype, "/x-shellscript")) ||
238 		 (en->mimemagic && strstr (en->mimemagic, "/x-shellscript")) ||
239 			 (en->mimetype && strstr (en->mimetype, "/x-csh")) ||
240 			 (en->mimemagic && strstr (en->mimemagic, "/x-csh")) ||
241 			 (en->mimetype && strstr (en->mimetype, "/x-perl")) ||
242 			 (en->mimemagic && strstr (en->mimemagic, "/x-perl")) 			 );
243     if (is_script && !IS_EXE_TYPE(en->type)){
244 	g_free(command_fmt);
245 	command_fmt = NULL;
246     }
247 
248     // for default editor...
249     gchar *text_editor = NULL;
250     if(!command_fmt) {
251 	text_editor = rodent_get_text_editor(en);
252 	NOOP ("OPEN: text_editor = %s\n", text_editor);
253 	if(text_editor) {
254 	    /* OK to apply an editor */
255 	    command_fmt = g_strconcat(text_editor, " ", NULL);
256 	}
257     }
258 
259     //command_fmt=get_command_fmt(en);
260     if (is_script) {
261 	rfm_threaded_show_text(widgets_p);
262 	if (!IS_EXE_TYPE(en->type)){
263 	    rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-warning",
264 		    g_strconcat(en->path, "\n", NULL));
265 	    rfm_threaded_diagnostics(widgets_p, "xffm_tag/stderr",
266 		    g_strconcat(_("The program exists, but is not executable.\nPlease check your installation and/or install the binary properly."),
267 		    "\n", NULL));
268 	    rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-info", NULL);
269 	    gchar *text=g_strdup_printf (_("Open with %s"), _("Text Editor"));
270 	    gchar *base=g_path_get_basename(en->path);
271 	    rfm_threaded_diagnostics(widgets_p, "xffm_tag/green", g_strconcat(text, ": ", base, "\n", NULL));
272 	    g_free(base);
273 	    g_free(text);
274 	}
275     }
276 
277     NOOP ("open_with(): magic=%s, mime=%s, command_fmt=%s, editor=%s\n",
278 	    en->mimemagic, en->mimetype, command_fmt, text_editor);
279     g_free(text_editor);
280 
281     if(command_fmt) {
282         command = MIME_mk_command_line (command_fmt, en->path);
283         TRACE( "OPEN: command = %s\n", command);
284 
285         RFM_THREAD_RUN2ARGV (widgets_p, command, FALSE);
286         g_free (command);
287         g_free (command_fmt);
288     } else {
289 	open_x(widgets_p);
290         //rodent_open_with_activate (NULL, (gpointer) widgets_p);
291     }
292     return;
293 }
294 
295 
296 // This is used by the go back callback
297 static void
pop_view_go_history(view_t * view_p)298 pop_view_go_history (view_t * view_p) {
299     GList *last;
300     if(!view_p->go_list)
301         return;
302     last = g_list_last (view_p->go_list);
303     if(!last) {
304         g_list_free (view_p->go_list);
305         view_p->go_list = NULL;
306         return;
307     }
308     view_p->go_list = g_list_remove (view_p->go_list, last->data);
309     if(!g_list_length (view_p->go_list)) {
310         g_list_free (view_p->go_list);
311         view_p->go_list = NULL;
312         return;
313     }
314     return;
315 }
316 
317 // This is used by the goto callback
get_jumpto_dir(widgets_t * widgets_p)318 static gchar *get_jumpto_dir(widgets_t *widgets_p){
319    if (g_thread_self() == rfm_get_gtk_thread()){
320 	g_error("get_jumpto_dir() is a thread function\n");
321     }
322     view_t *view_p = widgets_p->view_p;
323     gchar *f = g_build_filename (GOTO_DBH_FILE, NULL);
324     gchar *response = get_response_history ( _("Go To"), _("Path"),
325 	    NULL, // extra_text
326 	    f,
327 	    NULL, NULL, NULL, NULL,
328             GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
329             g_get_home_dir (),
330 	    MATCH_FILE);
331     g_free (f);
332 
333     NOOP("dialog returned with %s\n", response);
334     if (!response) return NULL;
335     gchar *choice = response;
336 
337     g_strstrip(choice);
338     if (strlen(choice)==0) {
339 	g_free(choice);
340 	return NULL;
341     }
342     if (g_path_is_absolute(choice)){
343 	if (!rfm_g_file_test_with_wait (choice, G_FILE_TEST_EXISTS)){
344 	   time_out_message(widgets_p, choice);
345 	   g_free(choice);
346 	   return NULL;
347 	}
348     } else {
349 	// make path absolute
350 	const gchar *dirname;
351 	if (view_p->en && view_p->en->path) dirname = view_p->en->path;
352 	else dirname = g_get_home_dir();
353 	gchar *fullpath = g_build_filename(dirname, choice, NULL);
354 	if (!rfm_g_file_test_with_wait (fullpath, G_FILE_TEST_EXISTS)){
355 	   time_out_message(widgets_p, fullpath);
356 	   g_free(fullpath);
357 	   g_free(choice);
358 	   return NULL;
359 	}
360 	g_free(fullpath);
361     }
362 
363 
364     if(!rfm_g_file_test_with_wait (choice, G_FILE_TEST_IS_DIR)) {
365 	gchar *text=g_strdup_printf(_("%s does not exist."), choice);
366 	rfm_confirm (widgets_p,GTK_MESSAGE_ERROR, text, NULL, NULL);
367 	g_free(choice);
368 	g_free(text);
369         return NULL;
370     }
371     else if(chdir (choice) < 0) {
372         rfm_threaded_show_text(widgets_p);
373         rfm_threaded_diagnostics (widgets_p, "xffm/stock_dialog-error", NULL);
374         rfm_threaded_diagnostics (widgets_p, "xffm_tag/stderr", g_strconcat(choice, ": ", strerror (errno), "\n", NULL));
375 	g_free(choice);
376 	return NULL;
377     }
378     g_free(choice);
379     gchar *g = g_get_current_dir ();
380     SETWD();
381     return g;
382 }
383 
384 /*****************************************************************************/
385 
386 // Used by execute()
387 static gchar *
get_command_fmt(record_entry_t * en)388 get_command_fmt(record_entry_t *en) {
389     gchar *command_fmt = MIME_command (en->mimetype);
390     if(!command_fmt) {
391         command_fmt = MIME_command (en->mimemagic);
392     }
393     gboolean is_text = ((en->mimetype && strstr (en->mimetype, "text/")) ||
394                         (en->mimemagic && strstr (en->mimemagic, "text/")) ||
395                         (en->filetype && strstr (en->filetype, "text")));
396     if(!command_fmt && is_text && getenv ("EDITOR_CMD") && strlen (getenv ("EDITOR_CMD"))) {
397         command_fmt = g_strdup (getenv ("EDITOR_CMD"));
398     }
399     return command_fmt;
400 }
401 
402 // Used by execute()
403 static gchar *
strip_path(gchar * command_fmt,const gchar * path)404 strip_path(gchar *command_fmt, const gchar *path){
405     if (!path) return command_fmt;
406     NOOP("stipping %s\n", command_fmt);
407     if (strstr(command_fmt, path)){
408         gchar *end = strstr(command_fmt,path) + strlen(path);
409         *strstr(command_fmt, path) = 0;
410         gchar *g = g_strconcat(command_fmt, "%","s",end, NULL);
411         g_free(command_fmt);
412         command_fmt=g;
413         NOOP("stipped %s\n", command_fmt);
414         return command_fmt;
415     }
416     // What if the path is quoted or escaped or both
417     gchar *esc_path = rfm_esc_string (path);
418     if (strstr(command_fmt, esc_path)){
419         command_fmt = strip_path(command_fmt, esc_path);
420     }
421     g_free(esc_path);
422     return command_fmt;
423 }
424 
425 typedef struct execute_t{
426     widgets_t *widgets_p;
427     GSList *list;
428 } execute_t;
429 
430 // Used by run and open-with callbacks
431 // This opens the confirmation or user input dialog.
432 static void *
execute(widgets_t * widgets_p,GSList * selection_list)433 execute (widgets_t *widgets_p, GSList *selection_list) {
434   if (g_thread_self() == rfm_get_gtk_thread()){
435 	g_error("execute() is a thread function\n");
436     }
437 
438     view_t *view_p = widgets_p->view_p;
439     //GSList *selection_list = execute_p->list;
440     gpointer retval=GINT_TO_POINTER(1);
441 
442     gchar *command_fmt=NULL;
443     /* set the working directory */
444     g_free (widgets_p->workdir);
445     if(view_p->en && IS_LOCAL_TYPE(view_p->en->type) && view_p->en->path)
446         widgets_p->workdir = g_strdup (view_p->en->path);
447     else
448         widgets_p->workdir = g_strdup (g_get_home_dir ());
449 
450     TRACE ("execute()...\n");
451     gchar *files = NULL;
452     gchar *files_txt;
453 
454     gchar *first_path=NULL;
455     if(selection_list) {
456 	files_txt = g_strdup_printf (_("Open with %s"),":   \n\n");
457         if(g_slist_length (selection_list)) {
458             gchar *tt,
459              *ttt;
460             files = g_strdup (" ");
461             GSList *tmp = selection_list;
462             for(; tmp; tmp = tmp->next) {
463                 record_entry_t *en = (record_entry_t *) tmp->data;
464                 char *b = g_path_get_basename (en->path);
465                 gchar *q = rfm_utf_string (rfm_chop_excess (b));
466                 tt = g_strconcat (files_txt, q, "\n", NULL);
467                 gchar *esc_path = rfm_esc_string (en->path);
468 		if (!first_path){
469 		    first_path=g_strdup(esc_path);
470 		    command_fmt=get_command_fmt(en);
471 		}
472                 ttt = g_strconcat (files, esc_path, " ", NULL);
473                 g_free (esc_path);
474                 g_free (files_txt);
475                 g_free (q);
476                 g_free (b);
477                 g_free (files);
478                 files_txt = tt;
479                 files = ttt;
480             }
481         }
482     } else {
483 	// no selection
484 	files_txt = g_strdup_printf ("%s \n\n", _("Command:"));
485     }
486     NOOP ("OPEN: files=%s\n", files);
487     NOOP ("OPEN: first_path=%s\n", first_path);
488     gboolean interm = FALSE;
489     gchar *g=NULL;
490     {
491         gchar *f = g_build_filename (RUN_DBH_FILE, NULL);
492         gchar *ff = g_build_filename (RUN_FLAG_FILE, NULL);
493         NOOP (stderr, "RUN_DBH_FILE=%s RUN_FLAG_FILE=%s\n", f, ff);
494 
495 	gchar *title;
496 	if (selection_list) {
497 	    title=g_strdup_printf(_("Open with %s"),"");
498 	} else {
499 	    title=g_strdup(_("Execute Shell Command"));
500 	}
501         g = get_response_history (title,
502 		files_txt,
503 		_("Console: quickly run single commands -- write a command here and press enter."),
504 		f,
505 		first_path,
506 		command_fmt, //NULL, // entry text
507 		ff,
508 		_("Run in Terminal"),
509 		GTK_FILE_CHOOSER_ACTION_OPEN,
510 		"/usr/bin",
511 		MATCH_COMMAND);
512        g_free (f);
513         g_free (ff);
514 	NOOP(stderr, "got: \"%s\"\n", g);
515     }
516     g_free (first_path);
517     g_free (command_fmt);
518 
519     g_free (files_txt);
520     if(!g) {
521         NOOP ("on_open_with_activate... !g\n");
522 	retval=NULL;
523 	goto cleanup;
524     }
525     if(g[strlen (g) + 1])
526         interm = TRUE;
527 
528     if(selection_list) {
529         /* if only one file selected, associate to mimetype...
530 	 * but not default unless no other command available
531 	 * (i.e., append, not prepend)*/
532         if(g_slist_length (selection_list) == 1) {
533 	    record_entry_t *en = selection_list->data;
534 	    if(!en->mimetype || strcmp(en->mimetype, _("unknown"))==0) {
535 		if (IS_LOCAL_TYPE(en->type) && !en->mimemagic) {
536 		    en->mimemagic = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_magic", "mime_function");
537 		    if (!en->mimemagic) en->mimemagic = g_strdup(_("unknown"));
538 		}
539 	    }
540 	    const gchar *type = en->mimetype;
541 	    if (!type || strcmp(type, _("unknown"))==0) type = en->mimemagic;
542             if(type) {
543                 gchar *command_fmt = g_strdup (g);
544                 if(interm) {
545                     gchar *term_command = MIME_mk_terminal_line (command_fmt);
546                     g_free (command_fmt);
547                     command_fmt = term_command;
548                 }
549 		command_fmt = strip_path(command_fmt,en->path);
550                 NOOP(stderr, "OPEN: adding %s --> %s (from %s)\n", type, command_fmt, g);
551 		rfm_rational(RFM_MODULE_DIR,"mime",
552 			(void *)(en->mimetype),
553 			(void *)command_fmt, "mime_append");
554 		// MIME_add would prepend, which is now deprecated:
555 		// MIME_add (view_p->mouse_event.selected_p->en->mimetype, command_fmt);
556 		g_free(command_fmt);
557             }
558         }
559     }
560     gchar *command;
561     if(strstr (g, "%s")) {
562         command = g_strdup_printf (g, (files)?files:"");
563     } else {
564         command = g_strdup_printf ("%s %s", g, (files)?files:"");
565     }
566     g_strstrip(command);
567     g_free(g);
568     NOOP (stderr,"OPEN: command = \"%s\"\n", command);
569     g_free (files);
570 
571     if(widgets_p->diagnostics_window){
572 	if (!rfm_threaded_get_visible(widgets_p->diagnostics_window)){
573 	    rfm_threaded_show_text(widgets_p);
574 	}
575     } else {
576 	rfm_threaded_show_text(widgets_p);
577     }
578 
579     // do the call with argv so that command not saved in lpterm history
580     // (but this is broken when we have pipes or redirection)
581     gboolean shell_it = FALSE;
582     gchar *tokens="|><;&";
583     gchar *c=tokens;
584     for (c=tokens; *c; c++){
585 	if (strchr(command, *c)){
586 	    shell_it=TRUE;
587 	    break;
588 	}
589     }
590     NOOP(stderr, "command = %s (shell=%d)\n", command, shell_it);
591     if (shell_it){
592 	RFM_THREAD_RUN (widgets_p, command, interm);
593     } else {
594 	RFM_THREAD_RUN2ARGV (widgets_p, command, interm);
595     }
596 
597     g_free (command);
598     // Cleanup
599 cleanup:;
600     GSList *list = selection_list;
601     for (; list && list->data; list = list->next){
602 	record_entry_t *en = list->data;
603 	rfm_destroy_entry(en);
604     }
605     if (selection_list) g_slist_free(selection_list);
606     TRACE("execute done...\n");
607     return retval;
608 }
609 
610 
611 static void
rodent_save_workdir_history(char * p)612 rodent_save_workdir_history (char *p) {
613     gchar *f = g_build_filename (WORKDIR_DBH_FILE, NULL);
614     COMBOBOX_save_to_history (f, p);
615     g_free (f);
616 }
617 // Determines the work directory of the command to be executed
618 // to do things like extract a tar file to a selected diretory
619 static gchar *
autofunction_workdir(widgets_t * widgets_p,const gchar * querypath)620 autofunction_workdir (widgets_t *widgets_p, const gchar * querypath) {
621     if (g_thread_self() == rfm_get_gtk_thread()){
622 	g_error("autofunction_workdir() is a thread function\n");
623     }
624     view_t *view_p = widgets_p->view_p;
625     static gchar *last_dir = NULL;
626     gchar *g=NULL;
627 
628     if (!view_p->en) return NULL;
629     if(querypath) {
630         gchar *f = g_build_filename (WORKDIR_DBH_FILE, NULL);
631         const gchar *folder;
632         if(view_p->en && view_p->en->path && IS_SDIR(view_p->en->type)) {
633             folder = view_p->en->path;
634         } else {
635             folder = g_get_home_dir ();
636         }
637         NOOP ("COMBO: last_dir is %s\n", last_dir);
638 	//const gchar *default_dir=last_dir;
639 	const gchar *default_dir=NULL;
640 	if (!default_dir) default_dir=view_p->en->path;
641 	if (!rfm_entry_available(widgets_p, view_p->en)) {
642 	    default_dir=g_get_home_dir();
643 	}
644 	g = get_response_history ( _(querypath),
645 			    _("Path"), _("Select directory"),
646 			    f, NULL,
647                             default_dir,
648                             NULL, NULL,
649                             GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
650                             folder,
651 			    MATCH_FILE);
652         g_free (f);
653 
654         if(!g) return NULL;
655 
656 	gboolean exists = g_file_test (g, G_FILE_TEST_EXISTS);
657 	gboolean isdir = g_file_test (g, G_FILE_TEST_IS_DIR);
658 
659 
660 	if(exists && !isdir) {
661             rfm_threaded_status (widgets_p, "xffm/stock_dialog-warning", g_strdup(strerror (ENOTDIR)));
662 	    g_free(g);
663             return NULL;
664         }
665         if(!exists) {
666             gchar *b = g_strdup_printf ("%s: %s\n%s...", g,
667                                         strerror (ENOENT),_("Create New Folder"));
668             if(!rfm_confirm (widgets_p, GTK_MESSAGE_QUESTION, b, _("Cancel"), NULL)) {
669 		g_free(g);
670                 g_free (b);
671                 return NULL;
672             }
673             g_free (b);
674             if(g_mkdir_with_parents (g, 0750) < 0) {
675 		rfm_threaded_show_text(widgets_p);
676 		rfm_threaded_diagnostics (widgets_p, "xffm/stock_dialog-error", NULL);
677 		rfm_threaded_status (widgets_p, "xffm_tag/stderr", g_strconcat(g, ": ", strerror (errno), "\n", NULL));
678 		g_free(g);
679                 return NULL;
680             }
681         }
682 
683 
684         g_free (last_dir);
685         last_dir = g_strdup (g);
686         NOOP ("COMBO: setting last_dir to %s\n", last_dir);
687         if(isdir)
688             rodent_save_workdir_history (widgets_p->workdir);
689         else {
690             rfm_threaded_show_text(widgets_p);
691             rfm_threaded_diagnostics (widgets_p, "xffm/stock_dialog-error", NULL);
692             rfm_threaded_status (widgets_p, "xffm_tag/stderr", g_strconcat(g, ": ", strerror (errno), "\n", NULL));
693 	    g_free(g);
694             return NULL;
695         }
696         return g;
697     }
698 
699     g_free(g);
700     return NULL;
701 }
702 
703 static int
select_all_view(view_t * view_p,gboolean invert)704 select_all_view (view_t * view_p, gboolean invert) {
705     rfm_global_t *rfm_global_p = rfm_global();
706     population_t **population_pp;
707     int items = 0;
708     if(!view_p || !view_p->en)
709         return items;
710     rfm_cursor_wait (rfm_global_p->window);
711     population_pp = view_p->population_pp;
712     for(; population_pp && *population_pp; population_pp++) {
713         if((*population_pp)->en == NULL)
714             continue;
715         if(IS_DUMMY_TYPE ((*population_pp)->en->type))
716             continue;
717         items++;
718         NOOP ("selected item %d", items);
719         //
720 
721 	if (invert) {
722 	    if ((*population_pp)->flags & POPULATION_SELECTED) {
723 		//no gtk in this function:
724 		rfm_unselect_pixbuf (view_p, *population_pp);
725 	    } else {
726 		//no gtk in this function:
727 		rfm_select_pixbuf (view_p, *population_pp);
728 	    }
729 	    rfm_expose_item (view_p, *population_pp);
730 	} else {
731 	    if (!((*population_pp)->flags & POPULATION_SELECTED)){
732 		//no gtk in this function:
733 		rfm_select_pixbuf (view_p, *population_pp);
734 		//all expose issues are invoked in main context:
735 		rfm_expose_item (view_p, *population_pp);
736 	    }
737 	}
738 
739     }
740     rfm_threaded_cursor_reset (rfm_global_p->window);
741     return items;
742 }
743 
744 enum {
745     END_MATCH,
746     START_MATCH,
747     TOMATO_IN_SANDWICH_MATCH,
748     BREAD_ON_SANDWICH_MATCH,
749     EXACT_MATCH
750 };
751 
752 static gint
select_byfilter_view(widgets_t * widgets_p,const gchar * select_filter,gboolean select_it)753 select_byfilter_view (widgets_t *widgets_p, const gchar * select_filter, gboolean select_it) {
754     rfm_global_t *rfm_global_p = rfm_global();
755 
756     view_t *view_p = widgets_p->view_p;
757     population_t **population_pp;
758     gint items = 0;
759     if(!view_p || !view_p->en) return items;
760     if(!select_filter || !strlen (select_filter)) return items;
761     if(strcmp (select_filter, "*") == 0) return select_all_view (view_p, FALSE);
762     rfm_threaded_cursor_wait (rfm_global_p->window);
763 
764     gchar *filter = g_strdup (select_filter);
765     memset (filter, 0, strlen (select_filter));
766     int j = 0,
767         i = 0,
768         caso;
769     for(; i < strlen (select_filter); i++) {
770         if(select_filter[i] != '*')
771             filter[j++] = select_filter[i];
772     }
773 
774     if(select_filter[0] == '*' && select_filter[strlen (select_filter) - 1] == '*') {
775         caso = TOMATO_IN_SANDWICH_MATCH;
776     } else if(select_filter[0] == '*') {
777         caso = END_MATCH;
778     } else if(select_filter[strlen (select_filter) - 1] == '*') {
779         caso = START_MATCH;
780     } else if(strchr (select_filter, (int)'*')) {
781         caso = BREAD_ON_SANDWICH_MATCH;
782     } else {
783         caso = EXACT_MATCH;
784     }
785 
786     //rodent_unselect_all_pixbuf (view_p);
787     population_pp = view_p->population_pp;
788     for(; population_pp && *population_pp; population_pp++) {
789         gchar *f;
790         gboolean match = FALSE;
791         if((*population_pp)->en == NULL)
792             continue;
793         if((*population_pp)->en->path == NULL)
794             continue;
795         if(IS_DUMMY_TYPE ((*population_pp)->en->type))
796             continue;
797         f = g_path_get_basename ((*population_pp)->en->path);
798         gchar *p = strcasestr (f, filter);
799 
800         if(p && caso == END_MATCH) {
801             gchar *pp;
802             do {
803                 pp = p;
804                 p = strcasestr (p + 1, filter);
805             }
806             while(p);
807             p = pp;
808         }
809 
810         if(p) {
811             NOOP ("p=%s, filter=%s\n", p, filter);
812             switch (caso) {
813             case TOMATO_IN_SANDWICH_MATCH:
814                 match = TRUE;
815                 break;
816             case END_MATCH:
817                 if(p[strlen (filter)] == 0)
818                     match = TRUE;
819                 break;
820             case START_MATCH:
821                 if(p == f)
822                     match = TRUE;
823                 break;
824             case EXACT_MATCH:
825                 if(strlen (p) == strlen (filter))
826                     match = TRUE;
827                 break;
828             case BREAD_ON_SANDWICH_MATCH:
829                 //not implemented. Need to do 2 matches.
830                 //break;
831             default:           //START_END_MATCH
832                 match = TRUE;
833                 break;
834 
835             }
836         }
837         if(match) {
838             items++;
839             if (select_it) rfm_select_pixbuf (view_p, *population_pp);
840 	    else rfm_unselect_pixbuf (view_p, *population_pp);
841 	    rfm_expose_item (view_p, *population_pp);
842         }
843         g_free (f);
844     }
845     rfm_threaded_cursor_reset (rfm_global_p->window);
846     gchar *plural_text=g_strdup_printf (ngettext ("%'u item", "%'u items",
847                                                items),items);
848     gchar *g = g_strdup_printf ("%s: %s", _("Selection"), plural_text);
849     g_free(plural_text);
850 
851     rfm_threaded_status (&(view_p->widgets), "xffm/stock_dialog-info", g );
852     g_free (filter);
853 
854     return items;
855 }
856 
857 static void
unselect_all(widgets_t * widgets_p)858 unselect_all (widgets_t *widgets_p) {
859     view_t *view_p = widgets_p->view_p;
860     rodent_unselect_all_pixbuf (view_p);
861 }
862 
863 
864 static void
private_mount(widgets_t * widgets_p,gint mounted)865 private_mount (widgets_t *widgets_p, gint mounted) {
866     rfm_global_t *rfm_global_p = rfm_global();
867     view_t *view_p = widgets_p->view_p;
868     record_entry_t *en = view_p->selection_list->data;
869     NOOP ("MOUNT: private_mount %d (0x%x)\n", mounted, GPOINTER_TO_INT(view_p));
870     if(!en || !en->path) {
871         DBG ("no entry to mount\n");
872         return;
873     }
874     if(mounted){
875         SET_MOUNTED_TYPE (en->type);
876     } else{
877         UNSET_MOUNTED_TYPE (en->type);
878     }
879     rfm_threaded_show_text(widgets_p);
880     gchar *text;
881     const gchar *icon;
882     if (mounted){
883 	icon = "xffm/emblem_redball/compositeC/stock_go-up";
884 	text = g_strdup_printf(_("Unmounting %s"), en->path);
885     } else {
886 	icon = "xffm/emblem_greenball/compositeC/stock_go-up";
887 	text = g_strdup_printf(_("Mounting %s"), en->path);
888     }
889     rfm_threaded_diagnostics(widgets_p, icon, g_strconcat(text, "\n", NULL));
890     FSTAB_fstab_mount (widgets_p, en);
891     g_free(text);
892 
893 
894     unselect_all(widgets_p);
895     rfm_threaded_cursor_reset (rfm_global_p->window);
896 
897     NOOP ("MOUNT: private_mount done\n");
898     return;
899 }
900 
901 
902 static gint
gui_pasteboard_list(GList ** list_p)903 gui_pasteboard_list (GList ** list_p) {
904 
905     // client side pasteboard, via MIT-shm
906     gchar *b=rfm_get_paste_buffer();
907     if((!b) || (!strlen (b))) {
908       no_pasteboard:
909 	g_free(b);
910 	return 0;
911     }
912     gboolean cut;
913     gchar *word;
914     if((word = strtok (b, ":")) == NULL)
915         goto no_pasteboard;
916     if(!strstr (word, "#xfvalid_buffer"))
917         goto no_pasteboard;
918     if((word = strtok (NULL, ":")) == NULL)
919         goto no_pasteboard;
920     if(strstr (word, "cut"))
921         cut = TRUE;
922     else
923         cut = FALSE;
924     if((word = strtok (NULL, ":")) == NULL)
925         goto no_pasteboard;
926     //src_host = g_strdup(word);
927 
928     word = word + strlen (word) + 1;
929     if(word[0] == '\n') {
930         word++;
931         if(word[0] == 0)
932             goto no_pasteboard;
933     } else {
934         if((word = strtok (NULL, "\n")) == NULL)
935             goto no_pasteboard;
936         word = word + strlen (word) + 1;
937     }
938 
939     /* create list to send to CreateTmpList */
940     gint retval = rfm_uri_parse_list (word, list_p);
941 
942     g_free (b);
943     if (retval) {
944 	if(cut) retval=1;
945 	else retval= 2;
946     }
947     return retval;
948 }
949 
950 static gint
gui_pasteboard_transfer(widgets_t * widgets_p,record_entry_t * t_en,GList * list,gboolean cut,gboolean symlink)951 gui_pasteboard_transfer (widgets_t * widgets_p,
952                          record_entry_t * t_en,
953 			 GList * list,
954 			 gboolean cut,
955 			 gboolean symlink) {
956     if (!list){
957         g_warning("gui_pasteboard_transfer() list is null\n");
958         return 0;
959     }
960     gchar *url = (gchar *) list->data;
961     if(!url){
962 	DBG("gui_pasteboard_transfer: !url\n");
963         return 0;
964     }
965 
966     if(t_en->module) {
967         NOOP ("PASTE: en->module=%s\n", t_en->module);
968         if(rfm_natural (PLUGIN_DIR, t_en->module, t_en, "valid_drop_site")) {
969             NOOP ("module: valid_drop_site for %s\n", t_en->module);
970             rfm_natural (PLUGIN_DIR, t_en->module, t_en, "set_drop_entry");
971             if(rfm_rational (PLUGIN_DIR, t_en->module, list, widgets_p, "process_drop")) {
972                 NOOP ("module: process_drop ok\n");
973                 /*result=TRUE; */
974             }
975             rfm_void (PLUGIN_DIR, t_en->module, "clear_drop_entry");
976             return 1;
977         }
978     }
979     NOOP ("PASTE: must be local then\n");
980     int mode;
981     if(cut) {
982         mode = TR_MOVE;
983     } else {
984         mode = TR_COPY;
985     }
986     if(symlink) {
987         mode = TR_LINK;
988     }
989 
990     // Only the uploading notice works here...
991     gchar *text=NULL;
992     const gchar *icon=NULL;
993     //gint type=0;
994     gboolean local_target = TRUE;
995     //gboolean local_source = TRUE;
996     //if (!IS_LOCAL_TYPE(type))local_source = FALSE;
997     if (!IS_LOCAL_TYPE(t_en->type))local_target = FALSE;
998     if (!local_target){
999       switch (mode){
1000         case TR_COPY:
1001 	case TR_MOVE:
1002         case TR_COPY_REMOTE:
1003 	case TR_MOVE_REMOTE:
1004 	    icon = "xffm/emblem_network/compositeSE/stock_go-forward";
1005 	    text = g_strdup_printf(_("Uploading file %s"), "...");
1006 	    break;
1007 	default:
1008 	    break;
1009       }
1010     } else {
1011 	// Local target. Test first item of list for remote host.
1012 	const gchar *path = list->data;
1013 	record_entry_t *en = rfm_stat_entry(path, 0);
1014 	if (!IS_LOCAL_TYPE(en->type)) {
1015 	    icon = "xffm/emblem_network/compositeSE/stock_go-back";
1016 	    text = g_strdup_printf(_("Downloading file %s..."), "");
1017 	}
1018 	rfm_destroy_entry(en);
1019    }
1020 
1021 
1022 
1023     if (text) {
1024 	rfm_threaded_diagnostics(widgets_p, "xffm/emblem_network/compositeSE/stock_go-forward", NULL);
1025 	rfm_threaded_diagnostics(widgets_p, icon, NULL);
1026 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/red", g_strconcat(text, "\n", NULL));
1027 	g_free(text);
1028     }
1029     // Here we are already in a threaded environment, so plain cp
1030     // would create an unnecessary extra thread.
1031     // cp (mode, list, t_en->path);
1032     plain_cp(widgets_p, mode, list, t_en->path, FALSE);
1033 
1034     return 1;
1035 }
1036 
1037 
1038 static void
private_paste(widgets_t * widgets_p,view_t * view_p,gboolean symlink)1039 private_paste (widgets_t * widgets_p, view_t * view_p, gboolean symlink) {
1040     gboolean cut;
1041     GList *list = NULL;
1042     record_entry_t *t_en = NULL;
1043     int i;
1044 
1045 
1046 
1047     if((t_en = view_p->en) == NULL){
1048 	DBG("(t_en = view_p->en) == NULL\n");
1049         return;
1050     }
1051 
1052 
1053     if((i = gui_pasteboard_list (&list)) == 0){
1054 	DBG("(i = gui_pasteboard_list (&list)) == 0\n");
1055         return;
1056     }
1057     if(i == 1)
1058         cut = TRUE;
1059     else
1060         cut = FALSE;
1061     i = gui_pasteboard_transfer (widgets_p, t_en, list, cut, symlink);
1062 
1063     list = rfm_uri_free_list (list);
1064 
1065     if(i) {
1066         if(cut){
1067 	    rfm_clear_paste_buffer();
1068 	}
1069     }
1070     return;
1071 }
1072 
1073 static void
gui_pasteboard_copy_cut(widgets_t * widgets_p,gboolean cut,GSList ** paste_list)1074 gui_pasteboard_copy_cut (widgets_t * widgets_p, gboolean cut, GSList ** paste_list) {
1075     gint len;
1076     gchar *buffer;
1077     //gchar *files;
1078     view_t *view_p = widgets_p->view_p;
1079     // clear any previous icon emblems
1080     rodent_clear_cut_icons (view_p);
1081 
1082     if(*paste_list == NULL){
1083 	DBG("*paste_list == NULL\n");
1084         return;
1085     }
1086 
1087     if(cut)
1088         rfm_threaded_status (widgets_p, "xffm/stock_dialog-info", g_strdup(_("Cut")));
1089     else
1090         rfm_threaded_status (widgets_p, "xffm/stock_dialog-info", g_strdup(_("Copy")));
1091 
1092     rfm_clear_paste_buffer();
1093 
1094     len = 1 + strlen ("#xfvalid_buffer:copy:%%:\n");
1095     len += strlen (g_get_host_name ());
1096     GSList *tmp = *paste_list;
1097     for(; tmp; tmp = tmp->next) {
1098         gint addlen;
1099         record_entry_t *en = (record_entry_t *) tmp->data;
1100         addlen = 0;
1101         len += (1 + strlen (en->path) + addlen);
1102     }
1103     buffer = (gchar *)malloc (len * sizeof (char) + 1);
1104     if(!buffer) {
1105         DBG ("rfm: unable to allocate paste buffer\n");
1106         return;
1107     }
1108     sprintf (buffer, "#xfvalid_buffer:%s:%s:\n", (cut) ? "cut" : "copy", g_get_host_name ());
1109     //files = buffer + strlen (buffer);
1110 
1111     for(tmp = *paste_list; tmp; tmp = tmp->next) {
1112         record_entry_t *en = (record_entry_t *) tmp->data;
1113         {
1114             strcat (buffer, en->path);
1115             strcat (buffer, "\n");
1116         }
1117     }
1118     NOOP("dbg:len=%d,strlen=%d,data=%s\n",len,strlen(buffer),buffer);
1119     rfm_store_paste_buffer(buffer, len);
1120     g_free (buffer);
1121     buffer = NULL;
1122 
1123     if(cut)
1124         rfm_threaded_status (widgets_p, "xffm/stock_dialog-info", g_strconcat(_("Cut"), NULL));
1125     else
1126         rfm_threaded_status (widgets_p, "xffm/stock_dialog-info", g_strconcat(_("Copy"), NULL));
1127     //view_p->flags.pasteboard_serial++;
1128     NOOP ("PASTE: view_p->flags.pasteboard_serial=%d\n", view_p->flags.pasteboard_serial);
1129     gchar *value = g_strdup_printf ("%d", view_p->flags.pasteboard_serial + 1);
1130     if (rfm_rational (RFM_MODULE_DIR, "settings", (void *)"RFM_PASTEBOARD_SERIAL", (void *)value, "mcs_set_var") == NULL){
1131         rfm_setenv ("RFM_PASTEBOARD_SERIAL", value, TRUE);
1132         NOOP("cannot set RFM_PASTEBOARD_SERIAL");
1133     }
1134     g_free (value);
1135     rodent_update_cut_icons(view_p);
1136     TRACE("copy-cut calling rodent_expose_all()\n");
1137     //rodent_expose_all (view_p);
1138     rodent_redraw_items (view_p);
1139 }
1140 
1141 static void
copy_cut_callback(widgets_t * widgets_p,gboolean cut)1142 copy_cut_callback (widgets_t *widgets_p, gboolean cut) {
1143 
1144     view_t *view_p = widgets_p->view_p;
1145     if (!rfm_entry_available(widgets_p, view_p->en)) return;
1146     if(!view_p->selection_list) return;
1147 
1148     gui_pasteboard_copy_cut (widgets_p, cut, &(view_p->selection_list));
1149     // unselect stuff if it is cut or copied.
1150     GSList *tmp=view_p->selection_list;
1151     for (;tmp && tmp->data; tmp=tmp->next){
1152 	record_entry_t *en=tmp->data;
1153 	rfm_destroy_entry(en);
1154     }
1155     g_slist_free (view_p->selection_list);
1156     view_p->selection_list = NULL;
1157 
1158     // Mark all population items as unselected.
1159     if(rfm_population_read_lock (view_p, "copy_cut_callback")) {
1160         population_t **pp;
1161         for(pp = view_p->population_pp; pp && *pp; pp++) {
1162             population_t *population_p = *pp;
1163             population_p->flags  &= (POPULATION_SELECTED ^ 0xffffffff);
1164         }
1165         rfm_population_read_unlock (view_p, "copy_cut_callback");
1166     }
1167 
1168 }
1169 static void
paste_callback(widgets_t * widgets_p,gboolean symlink)1170 paste_callback (widgets_t *widgets_p, gboolean symlink) {
1171     view_t *view_p = widgets_p->view_p;
1172     if(!view_p->en)
1173         return;
1174     if (!rfm_entry_available(widgets_p, view_p->en)) return;
1175     //rfm_details->pastepath = view_p->en->path;
1176     private_paste (widgets_p, view_p, symlink);
1177 }
1178 
1179 
1180 ///////////////////////////////////////////////////////////////////////////
1181 ///******************************************************************///
1182 //////////////////////////////////////////////////////////////////////////
1183 
1184 static void
glob_x(widgets_t * widgets_p)1185 glob_x (widgets_t *widgets_p){
1186     NOOP( "glob_x...\n");
1187     gchar *fgr = g_find_program_in_path("rodent-fgr");
1188     if (!fgr) {
1189 	DBG("fgr not found.\n");
1190         return;
1191     }
1192 
1193     view_t *view_p = widgets_p->view_p;
1194     gchar *path = NULL;
1195 
1196     // on keybind call, mouse_event is ignored, selection_p is
1197     // set to NULL in keybind.
1198     if(view_p->mouse_event.selected_p && view_p->mouse_event.selected_p->en
1199 	    && IS_SDIR(view_p->mouse_event.selected_p->en->type)
1200        && g_slist_length (view_p->selection_list) == 1) {
1201 	path = g_strdup(view_p->mouse_event.selected_p->en->path);
1202     } else if(view_p->en) {
1203 	path = g_strdup(view_p->en->path);
1204     }
1205     gchar *argv[]={fgr, path, NULL};
1206     rfm_threaded_show_text(widgets_p);
1207     rfm_thread_run_argv(widgets_p, argv, FALSE);
1208     g_free(fgr);
1209     g_free(path);
1210 }
1211 
1212 static void
help(widgets_t * widgets_p)1213 help (widgets_t *widgets_p){
1214     //view_t *view_p = widgets_p->view_p;
1215     // XXX: should define PDF_DIR and use ./configure --pdfdir=xxx
1216     gchar *help_file=g_strdup_printf("%s/doc/rfm/RTFM.pdf",
1217 	    PACKAGE_DATA_DIR);
1218     // This is a local and absolute path.
1219     if (!g_file_test(help_file, G_FILE_TEST_EXISTS)){
1220 	DBG("%s: %s\n", help_file, strerror(ENOENT));
1221     } else {
1222 	record_entry_t *en=rfm_stat_entry(help_file, 0);
1223 	en->mimetype=MIME_type(en->path, NULL);
1224 	open_with (widgets_p, en);
1225 	rfm_destroy_entry(en);
1226     }
1227     g_free(help_file);
1228 }
1229 static void
remove_x(widgets_t * widgets_p)1230 remove_x (widgets_t *widgets_p){
1231     view_t *view_p = widgets_p->view_p;
1232     if (view_p && g_slist_length(view_p->selection_list) >= 1){
1233 	GSList *list = NULL;
1234 	GSList *tmp=view_p->selection_list;
1235 	for (;tmp && tmp->data; tmp=tmp->next) {
1236 	    record_entry_t *en=tmp->data;
1237 	    list = g_slist_prepend(list, g_strdup (en->path));
1238 	    list = g_slist_reverse(list);
1239 	}
1240 	rm(widgets_p, list);
1241 	// unselect all items now so they won't remain in selection
1242 	// list when the thread is done.
1243         TRACE("** rm call has returned\n");
1244 	rodent_unselect_all_pixbuf (view_p);
1245     }
1246 }
1247 
1248 static void
refresh(widgets_t * widgets_p)1249 refresh (widgets_t *widgets_p){
1250     NOOP(stderr, "refresh...\n");
1251     view_t *view_p = widgets_p->view_p;
1252     if(view_p->en){
1253 	if (view_p->en->path) {
1254 	    gchar *path = g_strdup( view_p->en->path);
1255 	    rfm_cleanup_thumbnails(path);
1256 	}
1257 	if (view_p->en->module &&
1258 	    rfm_natural(PLUGIN_DIR, view_p->en->module, view_p, "reload")) {
1259 		return;
1260 	}
1261     }
1262     record_entry_t *en = rfm_copy_entry (view_p->en);
1263     if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
1264 }
1265 
1266 static void
host(widgets_t * widgets_p)1267 host (widgets_t *widgets_p) {
1268     view_t *view_p = widgets_p->view_p;
1269     if(view_p->child_constructor) {
1270         (*view_p->child_constructor) (widgets_p, NULL);
1271     } else {
1272         rodent_push_view_go_history ();
1273         if (!rodent_refresh (widgets_p, NULL)){
1274             g_warning("!rodent_refresh (widgets_p, NULL)\n");
1275         }
1276     }
1277 }
1278 
1279 static void
goup(widgets_t * widgets_p)1280 goup (widgets_t *widgets_p) {
1281     view_t *view_p = widgets_p->view_p;
1282     record_entry_t *en = NULL;
1283     if (view_p->population_pp && view_p->population_pp[0]){
1284 	if (view_p->population_pp[0]->en &&
1285 		view_p->population_pp[0]->en->module) {
1286 	    en =rfm_copy_entry(view_p->population_pp[0]->en);
1287 	} else if (view_p->population_pp[0]->en) {
1288 	    gchar *path=g_strdup(view_p->population_pp[0]->en->path);
1289 	    if (g_path_is_absolute(path)){
1290 		while (!rfm_g_file_test_with_wait(path, G_FILE_TEST_IS_DIR)){
1291 		    gchar *d = g_path_get_dirname(path);
1292 		    g_free(path);
1293 		    path = d;
1294 		}
1295 	    } else {
1296 		g_error("goup_activate(): this should not happen\n");
1297 	    }
1298 	    en =rfm_stat_entry(path, 0);
1299 	    g_free(path);
1300 	}
1301     }
1302     if (!en) {
1303 	host (widgets_p);
1304 	return;
1305     }
1306     if (IS_SDIR(en->type)){
1307         rodent_push_view_go_history ();
1308     }
1309     if(view_p->child_constructor) {
1310 	if (en->module) {
1311 	  gchar *m=g_strdup_printf("rodent-plug %s", en->module);
1312           (*view_p->child_constructor) (widgets_p, (char *)m);
1313 	  g_free(m);
1314 	} else {
1315           (*view_p->child_constructor) (widgets_p, en->path);
1316         }
1317         rfm_destroy_entry(en);
1318     } else {
1319 	if (IS_SDIR(en->type)){
1320 	    rodent_push_view_go_history ();
1321 	}
1322 	if (!rodent_refresh (widgets_p, en)){
1323             rfm_destroy_entry(en);
1324         }
1325     }
1326 }
1327 
1328 
1329 static void
forward(widgets_t * widgets_p)1330 forward (widgets_t *widgets_p){
1331     view_t *view_p = widgets_p->view_p;
1332     if (!view_p->f_list) {
1333 	rfm_threaded_show_text(widgets_p);
1334 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-info", NULL);
1335 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/blue",
1336 		g_strconcat(_("Empty history"), "\n", NULL));
1337 	jump_to(widgets_p);
1338 	return;
1339     }
1340     record_entry_t *en = view_p->f_list->data;
1341     view_p->f_list = g_slist_remove(view_p->f_list, en);
1342     // if we reach the end, push history (hack)
1343     rodent_push_view_go_history();
1344     if(en) view_p->module = en->module;
1345     else view_p->module = NULL;
1346     TRACE( "forward() calling rodent_full_reload_view\n");
1347     rodent_full_reload_view ((gpointer) view_p, en);
1348 }
1349 
1350 static void
back(widgets_t * widgets_p)1351 back (widgets_t *widgets_p){
1352     view_t *view_p = widgets_p->view_p;
1353     GList *last = g_list_last (view_p->go_list);
1354     if(!last) {
1355 	// This will only occur on keybinding callback.
1356 	rfm_threaded_show_text(widgets_p);
1357 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-info", NULL);
1358 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/blue",
1359 		g_strconcat(_("Initial Point"),
1360 		": ", (view_p->en)?view_p->en->path:_("Plugins"), "\n", NULL));
1361 	return;
1362     }
1363     record_entry_t *en = last->data;
1364     // Failure warning instead of going to previous back.
1365     if (!rfm_entry_available(widgets_p, en)) {
1366 	pop_view_go_history (view_p);
1367 	return;
1368     }
1369     view_p->f_list = g_slist_prepend(view_p->f_list, rfm_copy_entry(view_p->en));
1370     if(en) view_p->module = en->module;
1371     else view_p->module = NULL;
1372     pop_view_go_history (view_p);
1373     TRACE( "back() calling rodent_full_reload_view\n");
1374     rodent_full_reload_view ((gpointer) view_p, en);
1375 }
1376 
1377 static void
home(widgets_t * widgets_p)1378 home (widgets_t *widgets_p){
1379     view_t *view_p = widgets_p->view_p;
1380     if (!rfm_g_file_test_with_wait (g_get_home_dir(), G_FILE_TEST_IS_DIR)){
1381 	 time_out_message(widgets_p, g_get_home_dir());
1382 	 return;
1383     }
1384     if(view_p->child_constructor) {
1385 	(*view_p->child_constructor) (widgets_p, (char *)g_get_home_dir ());
1386     } else {
1387 	rodent_push_view_go_history ();
1388 	record_entry_t *en = rfm_stat_entry ((gchar *) g_get_home_dir (), 0);
1389 	if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
1390     }
1391 }
1392 
1393 static void
jump_to(widgets_t * widgets_p)1394 jump_to (widgets_t *widgets_p){
1395     view_t *view_p = widgets_p->view_p;
1396     gchar *g = get_jumpto_dir(widgets_p);
1397     if (!g) return;
1398     if(view_p->child_constructor) {
1399 	(*view_p->child_constructor) (widgets_p, g);
1400     } else {
1401 	rodent_push_view_go_history ();
1402 	rfm_save_to_go_history (g);
1403 	record_entry_t *en = rfm_stat_entry (g, 0);
1404 	if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
1405     }
1406     g_free (g);
1407 }
1408 
1409 static void
plugin_goto(widgets_t * widgets_p,gpointer data)1410 plugin_goto (widgets_t *widgets_p, gpointer data) {
1411     view_t *view_p = widgets_p->view_p;
1412     GtkWidget *menu_item = data;
1413     const gchar *module_name = g_object_get_data(G_OBJECT(menu_item), "module_name");
1414     if(module_name) {
1415       if (view_p->child_constructor) {
1416 	gchar *m = g_strconcat("rodent-plug"," ", module_name, NULL);
1417         (*view_p->child_constructor) (widgets_p, (char *)m);
1418 	g_free(m);
1419       } else {
1420         rodent_push_view_go_history ();
1421         record_entry_t *new_en = rfm_mk_entry (0);
1422         SET_ROOT_TYPE (new_en->type);
1423         new_en->module = module_name;
1424         new_en->path = rfm_void (PLUGIN_DIR, module_name, "module_label");
1425 	if (!rodent_refresh (widgets_p, new_en)){ rfm_destroy_entry(new_en); }
1426       }
1427     } else {
1428         DBG ("cannot get module_name from module-goto menu\n");
1429     }
1430     return;
1431 }
1432 
1433 // This function uses menuitem and does not accept keybinding...
1434 static void
level_goto(widgets_t * widgets_p,gpointer data)1435 level_goto (widgets_t *widgets_p, gpointer data) {
1436     view_t *view_p = widgets_p->view_p;
1437     GtkWidget *menu_item = data;
1438     const gchar *path = g_object_get_data(G_OBJECT(menu_item), "path");
1439     NOOP("path is %s\n", path);
1440     if(path) {
1441         if(view_p->child_constructor) {
1442             (*view_p->child_constructor) (widgets_p, (char *)path);
1443         } else {
1444             rodent_push_view_go_history ();
1445 	    record_entry_t *new_en;
1446 	    if (rfm_g_file_test_with_wait(path, G_FILE_TEST_EXISTS)){
1447 		     new_en = rfm_stat_entry (path, 0);
1448 	    } else {
1449 		rfm_confirm (widgets_p, GTK_MESSAGE_ERROR, strerror (EEXIST), NULL, NULL);
1450 		return;
1451 	    }
1452 	    if (new_en && !new_en->module) {
1453 		rfm_save_to_go_history ((gchar *) path);
1454 	    }
1455 	    if (!rodent_refresh (widgets_p, new_en)){
1456 		rfm_destroy_entry(new_en);
1457 	    }
1458 
1459         }
1460     } else {
1461         DBG ("cannot get path from level-goto menu\n");
1462     }
1463     return;
1464 }
1465 
1466 
1467 static void
ascending_descending(widgets_t * widgets_p,enum menu_enum_t menu_enum)1468 ascending_descending (widgets_t *widgets_p, enum menu_enum_t menu_enum){
1469     view_t *view_p = widgets_p->view_p;
1470 
1471     if (view_p->flags.preferences & SORT_ASCENDING) {
1472 	view_p->flags.preferences &= (SORT_ASCENDING ^ 0xffffffff);
1473     } else {
1474 	view_p->flags.preferences |= SORT_ASCENDING;
1475     }
1476 #if 0
1477     if (menu_enum == ASCENDING_ACTIVATE) {
1478 	if (view_p->flags.preferences & SORT_ASCENDING) return;
1479 	view_p->flags.preferences |= SORT_ASCENDING;
1480     } else {
1481 	if ((view_p->flags.preferences & SORT_ASCENDING) == 0) return;
1482 	view_p->flags.preferences &= (SORT_ASCENDING ^ 0xffffffff);
1483     }
1484 #endif
1485     rfm_save_view_preferences (view_p, view_p->en);
1486     record_entry_t *en = rfm_copy_entry (view_p->en);
1487     if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
1488 }
1489 
1490 static void
about(widgets_t * widgets_p)1491 about(widgets_t *widgets_p){
1492     gchar *argv[3];
1493     argv[0] = "rodent";
1494     argv[1] = "--version";
1495     argv[2] = NULL;
1496 
1497 
1498     rfm_threaded_show_text (widgets_p);
1499     rfm_thread_run_argv (widgets_p, argv, FALSE);
1500     // pipe output of current app...
1501     gchar *app = g_strdup("rodent-app");
1502     rfm_global_t *rfm_global_p = rfm_global();
1503     if (rfm_global_p){
1504 	gchar *c = g_strdup_printf("%s --version", rfm_global_p->argv[0]);
1505 	FILE *p = popen(c, "r");
1506 	gchar buffer[256];
1507 	memset(buffer, 0, 256);
1508 	if (p && fgets(buffer, 255, p)){
1509 	    g_free(app);
1510 	    if (strchr(buffer,'\n')) *strchr(buffer,'\n') = 0;
1511 	    app = g_strdup(buffer);
1512 	}
1513 	if (p) pclose(p);
1514     }
1515 
1516     void *arg[]={widgets_p, app};
1517     rfm_context_function(about_dialog_f, arg);
1518     g_free(app);
1519 }
1520 
1521 static void
newdir(widgets_t * widgets_p)1522 newdir (widgets_t *widgets_p) {
1523     view_t *view_p = widgets_p->view_p;
1524     record_entry_t *en =  view_p->en;
1525     gchar *label = g_strdup_printf ("%s/", en->path);
1526     gchar *q = rfm_utf_string (rfm_chop_excess (label));
1527     gchar *g = get_response (_("Create New Folder"), q,
1528                                           _("Name"));
1529     g_free (label);
1530     g_free (q);
1531 
1532     if(g && strlen (g)) {
1533       gchar *p = g_build_filename (en->path, g, NULL);
1534       //
1535       if(!rfm_locate_path(view_p, p))
1536       {
1537         gchar *argv[4];
1538         int j=0;
1539         argv[j++]="mkdir";
1540         argv[j++]=p;
1541         argv[j++]=NULL;
1542 
1543 	if (en->st->st_mode == 0) {
1544 	    DBG("This should not happen: en->st->st_mode == 0\n");
1545 	    g_free(g);
1546 	    return;
1547 	}
1548 
1549 	if (rfm_write_ok_path(en->path)){
1550 	    rfm_thread_run_argv (widgets_p, argv, FALSE);
1551 	} else {
1552 	    gchar *base=g_path_get_basename(p);
1553 	    gchar *operation=g_strconcat("mkdir ", base, NULL);
1554 	    g_free(base);
1555 	    if (confirm_sudo(widgets_p, en->path,
1556 		    _("write failed"), operation)){
1557 		RFM_TRY_SUDO (widgets_p, argv, FALSE);
1558 		rfm_threaded_show_text(widgets_p);
1559 		rfm_threaded_diagnostics(widgets_p, "xffm/stock_properties",NULL);
1560 		rfm_threaded_diagnostics(widgets_p, "xffm_tag/green",
1561 			g_strconcat(_("Don't forget"), " ", NULL));
1562 		rfm_threaded_diagnostics(widgets_p, "xffm_tag/magenta",
1563 		    g_strconcat("chown pid:gid", " ", p, "\n", NULL));
1564 	    }
1565 	    g_free(operation);
1566 	}
1567       }
1568       else {
1569             rfm_confirm (widgets_p, GTK_MESSAGE_ERROR, strerror (EEXIST), NULL, NULL);
1570       }
1571       g_free(p);
1572     }
1573     g_free(g);
1574 }
1575 
1576 static void
newfile(widgets_t * widgets_p)1577 newfile (widgets_t *widgets_p) {
1578     view_t *view_p = widgets_p->view_p;
1579     record_entry_t *en = view_p->en;
1580     gchar *label = g_strdup_printf ("%s/", en->path);
1581     gchar *q = rfm_utf_string (rfm_chop_excess (label));
1582     gchar *g = get_response ( _("New file"), q, _("Name"));
1583     g_free (q);
1584     g_free (label);
1585     if(g && strlen (g)) {
1586         gchar *p = g_build_filename (en->path, g, NULL);
1587         if(!rfm_locate_path(view_p, p)) {
1588 	    gchar *argv[3];
1589 	    int j=0;
1590 	    argv[j++]="touch";
1591 	    argv[j++]=p;
1592 	    argv[j++]=NULL;
1593 
1594 
1595 	    if (rfm_write_ok_path(en->path)){
1596 		rfm_thread_run_argv (widgets_p, argv, FALSE);
1597 	    } else {
1598 		gchar *base=g_path_get_basename(p);
1599 		gchar *operation=g_strconcat("touch ", base, NULL);
1600 		g_free(base);
1601 		if (confirm_sudo(widgets_p, en->path,
1602 			_("write failed"), operation)){
1603 		    RFM_TRY_SUDO (widgets_p, argv, FALSE);
1604 		    rfm_threaded_show_text(widgets_p);
1605 		    rfm_threaded_diagnostics(widgets_p, "xffm/stock_properties",NULL);
1606 		    rfm_threaded_diagnostics(widgets_p, "xffm_tag/green",
1607 			    g_strconcat(_("Don't forget"), " ", NULL));
1608 		    rfm_threaded_diagnostics(widgets_p, "xffm_tag/magenta",
1609 			g_strconcat("chown pid:gid", " ", p, "\n", NULL));
1610 		}
1611 		g_free(operation);
1612 	    }
1613          } else {
1614             rfm_confirm (widgets_p, GTK_MESSAGE_ERROR, strerror (EEXIST), NULL, NULL);
1615         }
1616         g_free (p);
1617     }
1618     g_free(g);
1619 }
1620 
1621 static void
run(widgets_t * widgets_p)1622 run(widgets_t *widgets_p){
1623     gboolean visible=rfm_threaded_diagnostics_is_visible(widgets_p);
1624     if (!visible) rfm_threaded_show_text(widgets_p);
1625     if (!execute (widgets_p, NULL)){
1626 	if (!visible && widgets_p->diagnostics_window==NULL){
1627 	    rfm_threaded_hide_text(widgets_p);
1628 	}
1629     }
1630 }
1631 
1632 static void
bcrypt(widgets_t * widgets_p)1633 bcrypt(widgets_t *widgets_p){
1634     // this will be an internal function call, rodent-bcrypt
1635     view_t *view_p = widgets_p->view_p;
1636     GSList *list=NULL;
1637     GSList *s_list = view_p->selection_list;
1638     if (g_slist_length(s_list) > MAX_COMMAND_ARGS - 5){
1639 	DBG("Argument list too long (%d > %d)\n",
1640 	    g_slist_length(s_list), MAX_COMMAND_ARGS - 5);
1641 	return;
1642     }
1643     for (; s_list && s_list->data; s_list = s_list->next){
1644 	record_entry_t *en = s_list->data;
1645 	if (en && g_path_is_absolute(en->path))
1646 	    list = g_slist_append(list, g_strdup(en->path));
1647     }
1648     if (!rfm_natural(RFM_MODULE_DIR, "bcrypt", list, "bcrypt_dialog")){
1649 	DBG("cannot load bcrypt plugin\n");
1650     }
1651     for (s_list = list; s_list && s_list->data; s_list = s_list->next){
1652 	g_free(s_list->data);
1653     }
1654     g_slist_free(list);
1655 }
1656 
1657 static void
open_x(widgets_t * widgets_p)1658 open_x(widgets_t *widgets_p){
1659     view_t *view_p = widgets_p->view_p;
1660     GSList *list=NULL;
1661     GSList *s_list = view_p->selection_list;
1662     for (; s_list && s_list->data; s_list = s_list->next){
1663 	record_entry_t *in_en = s_list->data;
1664 	record_entry_t *out_en = rfm_copy_entry(in_en);
1665 	list = g_slist_append(list, out_en);
1666     }
1667     execute(widgets_p, list);
1668 }
1669 
1670 static void
new_window(widgets_t * widgets_p)1671 new_window(widgets_t *widgets_p){
1672     view_t *view_p = widgets_p->view_p;
1673     gchar *new_path=NULL;
1674     if (view_p->module) {
1675 	new_path=g_strconcat("rodent-plug", " ", view_p->module, NULL);
1676     } else if (view_p->en) {
1677 	 if (!rfm_g_file_test_with_wait(view_p->en->path, G_FILE_TEST_IS_DIR)){
1678 	     time_out_message(widgets_p, view_p->en->path);
1679 	     return;
1680 	 }
1681 	new_path=g_strdup(view_p->en->path);
1682     }
1683     rodent_new_gridview(widgets_p, new_path);
1684     g_free(new_path);
1685 }
1686 static void
open_in_terminal(widgets_t * widgets_p)1687 open_in_terminal(widgets_t *widgets_p){
1688     view_t *view_p = widgets_p->view_p;
1689     gchar *shell = rfm_xterm_shell();
1690     if (!shell) return;
1691     if(!view_p->en
1692 	    || !view_p->en->path
1693 	    || !g_path_is_absolute(view_p->en->path)){
1694 	g_free (widgets_p->workdir);
1695 	widgets_p->workdir = g_strdup (g_get_home_dir ());
1696     } else {
1697 	g_free (widgets_p->workdir);
1698 	widgets_p->workdir = g_strdup (view_p->en->path);
1699     }
1700 
1701      gchar *argv[] = { shell, NULL };
1702     // use argv version so that it won't go into history file...
1703     rfm_thread_run_argv (widgets_p, argv, TRUE);
1704     g_free(shell);
1705 }
1706 static void
differences(widgets_t * widgets_p)1707 differences(widgets_t *widgets_p){
1708     view_t *view_p = widgets_p->view_p;
1709     gchar *file1 = NULL;
1710     gchar *file2 = NULL;
1711     if(view_p->selection_list) {
1712 	file1 = ((record_entry_t *) (view_p->selection_list->data))->path;
1713 	if(g_slist_length (view_p->selection_list) > 1){
1714 	    file2 = ((record_entry_t *) (view_p->selection_list->next->data))->path;
1715 	}
1716     }
1717     if (file1 && !rfm_g_file_test_with_wait(file1, G_FILE_TEST_EXISTS)) {
1718 	 time_out_message(widgets_p, file1);
1719 	 return;
1720     }
1721     if (file2 && !rfm_g_file_test_with_wait(file2, G_FILE_TEST_EXISTS)) {
1722 	 time_out_message(widgets_p, file2);
1723 	 return;
1724     }
1725     g_free (widgets_p->workdir);
1726     widgets_p->workdir = g_strdup (g_get_home_dir ());
1727 
1728     gchar *argv[4];
1729     int i = 0;
1730     argv[i++] = "rodent-diff";
1731     if(file1)
1732         argv[i++] = file1;
1733     if(file2)
1734         argv[i++] = file2;
1735     argv[i] = NULL;
1736 
1737     rfm_thread_run_argv (widgets_p, argv, FALSE);
1738 }
1739 static void
settings(widgets_t * widgets_p)1740 settings(widgets_t *widgets_p){
1741     if(rfm_void (RFM_MODULE_DIR, "settings", "module_active")) {
1742 	rfm_void (RFM_MODULE_DIR, "settings", "run_rfm_settings_dialog");
1743     } else {
1744 	DBG ("rodent_settings_activate(): cannot load libsettings\n");
1745     }
1746 }
1747 
1748 static void *
new_tab(gpointer data)1749 new_tab(gpointer data){
1750     void **arg = data;
1751     view_t *view_p = arg[0];
1752     gchar *argv = arg[1];
1753     g_free(arg);
1754     widgets_t *widgets_p = &(view_p->widgets);
1755     if (view_p->tab_constructor) (*(view_p->tab_constructor))(widgets_p, argv);
1756     g_free(argv);
1757     return NULL;
1758 }
1759 
1760 static void *
new_tab_f(void * data)1761 new_tab_f(void *data){
1762     if (rfm_get_gtk_thread() != g_thread_self()){
1763 	rfm_context_function(new_tab_f, data);
1764 	return NULL;
1765     }
1766     widgets_t *widgets_p = data;
1767     view_t *view_p = widgets_p->view_p;
1768     if (!view_p->tab_constructor) return NULL;
1769     gchar *path = NULL;
1770     if (view_p->en && !view_p->en->module) path = view_p->en->path;
1771     (*(view_p->tab_constructor))(widgets_p, path);
1772     return NULL;
1773 }
1774 
1775 
1776 
1777 
1778 
1779 // This function uses menuitem and does not accept keybinding...
1780 // autotype C is "open with" operator which is determined by
1781 // means of the command associated data item of the widget
1782 static void
autotype(widgets_t * widgets_p,gpointer menuitem)1783 autotype (widgets_t *widgets_p, gpointer menuitem) {
1784     if (!menuitem) return;
1785     view_t *view_p = widgets_p->view_p;
1786     gchar *new_command=NULL;
1787     record_entry_t *en = view_p->selection_list->data;
1788     if (!en->path || !strlen(en->path))return;
1789 
1790     const gchar *output_arg = g_object_get_data (G_OBJECT (menuitem), "output_arg");
1791     const gchar *command = g_object_get_data (G_OBJECT (menuitem), "command");
1792     const gchar *dirname = g_object_get_data (G_OBJECT (menuitem), "workdir");
1793     const gchar *querypath = g_object_get_data (G_OBJECT (menuitem), "querypath");
1794     const gchar *output_ext = g_object_get_data (G_OBJECT (menuitem), "output_ext");
1795 
1796     // Assign command as default command here, if applicable.
1797     if (g_object_get_data(G_OBJECT(menuitem), "CTL_SET")) {
1798 	NOOP("CTL is set\n");
1799 	// must substitute path in command line for %s
1800 	gchar *command_fmt=g_strdup(command);
1801 	command_fmt=strip_path(command_fmt,en->path);
1802 
1803 	if(!en->mimetype || strcmp(en->mimetype, _("unknown"))==0) {
1804 	    if (IS_LOCAL_TYPE(en->type) && !en->mimemagic) {
1805 		en->mimemagic = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_magic", "mime_function");
1806 		if (!en->mimemagic) en->mimemagic = g_strdup(_("unknown"));
1807 	    } else {
1808 		en->mimemagic = g_strdup(_("unknown"));
1809 	    }
1810 	}
1811 	if(en->mimetype && strcmp(en->mimetype, _("unknown"))!= 0) {
1812 	    NOOP (stderr, "OPEN: adding %s --> %s \n", view_p->mouse_event.selected_p->en->mimetype, command_fmt);
1813 	    // This sets it as default command for the specified mimetype
1814 	    MIME_add (en->mimetype, command_fmt);
1815 	}
1816 	g_free(command_fmt);
1817     }
1818 
1819 
1820 
1821 
1822     gint argc;
1823     gchar **argv;
1824     GError *error=NULL;
1825 
1826     if(!g_shell_parse_argv (command, &argc, &argv, &error)) {
1827         DBG("autotype_activate(%s): %s\n", command, error->message);
1828         g_error_free (error);
1829         g_strfreev (argv);
1830         NOOP ("!g_shell_parse_argv at popup_autostuff\n");
1831         return;
1832     }
1833 
1834 // internal commands:
1835     if (strcmp(argv[0], "rodent-newtab")==0){
1836         if(view_p->tab_constructor) {
1837 	    void **arg = (void **)malloc(2*sizeof(void*));
1838 	    if (!arg) g_error("malloc: %s\n", strerror(errno));
1839 	    arg[0] = view_p;
1840 	    arg[1] = g_strdup(argv[1]);
1841 	    // Wait for this:
1842 	    rfm_context_function(new_tab, arg);
1843         }
1844         return;
1845     }
1846     if (strcmp(argv[0], "rodent-bcrypt")==0){
1847 	bcrypt(widgets_p);
1848         return;
1849     }
1850     if (strcmp(argv[0], "rodent-newwin")==0){
1851 	rodent_new_gridview(widgets_p, argv[1]);
1852         return;
1853     }
1854     // We don't use this any more:
1855     g_strfreev (argv);
1856 
1857     gchar *workdir=NULL;
1858     if(querypath) {
1859         workdir=autofunction_workdir (widgets_p, querypath);
1860         if (!workdir) return;
1861     }
1862 
1863     if (dirname) {// XXX I wonder what this is for?
1864         g_free (widgets_p->workdir);
1865         widgets_p->workdir = g_strdup (dirname);
1866     }
1867     if(output_ext) {
1868         gchar *basename = g_path_get_basename (output_arg);
1869         gchar *output_path=g_strconcat("\"",workdir, G_DIR_SEPARATOR_S, basename, output_ext,"\"",NULL);
1870         gchar *esc_path = g_strconcat("\"",basename,"\"",NULL);
1871         g_free(basename);
1872         basename=esc_path;
1873 
1874         gchar *s=strstr(command,"%s");
1875         if (s) {
1876         // XXX this should have at least two %s tokens...
1877             new_command = g_strdup_printf(command, output_path, basename);
1878         } else {
1879                 NOOP("no %%s in command");
1880             new_command = g_strconcat (command, " ", output_path, " ", basename, NULL);
1881         }
1882         command = (const gchar *)new_command;
1883         g_free (output_path);
1884         g_free (basename);
1885     } else if (workdir) {
1886         g_free (widgets_p->workdir);
1887         widgets_p->workdir = g_strdup (workdir);
1888     }
1889     NOOP ("output_arg=%s, command=%s, querypath(string)=%s, output_ext=%s, dirname=%s workdir=%s\n", output_arg, command, querypath,
1890            output_ext, dirname, widgets_p->workdir);
1891 
1892     rfm_threaded_show_text(widgets_p);
1893     RFM_THREAD_RUN2ARGV (widgets_p, (void *)command, FALSE);
1894 
1895     g_free (new_command);
1896     g_free (workdir);
1897 
1898 
1899 }
1900 
1901 // This function is for executables and dotdesktop types.
1902 static void
autotype_r(widgets_t * widgets_p,gpointer menuitem)1903 autotype_r (widgets_t *widgets_p, gpointer menuitem) {
1904     if (!menuitem) return;
1905     record_entry_t *en = g_object_get_data(G_OBJECT(menuitem), "record_entry");
1906     if (en) {
1907 	if (en->mimetype &&
1908 	    strcmp(en->mimetype, "application/x-desktop")==0 &&
1909 	    rfm_rational(PLUGIN_DIR, "dotdesktop", widgets_p, en,  "double_click"))
1910 	{
1911 	    return;
1912 	}
1913 
1914 	if (en->path && IS_EXE_TYPE(en->type))
1915 	{
1916 	    NOOP("executing %s\n", en->path);
1917 	    g_free(widgets_p->workdir);
1918 	    widgets_p->workdir=g_path_get_dirname(en->path);
1919 	    if (!rfm_g_file_test_with_wait(widgets_p->workdir, G_FILE_TEST_EXISTS)){
1920 		time_out_message(widgets_p, widgets_p->workdir);
1921 		g_free(widgets_p->workdir);
1922 		widgets_p->workdir = g_strdup(g_get_home_dir());
1923 	    } else {
1924 		gchar *argv[2]={en->path, NULL};
1925 		rfm_thread_run_argv(widgets_p, argv, TRUE);
1926 	    }
1927 	}
1928     }
1929     return;
1930 }
1931 
1932 static void
rename_x(widgets_t * widgets_p)1933 rename_x (widgets_t *widgets_p) {
1934     view_t *view_p = widgets_p->view_p;
1935     void **arg = (void **) malloc(3*sizeof(void *));
1936     if (!arg) g_error("malloc: %s\n", strerror(errno));
1937     arg[0] = view_p;
1938     arg[1] = (void *)(view_p->mouse_event.selected_p);
1939     arg[2] = GINT_TO_POINTER(RENAME_CASO);
1940     rfm_context_function(mk_rename_entry, arg);
1941 }
1942 
1943 static void
duplicate(widgets_t * widgets_p)1944 duplicate (widgets_t *widgets_p) {
1945     view_t *view_p = widgets_p->view_p;
1946     void **arg = (void **) malloc(3*sizeof(void *));
1947     if (!arg) g_error("malloc: %s\n", strerror(errno));
1948     arg[0] = view_p;
1949     arg[1] = (void *)(view_p->mouse_event.selected_p);
1950     arg[2] = GINT_TO_POINTER(DUPLICATE_CASO);
1951     rfm_context_function(mk_rename_entry, arg);
1952 }
1953 
1954 static void
symlink_x(widgets_t * widgets_p)1955 symlink_x (widgets_t *widgets_p) {
1956     view_t *view_p = widgets_p->view_p;
1957     void **arg = (void **) malloc(3*sizeof(void *));
1958     if (!arg) g_error("malloc: %s\n", strerror(errno));
1959     arg[0] = view_p;
1960     arg[1] = (void *)(view_p->mouse_event.selected_p);
1961     arg[2] = GINT_TO_POINTER(SYMLINK_CASO);
1962     rfm_context_function(mk_rename_entry, arg);
1963 }
1964 
1965 
1966 static void
touch(widgets_t * widgets_p)1967 touch (widgets_t *widgets_p) {
1968     view_t *view_p = widgets_p->view_p;
1969     GSList *list = NULL;
1970     GSList *tmp = view_p->selection_list;
1971     for (;tmp && tmp->data; tmp=tmp->next) {
1972 	record_entry_t *en=tmp->data;
1973 	list = g_slist_append(list, g_strdup (en->path));
1974     }
1975     void **argv = (void **)malloc(2*sizeof(void *));
1976     argv[0] = widgets_p;
1977     argv[1] = list;
1978     rfm_context_function(touch_dialog, argv);
1979     return;
1980 }
1981 
1982 static void
properties(widgets_t * widgets_p)1983 properties (widgets_t *widgets_p) {
1984     view_t *view_p = widgets_p->view_p;
1985     if(view_p->module &&
1986 	    rfm_rational (PLUGIN_DIR, view_p->module,
1987 		widgets_p,  view_p->selection_list, "do_properties")
1988 	    ) {
1989 	// module has done the properties thing here;
1990     } else {
1991 	rfm_natural(RFM_MODULE_DIR, "properties", widgets_p, "do_prop");
1992     }
1993 }
1994 
1995 
1996 static void
select_all(widgets_t * widgets_p,gpointer user_data)1997 select_all (widgets_t *widgets_p, gpointer user_data) {
1998     view_t *view_p = widgets_p->view_p;
1999     rfm_status (&(view_p->widgets), "xffm/stock_dialog-info", _("Select All"), "...", NULL);
2000     select_all_view (view_p, GPOINTER_TO_INT(user_data));
2001     gchar *plural_text=g_strdup_printf (
2002 	ngettext ("%'u item", "%'u items", g_slist_length(view_p->selection_list)),
2003 	g_slist_length(view_p->selection_list));
2004     gchar *g = g_strdup_printf ("%s: %s", _("Selection"), plural_text);
2005     g_free(plural_text);
2006     rfm_threaded_status (&(view_p->widgets), "xffm/stock_dialog-info", g);
2007 }
2008 
2009 static void
select_by_filter(widgets_t * widgets_p,gpointer user_data)2010 select_by_filter (widgets_t *widgets_p, gpointer user_data) {
2011     gboolean select_it = GPOINTER_TO_INT(user_data);
2012     gchar *filter_s;
2013     view_t *view_p = widgets_p->view_p;
2014     gchar *b = g_strdup_printf ("%s/", view_p->en->path);
2015     gchar *label = rfm_utf_string (rfm_chop_excess (b));
2016     filter_s = get_response ( (select_it)?_("Select Items Matching..."):
2017 	    _("Unselect Items Matching..."), label, "*");
2018     g_free (label);
2019     g_free (b);
2020     if(filter_s && strlen (filter_s)) {
2021         select_byfilter_view (widgets_p, filter_s, select_it);
2022     }
2023     g_free(filter_s);
2024 }
2025 
2026 
2027 static void
mount(widgets_t * widgets_p)2028 mount (widgets_t *widgets_p) {
2029     private_mount (widgets_p, FALSE);
2030 }
2031 
2032 static void
unmount(widgets_t * widgets_p)2033 unmount (widgets_t *widgets_p) {
2034     private_mount (widgets_p, TRUE);
2035 }
2036 
2037 static void *close_x (gpointer data);
2038 
2039 
2040 static void *
quit(void * data)2041 quit (void *data) {
2042     //return NULL;
2043     rfm_global_t *rfm_global_p = rfm_global();
2044     g_mutex_lock(rfm_global_p->status_mutex);
2045     //g_error("wuit...\n");
2046     TRACE("quit(): setting status to STATUS_EXIT\n");
2047     rfm_global_p->status = STATUS_EXIT;
2048     g_mutex_unlock(rfm_global_p->status_mutex);
2049 
2050 #ifndef VERIFY_LEAKS
2051     TRACE("ZZZ quit(): killing all controller children now...\n");
2052     rfm_killall_children();
2053     // This is quick exit, without memory leak check cleanup
2054     TRACE("ZZZ quit(): exit now.\n");
2055     exit(1);
2056 #else
2057     TRACE("VERIFY_LEAKS is set on exit...\n");
2058     // This way the janitor exits the main loop and the main program
2059     // will do a full cleanup to verify memory leaks.
2060     widgets_t *widgets_p = data;
2061     TRACE( "ZZZ quit callback... thread 0x%x\n",GPOINTER_TO_INT(g_thread_self()));
2062     if (rfm_get_gtk_thread() != g_thread_self()){
2063         rfm_context_function(quit, widgets_p);
2064 	return NULL;
2065     }
2066     TRACE( "ZZZ quit callback proceed ... thread 0x%x\n",GPOINTER_TO_INT(g_thread_self()));
2067 
2068     g_cond_signal(rfm_global_p->janitor_signal);
2069     gtk_widget_hide(rfm_global_p->window);
2070     gdk_flush();
2071 #endif
2072     return NULL;
2073 }
2074 
2075 static void *
destructor(void * data)2076 destructor(void *data){
2077     view_t *view_p = data;
2078     (*(view_p->tab_destructor))(view_p);
2079     return NULL;
2080 }
2081 
2082 static void *
close_x(gpointer data)2083 close_x (gpointer data) {
2084     TRACE("ZZZ close_x callback...\n");
2085     widgets_t *widgets_p = data;
2086     rfm_global_t *rfm_global_p = rfm_global();
2087     if (!widgets_p){
2088 	DBG("close_x(): widgets_p==NULL\n");
2089 	return NULL;
2090     }
2091 
2092     if (strstr(rfm_global_p->argv[0], "rodent-desk")){
2093 	quit(widgets_p);
2094 	return NULL;
2095     }
2096 
2097     GSList **list_p = rfm_view_list_lock(NULL, "close_x");
2098     gint active_views = g_slist_length(*list_p);
2099     rfm_view_list_unlock("close_x");
2100     if(active_views == 1) quit(widgets_p);
2101     // Gridview...
2102     view_t *view_p = widgets_p->view_p;
2103     if (!view_p) return FALSE;
2104     TRACE("ZZZ calling destructor...\n");
2105     if (view_p->tab_destructor) destructor(view_p);
2106     return NULL;
2107 }
2108 
2109 
2110 // This function uses menuitem and does not accept keybinding...
2111 static void
bookmark_add(widgets_t * widgets_p,gpointer menuitem)2112 bookmark_add (widgets_t *widgets_p, gpointer menuitem) {
2113     view_t * view_p = widgets_p->view_p;
2114     const gchar *path = NULL;
2115     if (menuitem) path = g_object_get_data(G_OBJECT(menuitem), "path");
2116     else if (view_p->en) path = view_p->en->path;
2117     if (!path) return;
2118     if (!g_path_is_absolute(path)){
2119      return;
2120     }
2121     if (rodent_bookmarks_add(path)) {
2122 	unselect_all (widgets_p);
2123 	if (menuitem){
2124 	    GdkRectangle *rect=g_object_get_data(G_OBJECT(menuitem), "rect");
2125 	    if (rect) rfm_expose_rect (view_p, rect);
2126 	}
2127 	rodent_set_view_icon (view_p); // this is sent to main context.
2128 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-info",NULL);
2129 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/blue", g_strconcat(_("Bookmark added"),"\n",NULL));
2130     } else {
2131 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-warning",NULL);
2132 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/stderr", g_strconcat(_("The operation was cancelled."),"\n",NULL));
2133     }
2134 }
2135 
2136 // This function uses menuitem and does not accept keybinding...
2137 static void
bookmark_remove(widgets_t * widgets_p,gpointer menuitem)2138 bookmark_remove (widgets_t *widgets_p, gpointer menuitem) {
2139     view_t * view_p = widgets_p->view_p;
2140     const gchar *path = NULL;
2141     if (menuitem) path = g_object_get_data(G_OBJECT(menuitem), "path");
2142     else if (view_p->en) path = view_p->en->path;
2143     if (!path) return;
2144 
2145     if (rodent_bookmarks_remove(path)) {
2146 	unselect_all (widgets_p);
2147 	if (menuitem){
2148 	    GdkRectangle *rect=g_object_get_data(G_OBJECT(menuitem), "rect");
2149 	    if (rect) rfm_expose_rect (view_p, rect);
2150 	}
2151 	rodent_set_view_icon (view_p); // this is sent to main context.
2152     } else {
2153 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-warning",NULL);
2154 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/stderr", g_strconcat(_("The operation was cancelled."),"\n",NULL));
2155     }
2156 }
2157 
2158 static void
toggle_bookmark(widgets_t * widgets_p)2159 toggle_bookmark (widgets_t *widgets_p) {
2160     view_t * view_p = widgets_p->view_p;
2161     const gchar *path = NULL;
2162     if (view_p->en) path = view_p->en->path;
2163     if (!path) return;
2164     if (rodent_path_has_bookmark(path)) bookmark_remove(widgets_p, NULL);
2165     else bookmark_add(widgets_p, NULL);
2166 }
2167 
2168 static gint
compar(const void * a_p,const void * b_p)2169 compar(const void *a_p, const void *b_p){
2170     RodentCallback *a = (RodentCallback *)a_p;
2171     RodentCallback *b = (RodentCallback *)b_p;
2172     if (!a && !b) return 0;
2173     if (!a) return -1;
2174     if (!b) return -1;
2175     if (a->key - b->key) return (a->key - b->key);
2176     return (a->mask - b->mask);
2177 }
2178 
2179 static void
keybindings(widgets_t * widgets_p)2180 keybindings (widgets_t *widgets_p){
2181     RodentCallback *p = menu_callback_v;
2182     size_t nmemb = sizeof(menu_callback_v) / sizeof(RodentCallback) - 1;
2183     // quick sort
2184     qsort(p, nmemb, sizeof(RodentCallback), compar);
2185     //void (*callback)(GtkMenuItem * menuitem, gpointer user_data);
2186     rfm_threaded_show_text(widgets_p);
2187     for (; p && p->function_id > 0; p++){
2188 	if (!p->key) continue;
2189 	gchar *mod=g_strdup("");
2190 	gchar *key=NULL;
2191 	if (p->mask & GDK_SHIFT_MASK) {
2192 	    gchar *g = g_strconcat (mod,_("Shift"), "+", NULL);
2193 	    g_free(mod);
2194 	    mod = g;
2195 	}
2196 	if (p->mask & GDK_CONTROL_MASK) {
2197 	    gchar *g = g_strconcat (mod,_("Control"), "+", NULL);
2198 	    g_free(mod);
2199 	    mod = g;
2200 	}
2201 	if (p->mask & GDK_MOD1_MASK)  {
2202 	     gchar *g = g_strconcat (mod,_("Alt"), "+", NULL);
2203 	    g_free(mod);
2204 	    mod = g;
2205 	}
2206 	if ((p->key > 0x40 && p->key < 0x5b) ||(p->key >0x02f  && p->key < 0x03a)) {
2207 	    key = g_strdup_printf("%c", p->key);
2208 	}
2209 	else if (p->key > 0x60 && p->key < 0x7b) {
2210 	    key = g_strdup_printf("%c", toupper(p->key));
2211 	}
2212 	else if (p->key > 0xffbd && p->key < 0xffca) { // function keys f1-f12
2213 	    key = g_strdup_printf("F%d", p->key-0xffbd);
2214 	}
2215 	else { // other keys
2216 	    switch (p->key){
2217 		case GDK_KEY_Home: key = g_strdup(_("Home")); break;
2218 		case GDK_KEY_Left: key = g_strdup(_("Left")); break;
2219 		case GDK_KEY_Up: key = g_strdup(_("Up")); break;
2220 		case GDK_KEY_Right: key = g_strdup(_("Right")); break;
2221 		case GDK_KEY_Down: key = g_strdup(_("Down")); break;
2222 		case GDK_KEY_Page_Up: key = g_strdup(_("Page up")); break;
2223 		case GDK_KEY_Page_Down: key = g_strdup(_("Page down")); break;
2224 		case GDK_KEY_End: key = g_strdup(_("End")); break;
2225 		case GDK_KEY_Begin: key = g_strdup(_("Begin")); break;
2226 		case GDK_KEY_Delete: key = g_strdup(_("Delete")); break;
2227 		case GDK_KEY_Insert: key = g_strdup(_("Insert")); break;
2228 		case GDK_KEY_equal: key = g_strdup(_("Equal")); break;
2229 		case GDK_KEY_plus: key = g_strdup(_("Plus")); break;
2230 		case GDK_KEY_minus: key = g_strdup(_("Minus")); break;
2231 		case GDK_KEY_KP_Add: key = g_strdup(_("Add")); break;
2232 		case GDK_KEY_KP_Subtract: key = g_strdup(_("Subtract")); break;
2233 	    }
2234 	}
2235 	if (!key) key = g_strdup_printf("0x%x", p->key);
2236 	const gchar *icon = p->icon;
2237 	if (!icon && p->type == CHECKITEM_TYPE)icon = "xffm/emblem_synchronized";
2238 	else if (!icon && p->type == RADIOITEM_TYPE)icon = "xffm/emblem_favorite";
2239 	rfm_threaded_diagnostics(widgets_p, icon, NULL);
2240 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/red", g_strconcat(mod, key, " ",NULL));
2241 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/green", g_strconcat(_(p->string), "\n",NULL));
2242 	g_free(key);
2243 	g_free(mod);
2244     }
2245 }
2246 
2247 static gboolean
do_item_click(widgets_t * widgets_p,record_entry_t * en)2248 do_item_click(widgets_t *widgets_p, record_entry_t *en){
2249     TRACE ("do_item_click: %s\n", en->path);
2250     if (en && !IS_LOCAL_TYPE(en->type) &&
2251 	    !rfm_entry_available(widgets_p, en))  return TRUE;
2252     if ((!en->mimetype  || strcmp(en->mimetype, _("unknown"))==0) && !en->mimemagic){
2253 	if (IS_LOCAL_TYPE(en->type) && !en->mimemagic) {
2254 	    // avoid magic on remote fs...
2255 	    en->mimemagic = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_magic", "mime_function");
2256 	    if (!en->mimemagic) en->mimemagic = g_strdup(_("unknown"));
2257 	}
2258 	if (!en->mimemagic) en->mimemagic = g_strdup(_("unknown"));
2259     }
2260     const gchar *mimetype = en->mimetype;
2261     if (!mimetype || strcmp(mimetype, _("unknown"))==0){
2262 	mimetype = en->mimemagic;
2263     }
2264 
2265     if (strstr(mimetype, "application/x-desktop") &&
2266 	rfm_void(PLUGIN_DIR, "dotdesktop", "module_active")) {
2267 	rfm_rational(PLUGIN_DIR, "dotdesktop", widgets_p, en, "double_click");
2268 	return TRUE;
2269     }
2270     gchar *prg = MIME_command (mimetype);
2271     NOOP("prg=%s, mimetype=%s\n", prg, mimetype);
2272     if (prg) {
2273 	// This open_with, since prg != NULL, will
2274 	// open the associated application.
2275 	NOOP (stderr, "OPEN: calling rodent_open_with()\n");
2276 	open_with (widgets_p, en);
2277 	g_free (prg);
2278 	return TRUE;
2279 
2280     } else	if (IS_EXE_TYPE (en->type)) {
2281 	// Since there is no associated application, then try
2282 	// to execute the program if it has the exec bit on.
2283 	NOOP("rodent_mouse: using RFM_THREAD_RUN2ARGV\n");
2284 	view_t *view_p = widgets_p->view_p;
2285 	if (view_p->en && IS_LOCAL_TYPE(view_p->en->type)){
2286 	    g_free(widgets_p->workdir);
2287 	    widgets_p->workdir=g_strdup(view_p->en->path);
2288 	}
2289 	/*  assume in_term to be safe */
2290 	RFM_THREAD_RUN2ARGV (widgets_p, en->path, TRUE);
2291 	return TRUE;
2292 
2293     } else {
2294 	// this open_with, when prg==NULL will open the dialog, or
2295 	// default to default editor if file is editable.
2296 	open_with (widgets_p, en);
2297 	return TRUE;
2298 
2299     }
2300     DBG("do_item_click(): nothing programed here with double click: %s\n", en->path);
2301     return FALSE;
2302 }
2303 #define MODULE_EN(x) ((view_p->module)?view_p->module:(x)->module)
2304 
2305 static gboolean
do_folder_click(widgets_t * widgets_p,record_entry_t * en)2306 do_folder_click(widgets_t *widgets_p, record_entry_t *en){
2307     TRACE( " do_folder_click...\n");
2308 
2309     if (en && !IS_LOCAL_TYPE(en->type) &&
2310 	    !rfm_entry_available(widgets_p, en))  {
2311 	return TRUE;
2312     }
2313 
2314     view_t *view_p = widgets_p->view_p;
2315     view_t *view_target = view_p;
2316 
2317     // Action will proceed. Clear out selection list.
2318     // XXX not working....
2319     {
2320 	// XXX Mutex protection is missing here.
2321 	GSList *list = view_p->selection_list;
2322 	for (;list && list->data; list=list->next){
2323 	    rfm_destroy_entry((record_entry_t *)list->data);
2324 	}
2325 	g_slist_free(view_p->selection_list);
2326 	view_p->selection_list = NULL;
2327     }
2328 
2329     // Special treatment when item vanishes from system
2330     // (only local types to avoid blockage on network error).
2331     if (en && !en->module &&
2332 	    IS_SDIR(en->type) &&
2333 	    IS_LOCAL_TYPE(en->type) &&
2334 	    !g_file_test(en->path, G_FILE_TEST_IS_DIR)) {
2335 	NOOP("Element is not a directory (may no longer exist)\n");
2336 	// if go up icon selected, then go up...
2337 	if(IS_UP_TYPE(en->type))
2338 	{
2339 	    gchar *path=g_strdup(en->path);
2340 	    while (!rfm_g_file_test(path, G_FILE_TEST_IS_DIR)){
2341 		gchar *d = g_path_get_dirname(path);
2342 		g_free(path);
2343 		path = d;
2344 	    }
2345 	    record_entry_t *new_en =rfm_stat_entry(path, 0);
2346 	    if (!rodent_refresh (&(view_target->widgets), new_en)) rfm_destroy_entry(new_en);
2347 	    g_free(path);
2348 	} else {
2349 	    rfm_confirm(widgets_p, GTK_MESSAGE_WARNING, _("The location does not exist."), NULL, _("Accept"));
2350 	}
2351 	return TRUE;
2352 
2353 
2354     }
2355 
2356     // Default folder click action: jump to.
2357     if(en) UNSET_DUMMY_TYPE(en->type);
2358     if(en && IS_SDIR(en->type)){
2359 	// en != NULL implies that path is directory
2360 	rfm_save_to_go_history (en->path);
2361     }
2362 
2363     if(view_p->flags.type == DESKVIEW_TYPE &&
2364 	    (!getenv("RFM_NAVIGATE_DESKTOP") ||
2365 	     strlen(getenv("RFM_NAVIGATE_DESKTOP"))==0)){
2366 	// This will open in a new window.
2367 	// Basically for deskview type.
2368 	gchar *path=NULL;
2369 	if (en && MODULE_EN(en)) {
2370 	    path=g_strdup_printf("rodent-plug %s", MODULE_EN(en));
2371 	} else if (en){
2372 	    path=g_strdup(en->path);
2373 	}
2374 
2375 	NOOP ("DOUBLE_CLICK: en && view_p->child_constructor: %s (%s)\n", path, MODULE_EN(en));
2376 	rodent_new_gridview(widgets_p, path);
2377 	g_free(path);
2378 	return TRUE;
2379 
2380     }
2381     NOOP(stderr, "folder click... doing refresh...\n");
2382     // This is for the navigation history
2383     rodent_push_view_go_history ();
2384     // Quick visual response to the user:
2385      rodent_threaded_clean_paper(&(view_target->widgets));
2386     record_entry_t *new_en = rfm_copy_entry(en);
2387     // Deskview and iconview navigation:
2388     if(rodent_refresh (&(view_target->widgets), new_en)) {
2389 	if(en && en->path &&
2390 		IS_SDIR (en->type)){
2391 	    // This is for the combobox history
2392 	    rfm_save_to_go_history (en->path);
2393 	}
2394     } else {
2395 	rfm_destroy_entry(new_en);
2396 	rodent_expose_all (view_target);
2397     }
2398     return TRUE;
2399 }
2400 
2401 static void *
double_click(widgets_t * widgets_p)2402 double_click(widgets_t *widgets_p){
2403      rfm_global_t *rfm_global_p = rfm_global();
2404    view_t *view_p = widgets_p->view_p;
2405     record_entry_t *en = NULL;
2406     g_mutex_lock(view_p->mutexes.status_mutex);
2407     gboolean status = view_p->flags.status;
2408     g_mutex_unlock(view_p->mutexes.status_mutex);
2409     if(status == STATUS_EXIT) return NULL;
2410 
2411     if (view_p->selection_list)
2412 	en = rfm_copy_entry((record_entry_t *)view_p->selection_list->data);
2413 
2414     NOOP( "**** double_click\n");
2415     //hide_tip (view_p);
2416 
2417 
2418     if(en && !en->module && IS_NOACCESS_TYPE (en->type) && !IS_PARTITION_TYPE(en->type)) {
2419 	rfm_threaded_show_text(widgets_p);
2420 	rfm_threaded_diagnostics (widgets_p, "xffm/stock_dialog-error", NULL);
2421 	rfm_threaded_diagnostics (widgets_p, "xffm_tag/stderr",
2422 		g_strconcat(strerror(EACCES), ": '", en->path, "'\n", NULL));
2423 	rfm_threaded_cursor_reset(rfm_global_p->window);
2424 	rfm_destroy_entry(en);
2425 	return NULL;
2426     }
2427 
2428     /* does the POPULATION_MODULE have something else in mind for the
2429        double click on the particular entry ? */
2430 
2431     gboolean item_click=FALSE;
2432     gboolean folder_click=FALSE;
2433     gboolean module_click=FALSE;
2434     if (en){
2435 	if (en && MODULE_EN(en)) {
2436 	    module_click = TRUE;
2437 	}
2438 	if (IS_SDIR (en->type)){
2439 	    folder_click = TRUE;
2440 	} else if (g_path_is_absolute (en->path)){
2441 	    item_click = TRUE;
2442 	} else if (module_click) {
2443 	    folder_click = TRUE;
2444 	}
2445     } else {
2446 	folder_click = TRUE;
2447     }
2448     TRACE( "Mouse: module_click=%d, item_click=%d, folder_click=%d\n",
2449 	    module_click,item_click, folder_click);
2450     // if the POPULATION_MODULE's double_click function does not exist or
2451     // returns NULL, callback proceeds with either item or folder behaviour.
2452     if (module_click &&
2453 	rfm_rational(PLUGIN_DIR, MODULE_EN(en), widgets_p, en,  "double_click"));
2454     else if (item_click) do_item_click(widgets_p, en);
2455     else if (folder_click) do_folder_click(widgets_p, en);
2456     else DBG("double_click(): should not reach this point (harmless though)\n");
2457 
2458     rfm_threaded_cursor_reset(rfm_global_p->window);
2459     rfm_destroy_entry(en);
2460     return NULL;
2461 }
2462 
2463 /////////////////////////////////////
2464 // Thread pool refactoring ready...//
2465 /////////////////////////////////////
2466 
2467 static void
apply_new_icon_size(view_t * view_p)2468 apply_new_icon_size (view_t *view_p){
2469     static gboolean running = FALSE;
2470     if (running){
2471         DBG("Quietely ignoring apply_new_icon_size until current execution is done.\n");
2472         return;
2473     } else running = TRUE;
2474     TRACE("apply_new_icon_size: id=%d size=%d\n", ICON_SIZE_ID(view_p) ,ICON_SIZE(view_p));
2475     if (!rfm_population_read_lock (view_p, "apply_new_icon_size")) {
2476         running = FALSE;
2477 	return ;
2478     }
2479     if (view_p->module){
2480 	// Set the iconsize in the module for the view_p.
2481 	gint size = ICON_SIZE_ID(view_p);
2482 	if (!size) size = -1;
2483 	rfm_rational(PLUGIN_DIR,view_p->module, view_p,
2484 		GINT_TO_POINTER(size), "module_icon_size");
2485     }
2486     //record_entry_t *en = rfm_copy_entry (view_p->en);
2487     rfm_save_view_preferences (view_p, view_p->en);
2488 
2489     view_p->flags.thumbnailer_active=TRUE;
2490     population_t **p = view_p->population_pp;
2491     gint element=0;
2492     for (;p && *p; p++, element++){
2493         population_t *population_p = *p;
2494         // FIXME: here we should resolve with the same procedure as used
2495         //        when initially loaded. This here is borked (using icontheme though not selected)
2496         //        but this *only* happens when monitor is disabled!
2497         //        Remove iconsize changes from monitor... Everything should be here.
2498         if (population_p->layout) g_object_unref(population_p->layout);
2499         population_p->layout=NULL;
2500         if (population_p->layout2) g_object_unref(population_p->layout2);
2501         population_p->layout2=NULL;
2502         if (population_p->layout_full) g_object_unref(population_p->layout_full);
2503         population_p->layout_full=NULL;
2504 
2505         if (population_p->pixbuf) g_object_unref(population_p->pixbuf);
2506         population_p->pixbuf = NULL;
2507 
2508         population_p->icon_size=ICON_SIZE(view_p);
2509         population_p->icon_size_id = ICON_SIZE_ID(view_p);
2510 
2511 
2512         // No monitor, then get new icons here...
2513         if (10) {
2514             if (population_p->flags & POPULATION_IS_IMAGE){
2515                 GdkPixbuf *pixbuf = rfm_create_preview (population_p->en->path, population_p->icon_size);//refs
2516                 if (pixbuf) {
2517                     population_p->thumbnail = pixbuf;
2518                     population_p->flags |= POPULATION_PIXBUF_CLEAN;
2519                     if (element % 5 == 0) rodent_expose_all(view_p);
2520                     //rfm_expose_item(view_p, population_p);
2521                 }
2522             }
2523 
2524             if (population_p->pixbuf == NULL) {
2525                 if (population_p->icon_id)
2526                     population_p->pixbuf = rfm_get_pixbuf(population_p->icon_id, ICON_SIZE(view_p));
2527                 else if (population_p->en && population_p->en->mimetype)
2528                     population_p->pixbuf = rfm_get_pixbuf(population_p->en->mimetype, ICON_SIZE(view_p));
2529                 else if (population_p->en && population_p->en->mimemagic)
2530                     population_p->pixbuf = rfm_get_pixbuf(population_p->en->mimemagic, ICON_SIZE(view_p));
2531                 else
2532                     population_p->pixbuf = rfm_get_pixbuf("xffm/whatever", ICON_SIZE(view_p));
2533 
2534             }
2535         } else {
2536             // monitor will take care of new icons
2537             // path absolute, en != NULL en-module ==NULL
2538             // memset(population_p->en->st, 0., sizeof(struct stat));
2539         }
2540         population_p->layout=NULL;
2541         population_p->layout2=NULL;
2542         population_p->layout_full=NULL;
2543 
2544         rfm_layout_pango_layout_setup(view_p); // this gets name column width for details view
2545         rfm_layout_population_grid_row (view_p, population_p, element); // this sets correct row,col
2546     }
2547 
2548     rfm_population_read_unlock (view_p, "apply_new_icon_size");
2549     rodent_expose_all(view_p);
2550     view_p->flags.thumbnailer_active=FALSE;
2551     running = FALSE;
2552 
2553 }
2554 
2555 static GMutex *
get_sweep_mutex(void)2556 get_sweep_mutex(void){
2557     static GMutex *mutex = NULL;
2558     static gsize initialized = 0;
2559     if (g_once_init_enter (&initialized)){
2560 	rfm_mutex_init(mutex);
2561       g_once_init_leave (&initialized, 1);
2562     }
2563     return mutex;
2564 }
2565 static void
reset_saved_iconsize(DBHashTable * old)2566 reset_saved_iconsize (DBHashTable * old) {
2567     DBHashTable *new = old->sweep_data;
2568     gint record_size = DBH_RECORD_SIZE(old);
2569 
2570     dbh_set_recordsize (new, record_size);
2571     memcpy(DBH_KEY(new), DBH_KEY(old), DBH_KEYLENGTH(old));
2572     memcpy(new->data, old->data, record_size);
2573     view_preferences_t *view_preferences_p = new->data;
2574     view_preferences_p->icon_size = rfm_get_default_size();
2575     NOOP("sweep now, record size=%d\n", record_size);
2576     dbh_update(new);
2577     return;
2578 }
2579 
2580 static void
default_iconsize_all(widgets_t * widgets_p)2581 default_iconsize_all (widgets_t *widgets_p){
2582     // The easy way would be just to unlink the preferences file,
2583     // but that would take down sort orders and show hidden
2584     // attributes as well. So instead we just set each saved preference
2585     // item to user default size.
2586     NOOP("rodent_default_iconsize_all\n");
2587 
2588     view_t *view_p = widgets_p->view_p;
2589     gint default_size = rfm_get_default_size();
2590 
2591     gchar *f;
2592     if (view_p->flags.type==ICONVIEW_TYPE) {
2593 	f = g_build_filename (GRID_PREFERENCES_FILE, NULL);
2594     } else {
2595 	f = g_build_filename (DESK_PREFERENCES_FILE, NULL);
2596     }
2597     FILE *f_p = fopen(f,"r");
2598     if (!f_p){
2599 	g_free(f);
2600 	return;
2601     }
2602     fclose(f_p);
2603     TRACE("opening %s...\n",f);
2604     DBHashTable *old = dbh_new (f, NULL, DBH_PARALLEL_SAFE);
2605     TRACE("opened %s.\n",f);
2606     if(old == NULL) {
2607 	g_free(f);
2608 	return;
2609     }
2610     dbh_set_parallel_lock_timeout(old, 3);
2611 
2612     gchar *ff=g_strconcat(f,"-new",NULL);
2613     GMutex *sweep_mutex=get_sweep_mutex() ;
2614     g_mutex_lock(sweep_mutex);
2615     unsigned char keylength=DBH_KEYLENGTH (old);
2616     gchar *directory = g_path_get_dirname(ff);
2617     if (!g_file_test(directory, G_FILE_TEST_IS_DIR)){
2618         g_mkdir_with_parents(directory, 0700);
2619     }
2620     g_free(directory);
2621     TRACE("opening %s...\n",ff);
2622     DBHashTable *new = dbh_new (ff, &keylength, DBH_PARALLEL_SAFE|DBH_CREATE);
2623     TRACE("open %s.\n",ff);
2624 
2625     if(new == NULL) {
2626 	dbh_close(old);
2627 	DBG("cannot create file %s\n", ff);
2628 	g_free(f);
2629 	g_free(ff);
2630 	g_mutex_unlock(sweep_mutex);
2631 	return;
2632     }
2633     dbh_set_parallel_lock_timeout(new, 3);
2634     old->sweep_data = new;
2635     NOOP("sweep now\n");
2636     dbh_foreach_sweep (old, reset_saved_iconsize);
2637 
2638     dbh_close(old);
2639     dbh_close(new);
2640 
2641     /*if (unlink(f) < 0) {
2642 	DBG("unlink(%s): %s\n", f, strerror(errno));
2643     }*/
2644     NOOP("rename(%s, %s)\n", f, ff);
2645     if (rename (ff,f) < 0) {
2646 	DBG("rename(%s, %s): %s\n", f, ff, strerror(errno));
2647     }
2648 
2649 
2650     g_free(f);
2651     g_free(ff);
2652 
2653     g_mutex_unlock(sweep_mutex);
2654 
2655     if (default_size != ICON_SIZE_ID(view_p)) {
2656 	rfm_layout_set_icon_size_full(view_p, default_size);
2657 	apply_new_icon_size (view_p);
2658     }
2659 }
2660 static void
default_iconsize(widgets_t * widgets_p)2661 default_iconsize (widgets_t *widgets_p){
2662     view_t *view_p = widgets_p->view_p;
2663     gint default_size = rfm_get_default_size();
2664     if (default_size != ICON_SIZE_ID(view_p)) {
2665 	rfm_layout_set_icon_size_full(view_p, default_size);
2666 	apply_new_icon_size (view_p);
2667     }
2668 }
2669 
2670 static void
increase_iconsize(widgets_t * widgets_p)2671 increase_iconsize (widgets_t *widgets_p){
2672     view_t *view_p = widgets_p->view_p;
2673     gint original_size = ICON_SIZE_ID(view_p);
2674     gint new_size = original_size + 24;
2675     //if (new_size > BIG_ICON_SIZE) new_size = LIST_ICON_SIZE;
2676     if (new_size > BIG_ICON_SIZE) new_size = BIG_ICON_SIZE;
2677     TRACE( "newsize/original %d/%d\n", new_size, original_size);
2678 
2679     if (original_size != new_size) {
2680 	rfm_layout_set_icon_size_full(view_p, new_size);
2681 	apply_new_icon_size (view_p);
2682     }
2683 }
2684 
2685 static void
decrease_iconsize(widgets_t * widgets_p)2686 decrease_iconsize (widgets_t *widgets_p){
2687     view_t *view_p = widgets_p->view_p;
2688     gint original_size = ICON_SIZE_ID(view_p);
2689     gint new_size = original_size - 24;
2690     //if (new_size < LIST_ICON_SIZE) new_size = BIG_ICON_SIZE;
2691     if (new_size < LIST_ICON_SIZE) new_size = LIST_ICON_SIZE;
2692     if (original_size != new_size) {
2693 	rfm_layout_set_icon_size_full(view_p, new_size);
2694 	apply_new_icon_size (view_p);
2695     }
2696 }
2697 
2698 
2699 static void
toggle_casesort(widgets_t * widgets_p)2700 toggle_casesort(widgets_t *widgets_p){
2701     view_t *view_p = widgets_p->view_p;
2702     // Toggle value
2703     view_p->flags.preferences ^= __CASE_INSENSITIVE;
2704 
2705     rfm_save_view_preferences (view_p, view_p->en);
2706     record_entry_t *en = rfm_copy_entry (view_p->en);
2707     NOOP(stderr, "*-*-*-* toggle_casesort rodent_refresh\n");
2708     if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
2709 }
2710 
2711 static void
backup_unbackup(widgets_t * widgets_p)2712 backup_unbackup(widgets_t *widgets_p){
2713     view_t *view_p = widgets_p->view_p;
2714 
2715     // Toggle value
2716     view_p->flags.preferences ^= __SHOWS_BACKUP;
2717     rfm_save_view_preferences (view_p, view_p->en);
2718     record_entry_t *en = rfm_copy_entry (view_p->en);
2719     /*if (SHOWS_BACKUP(view_p->flags.preferences)) {
2720 	SET_SHOWS_BACKUP(en->type);
2721     } else {
2722 	UNSET_SHOWS_BACKUP(en->type);
2723     }*/
2724     rodent_unsaturate_icon (view_p);
2725 
2726     if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
2727 }
2728 
2729 static void
hide_unhide(widgets_t * widgets_p)2730 hide_unhide(widgets_t *widgets_p){
2731     view_t *view_p = widgets_p->view_p;
2732 
2733     // Toggle value
2734     view_p->flags.preferences ^= __SHOW_HIDDEN;
2735     rfm_save_view_preferences (view_p, view_p->en);
2736     record_entry_t *en = rfm_copy_entry (view_p->en);
2737     /*if (SHOWS_HIDDEN(view_p->flags.preferences)) {
2738 	SET_SHOWS_HIDDEN(en->type);
2739     } else {
2740 	UNSET_SHOWS_HIDDEN(en->type);
2741     }*/
2742     rodent_unsaturate_icon (view_p);
2743 
2744     if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
2745 }
2746 
2747 static void
preview(widgets_t * widgets_p)2748 preview (widgets_t *widgets_p) {
2749     view_t *view_p = widgets_p->view_p;
2750 
2751     // Toggle value
2752     view_p->flags.preferences ^= __SHOW_IMAGES;
2753     // Save preferences
2754     rfm_save_view_preferences (view_p, view_p->en);
2755     // Now do the refresh.
2756     record_entry_t *en = rfm_copy_entry (view_p->en);
2757     if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
2758 }
2759 
2760 static void
sort(widgets_t * widgets_p,gpointer user_data)2761 sort(widgets_t *widgets_p, gpointer user_data){
2762     view_t *view_p = widgets_p->view_p;
2763     view_p->flags.sortcolumn = GPOINTER_TO_INT (user_data);
2764     switch (GPOINTER_TO_INT (user_data)){
2765 	case DATE_SORT:
2766 	case SIZE_SORT:
2767 	case MODE_SORT:
2768 	view_p->flags.preferences &= (SORT_ASCENDING ^ 0xffffffff);
2769 		break;
2770 	default:
2771 	view_p->flags.preferences |= SORT_ASCENDING;
2772     }
2773     NOOP(stderr, "sort callback: return on apply new sort: %d\n", GPOINTER_TO_INT (user_data));
2774     rfm_save_view_preferences (view_p, view_p->en);
2775     record_entry_t *en = rfm_copy_entry (view_p->en);
2776     if (!rodent_refresh (widgets_p, en)){ rfm_destroy_entry(en); }
2777 }
2778 
2779 static void
size(widgets_t * widgets_p,gpointer user_data)2780 size(widgets_t *widgets_p, gpointer user_data){
2781     NOOP(stderr, "size now...\n");
2782     view_t *view_p = widgets_p->view_p;
2783     gint new_size = GPOINTER_TO_INT (user_data);
2784     if (new_size != ICON_SIZE_ID(view_p)) {
2785 	rfm_layout_set_icon_size_full(view_p, new_size);
2786         apply_new_icon_size (view_p);
2787     }
2788 }
2789 
2790 
2791 /*****************************************************************************/
2792 
2793 
2794 // New thread pool compatible method.
2795 static void *
threaded_callback(void * data)2796 threaded_callback(void *data){
2797     TRACE("threaded_callback()...\n");
2798     void **arg = data;
2799     enum menu_enum_t menu_enum = GPOINTER_TO_INT(arg[0]);
2800     GtkWidget *menuitem = arg[1];
2801     view_t *view_p = arg[2];
2802 
2803     g_free(data);
2804 
2805     // Put a lock on the view list to hold janitor in
2806     // case the view scheduled to be destroyed.
2807     // This will return false if view_p is no longer valid.
2808     if (!rfm_view_list_lock(view_p, "threaded_callback")) return NULL;
2809 
2810     widgets_t *widgets_p = &(view_p->widgets);
2811 
2812     // Do we really need to stop monitor?
2813     // Probably. I had a crash on a ctrl-f, when it tests for directory
2814     // condition. But placed in such a top level place as such, it
2815     // causes diverse callback deadlocks. Must fine tune the lock placement.
2816     //rfm_rw_lock_reader_lock (&(view_p->mutexes.monitor_lock));
2817 
2818 	NOOP(stderr, "threaded_callback: 0x%d\n", menu_enum);
2819 
2820     gboolean valid = FALSE;
2821     switch (menu_enum){
2822   	case RENAME_ACTIVATE:
2823  	case DUPLICATE_ACTIVATE:
2824  	case SYMLINK_ACTIVATE:
2825 	case MOUNT_ACTIVATE:
2826  	case UNMOUNT_ACTIVATE:
2827  	case AUTOTYPE_ACTIVATE:
2828  	case AUTOTYPE_R_ACTIVATE:
2829 	    if (!is_valid_view_entry(widgets_p, menu_enum)) break;
2830 	    if (!is_single_selection(widgets_p, menu_enum)) break;
2831 	    valid = TRUE; break;
2832 
2833   	case BCRYPT_ACTIVATE:
2834 	case OPEN_WITH_ACTIVATE:
2835   	case TOUCH_ACTIVATE:
2836  	case PROPERTIES_ACTIVATE:
2837 	case REMOVE_ACTIVATE:
2838 	case CUT_ACTIVATE:
2839  	case COPY_ACTIVATE:
2840 	    if (!is_valid_view_entry(widgets_p, menu_enum)) break;
2841 	    if (!is_multiple_selection(widgets_p, menu_enum)) break;
2842 	    valid = TRUE; break;
2843 
2844  	case PASTE_ACTIVATE:
2845 	case DIFFERENCES_ACTIVATE:
2846 	case RELOAD_ACTIVATE:
2847 	case REFRESH_ACTIVATE:
2848 	case NEW_WINDOW_ACTIVATE:
2849 	case NEW_TAB_ACTIVATE:
2850 	case NEWDIR_ACTIVATE:
2851 	case NEWFILE_ACTIVATE:
2852 	case UNSELECT_ALL_ACTIVATE:
2853 	case SELECT_INVERT_ACTIVATE:
2854 	case SELECT_ALL_ACTIVATE:
2855 	case UNSELECT_BY_FILTER_ACTIVATE:
2856 	case SELECT_BY_FILTER_ACTIVATE:
2857 	case BOOKMARK_TOGGLED:
2858 	case ASCENDING_ACTIVATE:
2859 	case DESCENDING_ACTIVATE:
2860 	case BOOKMARK_ADD_ACTIVATE:
2861 	case BOOKMARK_REMOVE_ACTIVATE:
2862 	case LS_ACTIVATE:
2863 	    if (!is_valid_view_entry(widgets_p, menu_enum)) break;
2864 	    valid = TRUE; break;
2865 	// toggles:
2866 	case HIDDEN_TOGGLED:
2867 	case BACKUP_TOGGLED:
2868 	case PREVIEW_TOGGLED:
2869 	case CASESORT_TOGGLED:
2870 
2871 
2872 	case NAME_SORT_ACTIVATE:
2873 	case TYPE_SORT_ACTIVATE:
2874 	case DATE_SORT_ACTIVATE:
2875 	case SIZE_SORT_ACTIVATE:
2876 	case OWNER_SORT_ACTIVATE:
2877 	case GROUP_SORT_ACTIVATE:
2878 	case MODE_SORT_ACTIVATE:
2879 	    if (!is_valid_view_entry(widgets_p, menu_enum)) break;
2880 	    valid = TRUE; break;
2881 
2882 	case COMPACT_ICONSIZE_TOGGLED:
2883 	case TINY_ICONSIZE_TOGGLED:
2884 	case NORMAL_ICONSIZE_TOGGLED:
2885 	case BIG_ICONSIZE_TOGGLED:
2886 	case HUGE_ICONSIZE_TOGGLED:
2887 	case PLUS_ICONSIZE_ACTIVATE:
2888 	case MINUS_ICONSIZE_ACTIVATE:
2889 	case DEFAULT_ICONSIZE_ACTIVATE:
2890 	case DEFAULT_ICONSIZE_ALL_ACTIVATE:
2891 	default:
2892 	    valid = TRUE;
2893     }
2894     NOOP(  "***** callback: valid=%d\n", valid);
2895     if (valid) switch (menu_enum){
2896 
2897 // Size callbacks:
2898 	case COMPACT_ICONSIZE_TOGGLED:
2899 	    size(widgets_p, GINT_TO_POINTER(LIST_ICON_SIZE)); break;
2900 	case TINY_ICONSIZE_TOGGLED:
2901 	    size(widgets_p, GINT_TO_POINTER(TINY_ICON_SIZE)); break;
2902 	case NORMAL_ICONSIZE_TOGGLED:
2903 	    size(widgets_p, GINT_TO_POINTER(SMALL_ICON_SIZE)); break;
2904 	case BIG_ICONSIZE_TOGGLED:
2905 	    size(widgets_p, GINT_TO_POINTER(MEDIUM_ICON_SIZE)); break;
2906 	case HUGE_ICONSIZE_TOGGLED:
2907 	    size(widgets_p, GINT_TO_POINTER(BIG_ICON_SIZE)); break;
2908 	case PLUS_ICONSIZE_ACTIVATE:
2909 	    increase_iconsize(widgets_p); break;
2910 	case MINUS_ICONSIZE_ACTIVATE:
2911 	    decrease_iconsize(widgets_p); break;
2912 	case DEFAULT_ICONSIZE_ACTIVATE:
2913 	    default_iconsize(widgets_p); break;
2914 	case DEFAULT_ICONSIZE_ALL_ACTIVATE:
2915 	    default_iconsize_all(widgets_p); break;
2916 // Edit callbacks:
2917 	case CUT_ACTIVATE: copy_cut_callback (widgets_p, TRUE); break;
2918  	case COPY_ACTIVATE: copy_cut_callback (widgets_p, FALSE); break;
2919  	case PASTE_ACTIVATE: paste_callback (widgets_p, FALSE); break;
2920 	case REMOVE_ACTIVATE: remove_x( widgets_p); break;
2921 	case DIFFERENCES_ACTIVATE: differences( widgets_p); break;
2922  	case TOUCH_ACTIVATE: touch(widgets_p); break;
2923  	case PROPERTIES_ACTIVATE: properties(widgets_p); break;
2924 	case ACTIVATE: double_click(widgets_p); break;
2925 	case RUN_ACTIVATE: run(widgets_p); break;
2926 	case OPEN_WITH_ACTIVATE: open_x(widgets_p); break;
2927  	case MOUNT_ACTIVATE: mount(widgets_p); break;
2928  	case UNMOUNT_ACTIVATE: unmount(widgets_p); break;
2929  	case AUTOTYPE_ACTIVATE: autotype(widgets_p, menuitem); break;
2930  	case AUTOTYPE_R_ACTIVATE: autotype_r(widgets_p, menuitem); break;
2931 
2932 	case FIND_ACTIVATE:
2933 	case GLOB_ACTIVATE: glob_x(widgets_p); break;
2934 
2935   	case BCRYPT_ACTIVATE: bcrypt( widgets_p); break;
2936 	case LS_ACTIVATE: ls(widgets_p); break;
2937   	case RENAME_ACTIVATE: rename_x( widgets_p); break;
2938  	case DUPLICATE_ACTIVATE: duplicate( widgets_p); break;
2939  	case SYMLINK_ACTIVATE: symlink_x( widgets_p); break;
2940  	case DONE_WITH_RENAME:
2941 		rfm_context_function(done_with_rename, widgets_p);
2942 		break;
2943 // View independent callbacks
2944  	case KEYBINDINGS_ACTIVATE:  keybindings(widgets_p); break;
2945 	case HELP_ACTIVATE: help(widgets_p); break;
2946 	case ABOUT_ACTIVATE: about(widgets_p); break;
2947 
2948 	case HOST_ACTIVATE: host(widgets_p); break;
2949 	case OPEN_IN_TERMINAL_ACTIVATE: open_in_terminal(widgets_p); break;
2950 	case SETTINGS_ACTIVATE: settings(widgets_p); break;
2951  	case CLOSE_ACTIVATE: close_x(widgets_p); break;
2952  	case QUIT_ACTIVATE: quit(widgets_p); break;
2953  	case MENU_ACTIVATE:
2954 		DBG("MENU_ACTIVATE: should not reach here.\n");
2955 		break;
2956 
2957 /////////////////////
2958 
2959 // Go Callbacks:
2960 	case PLUGIN_GOTO_ACTIVATE: plugin_goto(widgets_p, menuitem); break;
2961 	case LEVEL_GOTO_ACTIVATE: level_goto(widgets_p, menuitem); break;
2962  	case BOOKMARK_ADD_ACTIVATE: bookmark_add(widgets_p, menuitem); break;
2963  	case BOOKMARK_REMOVE_ACTIVATE: bookmark_remove(widgets_p, menuitem); break;
2964 
2965 	case RELOAD_ACTIVATE:
2966 	case REFRESH_ACTIVATE: refresh(widgets_p); break;
2967 	case GOUP_ACTIVATE: goup(widgets_p); break;
2968 	case FORWARD_ACTIVATE: forward(widgets_p); break;
2969 	case BACK_ACTIVATE: back(widgets_p); break;
2970 	case HOME_ACTIVATE: home(widgets_p); break;
2971 	case JUMP_TO_ACTIVATE: jump_to(widgets_p); break;
2972 	case HIDDEN_TOGGLED: hide_unhide(widgets_p); break;
2973 	case BACKUP_TOGGLED: backup_unbackup(widgets_p); break;
2974 	case PREVIEW_TOGGLED: preview(widgets_p); break;
2975 	case NAME_SORT_ACTIVATE: sort(widgets_p,
2976 					 GINT_TO_POINTER(NAME_SORT)); break;
2977 	case TYPE_SORT_ACTIVATE: sort(widgets_p,
2978 					 GINT_TO_POINTER(TYPE_SORT)); break;
2979 	case DATE_SORT_ACTIVATE: sort(widgets_p,
2980 					 GINT_TO_POINTER(DATE_SORT)); break;
2981 	case SIZE_SORT_ACTIVATE: sort(widgets_p,
2982 					 GINT_TO_POINTER(SIZE_SORT)); break;
2983 	case OWNER_SORT_ACTIVATE: sort(widgets_p,
2984 					  GINT_TO_POINTER(OWNER_SORT)); break;
2985 	case GROUP_SORT_ACTIVATE: sort(widgets_p,
2986 					  GINT_TO_POINTER(GROUP_SORT)); break;
2987 	case MODE_SORT_ACTIVATE: sort(widgets_p,
2988 					 GINT_TO_POINTER(MODE_SORT)); break;
2989 	case NEW_WINDOW_ACTIVATE: new_window(widgets_p); break;
2990 	case NEW_TAB_ACTIVATE: new_tab_f(widgets_p); break;
2991 	case NEWDIR_ACTIVATE: newdir (widgets_p); break;
2992  	case NEWFILE_ACTIVATE: newfile (widgets_p); break;
2993  	case UNSELECT_ALL_ACTIVATE: unselect_all(widgets_p); break;
2994 	case SELECT_INVERT_ACTIVATE: select_all(widgets_p, GINT_TO_POINTER(1)); break;
2995  	case SELECT_ALL_ACTIVATE: select_all(widgets_p, NULL); break;
2996 	case UNSELECT_BY_FILTER_ACTIVATE: select_by_filter(widgets_p, NULL); break;
2997  	case SELECT_BY_FILTER_ACTIVATE: select_by_filter(widgets_p, GINT_TO_POINTER(1)); break;
2998  	case BOOKMARK_TOGGLED: toggle_bookmark(widgets_p); break;
2999  	case CASESORT_TOGGLED:  toggle_casesort(widgets_p); break;
3000 	case ASCENDING_ACTIVATE:
3001 	case DESCENDING_ACTIVATE:
3002 	    ascending_descending(widgets_p, menu_enum); break;
3003 
3004 
3005 //////////////
3006 // Dummy item:
3007 	case ENUM_CALLBACKS: break;
3008 
3009    } // end switch.
3010 
3011     //rfm_rw_lock_reader_unlock (&(view_p->mutexes.monitor_lock));
3012 
3013     rfm_view_list_unlock("threaded_callback()");
3014     TRACE("** threaded_callback is done\n");
3015    return NULL;
3016 }
3017 
3018 
3019