1 /*
2 * Copyright (C) 2002-2012 Edscott Wilson Garcia
3 * EMail: edscott@users.sf.net
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program;
18 */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include "rodent.h"
24 #include "rfm_modules.h"
25 #include "rodent_popup.i"
26
27 void
rodent_update_menu(GtkWidget * menu)28 rodent_update_menu(GtkWidget *menu){
29 if (!menu || !GTK_IS_CONTAINER(menu)) return;
30 // First, hide everything in menu.
31 #if GTK_MAJOR_VERSION==2 && GTK_MINOR_VERSION<24
32 // This is deprecated as of 2.24, which forces us
33 // to get children and hide each one of them... bleah!
34 gtk_widget_hide_all (menu);
35 #else
36 GList *children = gtk_container_get_children(GTK_CONTAINER(menu));
37 GList *tmp=children;
38 for (; tmp && tmp->data; tmp = tmp->next){
39 if(GTK_IS_WIDGET(tmp->data)) gtk_widget_hide (GTK_WIDGET(tmp->data));
40 }
41 g_list_free(children);
42 #endif
43 widgets_t *widgets_p = rfm_get_widget ("widgets_p");
44 view_t *view_p = widgets_p->view_p;
45
46 // Show the file menu
47 SHOW_IT("file_menu");
48 // hide items in file menu
49 HIDE_IT("rename_menuitem");
50 HIDE_IT("duplicate_menuitem");
51 HIDE_IT("symlink_menuitem");
52 HIDE_IT("touch_menuitem");
53 HIDE_IT("properties_menuitem");
54
55 // Show search item if we have fgr
56 gchar *fgr = g_find_program_in_path("rodent-fgr");
57 if (fgr) SHOW_IT ( "find2");
58 g_free(fgr);
59
60 // Next, show other items on a need to see basis.
61 //
62 // First test, do we have a valid associated population_p?
63 gint items=g_slist_length(view_p->selection_list);
64 if (items == 1){
65 // Yes, we do. So we show the cp/mv/ln items.
66 SHOW_IT("rename_menuitem");
67 SHOW_IT("duplicate_menuitem");
68 SHOW_IT("symlink_menuitem");
69 }
70 if (items && view_p->selection_list->data ) {
71 HIDE_IT ( "addbookmark_menuitem");
72 HIDE_IT ( "removebookmark_menuitem");
73 show_remove_item(view_p);
74 show_open_items(view_p);
75 show_properties_item(view_p);
76 if (items==1) {
77 // Mimetype specific items are shown here:
78 popup_autostuff (view_p->selection_list->data);
79
80 // Does the item need the mount/umount item?
81 // This will only be effective if fstab plugin is loadable.
82 show_mount_item(view_p);
83
84 record_entry_t *en = view_p->selection_list->data;
85 if (IS_SDIR(en->type)){
86 gboolean on = rodent_path_is_bookmarkable(en->path);
87 if (on) setup_bookmark_menuitem( en, "addbookmark_menuitem", on);
88 else setup_bookmark_menuitem( en, "removebookmark_menuitem", on);
89 }
90 }
91 if(view_p->module) {
92 rfm_rational (PLUGIN_DIR, view_p->module, widgets_p,
93 view_p->selection_list->data, "hide_local_menu_items");
94 rfm_rational (PLUGIN_DIR, view_p->module, widgets_p,
95 view_p->selection_list->data, "show_local_menu_items");
96 }
97 SHOW_IT ("touch_menuitem");
98 }
99 else {
100 //rodent_reset_menu_toggles ();// this is now after popup is mapped
101 rodent_reset_menu ();
102 }
103
104 }
105
106 void
rodent_pop_menu(const gchar * menu_id,GdkEventButton * event)107 rodent_pop_menu (const gchar *menu_id, GdkEventButton * event) {
108 gboolean is_thread = (g_thread_self() != rfm_get_gtk_thread());
109 if (is_thread){
110 g_error("rodent_pop_menu: fixme, this is broken when called from a thread\n");
111 return;
112 }
113 widgets_t *widgets_p = rfm_get_widget ("widgets_p");
114 view_t *view_p = widgets_p->view_p;
115
116 if(view_p->module && !(event->state & GDK_CONTROL_MASK)){
117 if (rfm_rational (PLUGIN_DIR, view_p->module,
118 widgets_p, NULL,
119 "private_popup")) return ;
120 }
121
122 GtkMenu *menu = rfm_get_widget(menu_id);
123 if (!menu){
124 DBG("Menu not ready: be patient\n");
125 return;
126 }
127 #if 10
128 // hide/show items depending on context:
129 rodent_update_menu(GTK_WIDGET(menu));
130 #endif
131 // pop it:
132 NOOP(stderr, "gtk_menu_popup \"%s\" now...\n", menu_id);
133 #if GTK_MAJOR_VERSION<3
134 //gtk_menu_popup (menu, rfm_get_widget("main_popup_menu_menu"), NULL, NULL, NULL, 3, event->time);
135 gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 3, event->time);
136 #else
137 GdkDeviceManager *gdm =
138 gdk_display_get_device_manager (gdk_display_get_default());
139 gtk_menu_popup_for_device (menu,
140 gdk_device_manager_get_client_pointer(gdm), // GdkDevice *device,
141 NULL, NULL, NULL, NULL,
142 NULL, //GDestroyNotify destroy,
143 3, event->time);
144 #endif
145
146 #if 10
147 // Finally, set toggles to correct setting (with popup mapped).
148 if (!g_slist_length(view_p->selection_list) || !view_p->selection_list->data ) {
149 rodent_reset_menu_toggles ();
150 }
151 #endif
152
153
154 NOOP(stderr, "menu popped \"%s\" now...\n", menu_id);
155 return ;
156 }
157
158 ///////////////////////////////////////////////////////////////////////////////////
159 ///////////////////////////////////////////////////////////////////////////////////
160 void
rodent_push_view_go_history(void)161 rodent_push_view_go_history (void) {
162 widgets_t *widgets_p = rfm_get_widget ("widgets_p");
163 if (!widgets_p) return;
164 view_t *view_p = widgets_p->view_p;
165
166 record_entry_t *history_en;
167 /*if (!view_p->en || !view_p->en->path) return; */
168 if(view_p->go_list) {
169 GList *last = g_list_last (view_p->go_list);
170 record_entry_t *last_en;
171 last_en = last->data;
172 if(!last_en && !view_p->en)
173 return; /* NULL case */
174 if(last_en && view_p->en) {
175 if(!last_en->path && !view_p->en->path)
176 return;
177 if(last_en->path && view_p->en->path) {
178 if(strcmp (last_en->path, view_p->en->path) == 0)
179 return;
180 }
181 }
182 }
183 history_en = rfm_copy_entry (view_p->en);
184 view_p->go_list = g_list_append (view_p->go_list, history_en);
185 //if (view_p->f_list){}
186
187
188 return;
189 }
190 ////////////////////////////////////////////////////////////
191 ////////////////////////////////////////////////////////////
192
193 /****************/
194
195
196 void
rodent_reset_menu(void)197 rodent_reset_menu (void) {
198 widgets_t *widgets_p = rfm_get_widget ("widgets_p");
199 view_t * view_p = widgets_p->view_p;
200 gchar *void_items[]={"goto_menu", "sort_menu", "view_menu", "help_menu", "refresh3", "run2", "navigation_separator", "file_separator", "exec_separator", "exit2", NULL};
201
202 gchar **p;
203
204 static gsize initialized = 0;
205 if (g_once_init_enter(&initialized)){
206 // dynamically constructed texts.
207 GtkWidget *a = rfm_get_widget ("host2");
208 rfm_replace_menu_label(a, g_get_host_name ());
209 /*GtkWidget *label = gtk_bin_get_child (GTK_BIN (a));
210 gtk_label_set_text ((GtkLabel *) label, g_get_host_name ());*/
211 a = rfm_get_widget ("default_iconsize");
212 gchar *text = g_strdup_printf("%s (%s)", _("Reset default state"), _("Single Instance"));
213 rfm_replace_menu_label(a, text);
214 /* label = gtk_bin_get_child (GTK_BIN (a));
215 gtk_label_set_text ((GtkLabel *) label, text);*/
216 g_free(text);
217
218 a = rfm_get_widget ("default_iconsize_all");
219 text = g_strdup_printf("%s (%s)", _("Reset default state"), _("All Instances"));
220 rfm_replace_menu_label(a, text);
221 /*label = gtk_bin_get_child (GTK_BIN (a));
222 gtk_label_set_text ((GtkLabel *) label, text);*/
223 g_free(text);
224 g_once_init_leave(&initialized, 1);
225 }
226
227 for (p=void_items; p && *p; p++) SHOW_IT(*p);
228 if (view_p->flags.type == DESKVIEW_TYPE) HIDE_IT("newtab");
229 if(!view_p->en || !view_p->en->path) HIDE_IT ( "goup_menuitem");
230 if(!view_p->go_list) HIDE_IT ("go_back_menuitem");
231 if(!view_p->f_list) HIDE_IT("go_forward_menuitem");
232
233 rodent_bookmark_set_menuitems(&(view_p->widgets), "bookmark");
234 gint i;
235 for(i = 0; i < DEEPEST_BOOK_MENU_LEVELS; i++) {
236 gchar *name = g_strdup_printf ("bookmark-%d", i);
237 GtkWidget *menuitem = rfm_get_widget(name);
238 if (!menuitem){
239 DBG("rodent_reset_menu(): widget %s not found\n", name);
240 g_free(name);
241 continue;
242 }
243 gchar *path=g_object_get_data(G_OBJECT(menuitem), "path");
244 if (!path) {
245 HIDE_IT ( name);
246 } else {
247 SHOW_IT ( name);
248 }
249 g_free(name);
250 }
251
252 for(i = 0; i < DEEPEST_DIR_MENU_LEVELS; i++) {
253 char *name = g_strdup_printf ("level-%d", i);
254 HIDE_IT ( name);
255 g_free (name);
256 }
257 /* this shows valid directories to goto */
258 recursive_dirname (&(view_p->widgets), view_p->deepest_dir, 0);
259
260 gchar **w_name,
261 *widget_name[] = { "show_hidden_menuitem", "preview_images_menuitem", "newfile_menuitem", "newdirectory_menuitem", NULL };
262 for(w_name = widget_name; w_name && *w_name; w_name++) {
263 if(view_p->en && view_p->en->path) {
264 if(view_p->module) {
265 if(rfm_void (PLUGIN_DIR, view_p->module, *w_name))
266 SHOW_IT ( *w_name);
267 } else if(IS_SDIR(view_p->en->type)) {
268 SHOW_IT ( *w_name);
269 }
270 }
271 }
272
273 if(view_p->flags.preferences & SORT_ASCENDING){
274 HIDE_IT ( "ascending1");
275 // False positive.
276 // coverity[copy_paste_error : FALSE]
277 SHOW_IT ( "descending1");
278 } else {
279 HIDE_IT ( "descending1");
280 SHOW_IT ( "ascending1");
281 }
282
283 // dotdesktop_menu will not exist if dotdesktop module is not present
284 gboolean have_dotdesktop =
285 GPOINTER_TO_INT(rfm_void(PLUGIN_DIR, "dotdesktop", "is_root_module"));
286 if (have_dotdesktop) {
287 GtkWidget *applications_menu = rfm_get_widget("applications_menu");
288 if (applications_menu) {
289 GtkWidget *popup_widget=
290 rfm_rational(PLUGIN_DIR, "dotdesktop",widgets_p,
291 applications_menu,
292 "dotdesktop_nondetached_menu");
293 if (popup_widget) {
294 gtk_widget_show_all(applications_menu);
295 }
296 }
297 }
298
299
300 #if 0
301 if (view_p->flags.type == DESKVIEW_TYPE) {
302 if (ICON_SIZE(view_p) < BIG_ICON_SIZE) {
303 SHOW_IT ( "plus_iconsize");
304 }
305 if (ICON_SIZE(view_p) >= TINY_ICON_SIZE) {
306 SHOW_IT ( "minus_iconsize");
307 }
308 }
309 if (rfm_get_default_size() != ICON_SIZE_ID(view_p)){
310 SHOW_IT ( "default_iconsize");
311 }
312 #endif
313
314
315
316 if(rfm_pasteboard_status (view_p) && view_p->en && view_p->en->path
317 &&
318 IS_SDIR(view_p->en->type)
319 )
320 {
321 SHOW_IT ( "paste_menuitem");
322 }
323
324 if(view_p->constructor) {
325 SHOW_IT ( "newwindow");
326
327 }
328
329 if(getenv ("TERMINAL_CMD") && strlen (getenv ("TERMINAL_CMD"))) {
330 gchar *term = g_find_program_in_path (getenv ("TERMINAL_CMD"));
331 if (!term){
332 const gchar **p=rfm_get_terminals();
333 for (;p && *p; p++){
334 term = g_find_program_in_path (*p);
335 if (term) break;
336 }
337 }
338
339 if (term) {
340 SHOW_IT ( "terminal2");
341 g_free(term);
342 } else {
343 #ifdef DEBUG
344 const gchar *t=getenv ("TERMINAL_CMD");
345 DBG("Terminal command \"%s\" not found\n", t);
346 #endif
347 }
348 }
349 gchar *fgr = g_find_program_in_path("rodent-fgr");
350 if (fgr) {
351 SHOW_IT ( "find2");
352 g_free(fgr);
353 }
354 gchar *rodent_diff = g_find_program_in_path("rodent-diff");
355 if (rodent_diff){
356 SHOW_IT ( "differences2");
357 g_free(rodent_diff);
358 }
359
360 if(view_p->en) {
361 SHOW_IT ( "select_menu");
362 SHOW_IT ( "edit_separator");
363 }
364 if (rfm_void(RFM_MODULE_DIR, "settings", "module_active")) {
365 SHOW_IT ( "settings2");
366 }
367 HIDE_IT ( "addbookmark_menuitem");
368 HIDE_IT ( "removebookmark_menuitem");
369 if (view_p->en && view_p->en->path && g_path_is_absolute(view_p->en->path)){
370 gboolean on = rodent_path_is_bookmarkable(view_p->en->path);
371 if (on){
372 setup_bookmark_menuitem( view_p->en, "addbookmark_menuitem", on);
373 } else {
374 setup_bookmark_menuitem( view_p->en, "removebookmark_menuitem", on);
375 }
376 }
377 GtkWidget *inner_label = rfm_get_widget ("sort_menu");
378 if(view_p->flags.preferences & SORT_ASCENDING)
379 rfm_replace_menu_image(inner_label, "xffm/stock_sort-ascending");
380 else
381 rfm_replace_menu_image(inner_label, "xffm/stock_sort-descending");
382 }
383
384 void
rodent_reset_menu_toggles(void)385 rodent_reset_menu_toggles (void) {
386 NOOP( "***** popup now at rodent_reset_menu_toggles\n");
387 widgets_t *widgets_p = rfm_get_widget ("widgets_p");
388 view_t *view_p = widgets_p->view_p;
389 GtkCheckMenuItem *check;
390 switch (GPOINTER_TO_INT (ICON_SIZE_ID(view_p))){
391 case LIST_ICON_SIZE:
392 check = rfm_get_widget ("compact_iconsize"); break;
393 break;
394 case TINY_ICON_SIZE:
395 check = rfm_get_widget ("tiny_iconsize"); break;
396 break;
397 case MEDIUM_ICON_SIZE:
398 check = rfm_get_widget ("big_iconsize"); break;
399 break;
400 case BIG_ICON_SIZE:
401 check = rfm_get_widget ("huge_iconsize"); break;
402 break;
403 case SMALL_ICON_SIZE:
404 default:
405 check = rfm_get_widget ("normal_iconsize"); break;
406 break;
407 }
408 gtk_check_menu_item_set_active (check, TRUE);
409 switch (view_p->flags.sortcolumn){
410 case NAME_SORT:
411 check = rfm_get_widget ("namesort"); break;
412 case SIZE_SORT:
413 check = rfm_get_widget ("size6"); break;
414 case DATE_SORT:
415 check = rfm_get_widget ("date6"); break;
416 case OWNER_SORT:
417 check = rfm_get_widget ("owner6"); break;
418 case GROUP_SORT:
419 check = rfm_get_widget ("group6"); break;
420 case MODE_SORT:
421 check = rfm_get_widget ("mode6"); break;
422 case TYPE_SORT:
423 default:
424 check = rfm_get_widget ("unsorted6"); break;
425
426 }
427 gtk_check_menu_item_set_active (check, TRUE);
428 gtk_check_menu_item_set_active ((GtkCheckMenuItem *)
429 rfm_get_widget ("casesort_menuitem"), view_p->flags.preferences & __CASE_INSENSITIVE);
430
431 NOOP ("before setting __SHOW_IMAGES toggle now...%s\n", (view_p->flags.preferences & __SHOW_IMAGES) ? "ON" : "Off");
432 gtk_check_menu_item_set_active ((GtkCheckMenuItem *)
433 rfm_get_widget ("preview_images_menuitem"), view_p->flags.preferences & __SHOW_IMAGES);
434
435 NOOP ("after setting __SHOW_IMAGES toggle now...%s\n", (view_p->flags.preferences & __SHOW_IMAGES) ? "ON" : "Off");
436 gtk_check_menu_item_set_active ((GtkCheckMenuItem *)
437 rfm_get_widget ("show_hidden_menuitem"), view_p->flags.preferences & __SHOW_HIDDEN);
438 gtk_check_menu_item_set_active ((GtkCheckMenuItem *)
439 rfm_get_widget ("show_backup_menuitem"), view_p->flags.preferences & __SHOWS_BACKUP);
440 NOOP ("setting __SHOW_HIDDEN toggle now...%s\n", (view_p->flags.preferences & __SHOW_HIDDEN) ? "ON" : "Off");
441 return;
442 }
443
444 static pthread_mutex_t flags_mutex=PTHREAD_MUTEX_INITIALIZER;
445 void
rodent_recover_flags(extra_key_t * extra_key_p)446 rodent_recover_flags (extra_key_t * extra_key_p) {
447 DBHashTable *runflags;
448 GString *gs;
449 gint64 *flags;
450
451 pthread_mutex_lock(&flags_mutex);
452 TRACE("opening %s...\n",extra_key_p->flagfile);
453 runflags = dbh_new (extra_key_p->flagfile, NULL, DBH_READ_ONLY|DBH_PARALLEL_SAFE);
454 TRACE("opened %s.\n",extra_key_p->flagfile);
455
456 if(runflags == NULL) {
457 NOOP ("Cannot open %s\n", extra_key_p->flagfile);
458 extra_key_p->flag1 = 0;
459 extra_key_p->flag2 = 0;
460 pthread_mutex_unlock(&flags_mutex);
461 return;
462 }
463 dbh_set_parallel_lock_timeout(runflags, 3);
464 gs = g_string_new (extra_key_p->response);
465 sprintf ((char *)DBH_KEY (runflags), "%10u", g_string_hash (gs));
466 g_string_free (gs, TRUE);
467
468 if (dbh_load (runflags)){
469 flags = (gint64 *)runflags->data;
470 extra_key_p->flag1 = flags[0];
471 extra_key_p->flag2 = flags[1];
472 } else {
473 extra_key_p->flag1 = extra_key_p->flag2 = 0;
474 }
475 dbh_close (runflags);
476 pthread_mutex_unlock(&flags_mutex);
477
478 NOOP ("rodent_recover_flags(): flags recovered from dbh file for %s, flag1=%d flag2=%d\n",
479 extra_key_p->response, extra_key_p->flag1, extra_key_p->flag2);
480 }
481
482 void
rodent_save_flags(extra_key_t * extra_key_p)483 rodent_save_flags (extra_key_t * extra_key_p) {
484 DBHashTable *runflags;
485 GString *gs;
486 gint64 *flags;
487
488 pthread_mutex_lock(&flags_mutex);
489 TRACE("opening %s...\n",extra_key_p->flagfile);
490 runflags = dbh_new (extra_key_p->flagfile, NULL, DBH_PARALLEL_SAFE);
491 TRACE("opened %s.\n",extra_key_p->flagfile);
492
493 if(runflags == NULL) {
494 NOOP ("Creating cache file: %s", extra_key_p->flagfile);
495 unsigned char keylength=11;
496 gchar *directory = g_path_get_dirname(extra_key_p->flagfile);
497 if (!g_file_test(directory, G_FILE_TEST_IS_DIR)){
498 g_mkdir_with_parents(directory, 0700);
499 }
500 g_free(directory);
501 TRACE("opening %s...\n",extra_key_p->flagfile);
502 runflags = dbh_new (extra_key_p->flagfile, &keylength, DBH_CREATE|DBH_PARALLEL_SAFE);
503 TRACE("opened %s.\n",extra_key_p->flagfile);
504 if(runflags == NULL) {
505 DBG ("Cannot create %s\n", extra_key_p->flagfile);
506 pthread_mutex_unlock(&flags_mutex);
507 return;
508 }
509 }
510 dbh_set_parallel_lock_timeout(runflags, 3);
511 gs = g_string_new (extra_key_p->response);
512 sprintf ((char *)DBH_KEY (runflags), "%10u", g_string_hash (gs));
513 g_string_free (gs, TRUE);
514 flags = (gint64 *)runflags->data;
515 flags[0] = extra_key_p->flag1;
516 flags[1] = extra_key_p->flag2;
517 dbh_set_recordsize (runflags, 2 * sizeof (gint64));
518
519 dbh_update (runflags);
520 dbh_close (runflags);
521 pthread_mutex_unlock(&flags_mutex);
522 NOOP ("flags saved in dbh file %s flag1=%d flag2=%d\n", extra_key_p->flagfile, extra_key_p->flag1, extra_key_p->flag2);
523
524 }
525
526
527 gchar *
rodent_get_text_editor(record_entry_t * en)528 rodent_get_text_editor(record_entry_t *en){
529 if(!g_path_is_absolute(en->path)) {
530 return NULL;
531 }
532 gchar **text_editors = NULL;
533 // Default editor command.
534 // We magic the file because the freedesktop standard
535 // is borked and changes text/ for application/ on a
536 // number of files. Precisely what should not be done.
537 //
538 if (!en->mimetype) en->mimetype = MIME_type (en->path, en->st);
539 if(!en->mimetype || strcmp(en->mimetype, _("unknown"))==0) {
540 if (IS_LOCAL_TYPE(en->type) && !en->mimemagic){
541 en->mimemagic = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_magic", "mime_function");
542 if (!en->mimemagic) en->mimemagic = g_strdup(_("unknown"));
543 } else en->mimemagic = g_strdup(_("unknown"));
544 }
545 if(en->mimemagic && strstr (en->mimemagic, "text/")){
546 text_editors = MIME_apps ("text/plain");
547 } else if(en->mimetype && strstr (en->mimetype, "text/")){
548 text_editors = MIME_apps ("text/plain");
549 }
550
551 // Even magic mimetype may miss the mark. Take care of that here...
552 if(!en->filetype) {
553 if (IS_LOCAL_TYPE(en->type)) {
554 en->filetype = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_file", "mime_function");
555 if (!en->filetype) en->filetype = g_strdup(_("unknown"));
556 }
557 else en->filetype = g_strdup(_("unknown"));
558 }
559 if(!text_editors) {
560 if(en->filetype && strstr (en->filetype, "text"))
561 text_editors = MIME_apps ("text/plain");
562 }
563
564 if(!text_editors) {
565 return NULL;
566 }
567 g_strfreev(text_editors);
568 /* OK to apply an editor. We will use the default editor */
569 gchar *basename=NULL;
570 if(getenv ("EDITOR") && strlen (getenv ("EDITOR"))) {
571 basename=g_strdup(getenv ("EDITOR"));
572 }
573 return (basename);
574 }
575
576
577