4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* toolbar.c - for the button bars that go along the tops of windows */
43 #include "view_iface.h"
44 #include "bookmarks.h"
46 typedef struct _Tool Tool
;
48 typedef enum {DROP_NONE
, DROP_TO_PARENT
, DROP_TO_HOME
} DropDest
;
53 const gchar
*tip
; /* Tooltip */
54 void (*clicked
)(GtkWidget
*w
, FilerWindow
*filer_window
);
57 gboolean menu
; /* Activate on button-press */
60 Option o_toolbar
, o_toolbar_info
, o_toolbar_disable
;
62 static GtkTooltips
*tooltips
= NULL
;
64 /* TRUE if the button presses (or released) should open a new window,
65 * rather than reusing the existing one.
67 #define NEW_WIN_BUTTON(button_event) \
68 (o_new_button_1.int_value \
69 ? ((GdkEventButton *) button_event)->button == 1 \
70 : ((GdkEventButton *) button_event)->button != 1)
72 /* Static prototypes */
73 static void toolbar_close_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
74 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
75 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
76 static void toolbar_bookmarks_clicked(GtkWidget
*widget
,
77 FilerWindow
*filer_window
);
78 static void toolbar_help_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
79 static void toolbar_refresh_clicked(GtkWidget
*widget
,
80 FilerWindow
*filer_window
);
81 static void toolbar_size_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
82 static void toolbar_details_clicked(GtkWidget
*widget
,
83 FilerWindow
*filer_window
);
84 static void toolbar_hidden_clicked(GtkWidget
*widget
,
85 FilerWindow
*filer_window
);
86 static GtkWidget
*add_button(GtkWidget
*bar
, Tool
*tool
,
87 FilerWindow
*filer_window
);
88 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
);
89 static gboolean
drag_motion(GtkWidget
*widget
,
90 GdkDragContext
*context
,
94 FilerWindow
*filer_window
);
95 static void drag_leave(GtkWidget
*widget
,
96 GdkDragContext
*context
,
98 FilerWindow
*filer_window
);
99 static void handle_drops(FilerWindow
*filer_window
,
102 static void toggle_shaded(GtkWidget
*widget
);
103 static void option_notify(void);
104 static GList
*build_tool_options(Option
*option
, xmlNode
*node
, guchar
*label
);
105 static void tally_items(gpointer key
, gpointer value
, gpointer data
);
107 static Tool all_tools
[] = {
108 {N_("Close"), GTK_STOCK_CLOSE
, N_("Close filer window"),
109 toolbar_close_clicked
, DROP_NONE
, FALSE
,
112 {N_("Up"), GTK_STOCK_GO_UP
, N_("Change to parent directory"),
113 toolbar_up_clicked
, DROP_TO_PARENT
, TRUE
,
116 {N_("Home"), GTK_STOCK_HOME
, N_("Change to home directory"),
117 toolbar_home_clicked
, DROP_TO_HOME
, TRUE
,
120 {N_("Bookmarks"), ROX_STOCK_BOOKMARKS
, N_("Bookmarks menu"),
121 toolbar_bookmarks_clicked
, DROP_NONE
, FALSE
,
124 {N_("Scan"), GTK_STOCK_REFRESH
, N_("Rescan directory contents"),
125 toolbar_refresh_clicked
, DROP_NONE
, TRUE
,
128 {N_("Size"), GTK_STOCK_ZOOM_IN
, N_("Change icon size"),
129 toolbar_size_clicked
, DROP_NONE
, TRUE
,
132 {N_("Details"), ROX_STOCK_SHOW_DETAILS
, N_("Show extra details"),
133 toolbar_details_clicked
, DROP_NONE
, TRUE
,
136 {N_("Hidden"), ROX_STOCK_SHOW_HIDDEN
, N_("Show/hide hidden files"),
137 toolbar_hidden_clicked
, DROP_NONE
, TRUE
,
140 {N_("Help"), GTK_STOCK_HELP
, N_("Show ROX-Filer help"),
141 toolbar_help_clicked
, DROP_NONE
, TRUE
,
146 /****************************************************************
147 * EXTERNAL INTERFACE *
148 ****************************************************************/
150 void toolbar_init(void)
152 option_add_int(&o_toolbar
, "toolbar_type", TOOLBAR_NORMAL
);
153 option_add_int(&o_toolbar_info
, "toolbar_show_info", 1);
154 option_add_string(&o_toolbar_disable
, "toolbar_disable",
156 option_add_notify(option_notify
);
158 tooltips
= gtk_tooltips_new();
160 option_register_widget("tool-options", build_tool_options
);
163 /* Returns a button which can be used to turn a tool on and off.
164 * Button has 'tool_name' set to the tool's name.
165 * NULL if tool number i is too big.
167 GtkWidget
*toolbar_tool_option(int i
)
169 Tool
*tool
= &all_tools
[i
];
171 GtkWidget
*icon_widget
, *vbox
, *text
;
173 g_return_val_if_fail(i
>= 0, NULL
);
175 if (i
>= sizeof(all_tools
) / sizeof(*all_tools
))
178 button
= gtk_button_new();
179 gtk_tooltips_set_tip(tooltips
, button
, _(tool
->tip
), NULL
);
181 icon_widget
= gtk_image_new_from_stock(tool
->name
,
182 GTK_ICON_SIZE_LARGE_TOOLBAR
);
184 vbox
= gtk_vbox_new(FALSE
, 0);
185 gtk_box_pack_start(GTK_BOX(vbox
), icon_widget
, TRUE
, TRUE
, 0);
187 text
= gtk_label_new(_(tool
->label
));
188 gtk_box_pack_start(GTK_BOX(vbox
), text
, FALSE
, TRUE
, 0);
190 gtk_container_add(GTK_CONTAINER(button
), vbox
);
192 gtk_container_set_border_width(GTK_CONTAINER(button
), 1);
194 g_signal_connect_swapped(button
, "clicked",
195 G_CALLBACK(toggle_shaded
), vbox
);
197 g_object_set_data(G_OBJECT(button
), "tool_name",
198 (gchar
*) tool
->name
);
203 void toolbar_update_info(FilerWindow
*filer_window
)
209 if (o_toolbar
.int_value
== TOOLBAR_NONE
|| !o_toolbar_info
.int_value
)
210 return; /* Not showing info */
212 if (filer_window
->target_cb
)
215 view
= filer_window
->view
;
217 n_selected
= view_count_selected(view
);
224 if (filer_window
->scanning
)
227 GTK_LABEL(filer_window
->toolbar_text
), "");
231 if (!filer_window
->show_hidden
)
233 GHashTable
*hash
= filer_window
->directory
->known_items
;
236 g_hash_table_foreach(hash
, tally_items
, &tally
);
239 s
= g_strdup_printf(_(" (%u hidden)"), tally
);
242 n_items
= view_count_items(view
);
245 label
= g_strdup_printf("%d %s%s",
247 n_items
!= 1 ? _("items") : _("item"),
249 else /* (French plurals work differently for zero) */
250 label
= g_strdup_printf(_("No items%s"),
260 view_get_iter(filer_window
->view
, &iter
, VIEW_ITER_SELECTED
);
262 while ((item
= iter
.next(&iter
)))
263 if (item
->base_type
!= TYPE_DIRECTORY
)
264 size
+= (double) item
->size
;
266 label
= g_strdup_printf(_("%u selected (%s)"),
267 n_selected
, format_double_size(size
));
270 gtk_label_set_text(GTK_LABEL(filer_window
->toolbar_text
), label
);
274 /* Create, destroy or recreate toolbar for this window so that it
275 * matches the option setting.
277 void toolbar_update_toolbar(FilerWindow
*filer_window
)
279 g_return_if_fail(filer_window
!= NULL
);
281 if (filer_window
->toolbar
)
283 gtk_widget_destroy(filer_window
->toolbar
);
284 filer_window
->toolbar
= NULL
;
285 filer_window
->toolbar_text
= NULL
;
288 if (o_toolbar
.int_value
!= TOOLBAR_NONE
)
290 filer_window
->toolbar
= create_toolbar(filer_window
);
291 gtk_box_pack_start(filer_window
->toplevel_vbox
,
292 filer_window
->toolbar
, FALSE
, TRUE
, 0);
293 gtk_box_reorder_child(filer_window
->toplevel_vbox
,
294 filer_window
->toolbar
, 0);
295 gtk_widget_show_all(filer_window
->toolbar
);
298 filer_target_mode(filer_window
, NULL
, NULL
, NULL
);
299 toolbar_update_info(filer_window
);
302 /****************************************************************
303 * INTERNAL FUNCTIONS *
304 ****************************************************************/
306 static void toolbar_help_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
310 event
= gtk_get_current_event();
311 if (event
->type
== GDK_BUTTON_RELEASE
&&
312 ((GdkEventButton
*) event
)->button
!= 1)
313 menu_rox_help(NULL
, HELP_MANUAL
, NULL
);
315 filer_opendir(make_path(app_dir
, "Help"), NULL
, NULL
);
318 static void toolbar_refresh_clicked(GtkWidget
*widget
,
319 FilerWindow
*filer_window
)
323 event
= gtk_get_current_event();
324 if (event
->type
== GDK_BUTTON_RELEASE
&&
325 ((GdkEventButton
*) event
)->button
!= 1)
327 filer_opendir(filer_window
->sym_path
, filer_window
, NULL
);
332 filer_update_dir(filer_window
, TRUE
);
336 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
340 event
= gtk_get_current_event();
341 if (event
->type
== GDK_BUTTON_RELEASE
&& NEW_WIN_BUTTON(event
))
343 filer_opendir(home_dir
, filer_window
, NULL
);
346 filer_change_to(filer_window
, home_dir
, NULL
);
349 static void toolbar_bookmarks_clicked(GtkWidget
*widget
,
350 FilerWindow
*filer_window
)
354 g_return_if_fail(filer_window
!= NULL
);
356 event
= gtk_get_current_event();
357 if (event
->type
== GDK_BUTTON_PRESS
&&
358 ((GdkEventButton
*) event
)->button
== 1)
360 bookmarks_show_menu(filer_window
);
362 else if (event
->type
== GDK_BUTTON_RELEASE
&&
363 ((GdkEventButton
*) event
)->button
!= 1)
369 static void toolbar_close_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
373 g_return_if_fail(filer_window
!= NULL
);
375 event
= gtk_get_current_event();
376 if (event
->type
== GDK_BUTTON_RELEASE
&&
377 ((GdkEventButton
*) event
)->button
!= 1)
379 filer_opendir(filer_window
->sym_path
, filer_window
, NULL
);
381 else if (!filer_window_delete(filer_window
->window
, NULL
, filer_window
))
382 gtk_widget_destroy(filer_window
->window
);
385 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
389 event
= gtk_get_current_event();
390 if (event
->type
== GDK_BUTTON_RELEASE
&& NEW_WIN_BUTTON(event
))
392 filer_open_parent(filer_window
);
395 change_to_parent(filer_window
);
398 static void toolbar_size_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
402 bev
= (GdkEventButton
*) gtk_get_current_event();
404 display_change_size(filer_window
,
405 bev
->type
== GDK_BUTTON_RELEASE
&& bev
->button
== 1);
408 static void toolbar_details_clicked(GtkWidget
*widget
,
409 FilerWindow
*filer_window
)
411 if (filer_window
->view_type
== VIEW_TYPE_DETAILS
)
412 filer_set_view_type(filer_window
, VIEW_TYPE_COLLECTION
);
414 filer_set_view_type(filer_window
, VIEW_TYPE_DETAILS
);
417 static void toolbar_hidden_clicked(GtkWidget
*widget
,
418 FilerWindow
*filer_window
)
420 display_set_hidden(filer_window
, !filer_window
->show_hidden
);
423 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
)
429 bar
= gtk_toolbar_new();
430 gtk_widget_set_size_request(bar
, 100, -1);
432 if (o_toolbar
.int_value
== TOOLBAR_LARGE
)
433 gtk_toolbar_set_style(GTK_TOOLBAR(bar
), GTK_TOOLBAR_BOTH
);
434 else if (o_toolbar
.int_value
== TOOLBAR_HORIZONTAL
)
435 gtk_toolbar_set_style(GTK_TOOLBAR(bar
), GTK_TOOLBAR_BOTH_HORIZ
);
437 gtk_toolbar_set_style(GTK_TOOLBAR(bar
), GTK_TOOLBAR_ICONS
);
439 for (i
= 0; i
< sizeof(all_tools
) / sizeof(*all_tools
); i
++)
441 Tool
*tool
= &all_tools
[i
];
446 b
= add_button(bar
, tool
, filer_window
);
447 if (tool
->drop_action
!= DROP_NONE
)
448 handle_drops(filer_window
, b
, tool
->drop_action
);
451 filer_window
->toolbar_text
= gtk_label_new("");
452 gtk_misc_set_alignment(GTK_MISC(filer_window
->toolbar_text
), 0, 0.5);
453 gtk_toolbar_append_widget(GTK_TOOLBAR(bar
),
454 filer_window
->toolbar_text
, NULL
, NULL
);
459 /* This is used to simulate a click when button 3 is used (GtkButton
460 * normally ignores this).
462 static gint toolbar_other_button
= 0;
463 static gint
toolbar_button_pressed(GtkButton
*button
,
464 GdkEventButton
*event
,
465 FilerWindow
*filer_window
)
467 gint b
= event
->button
;
470 tool
= g_object_get_data(G_OBJECT(button
), "rox-tool");
471 g_return_val_if_fail(tool
!= NULL
, TRUE
);
473 if (tool
->menu
&& b
== 1)
475 tool
->clicked((GtkWidget
*) button
, filer_window
);
479 if ((b
== 2 || b
== 3) && toolbar_other_button
== 0)
481 toolbar_other_button
= event
->button
;
482 gtk_grab_add(GTK_WIDGET(button
));
483 gtk_button_pressed(button
);
491 static gint
toolbar_button_released(GtkButton
*button
,
492 GdkEventButton
*event
,
493 FilerWindow
*filer_window
)
495 if (event
->button
== toolbar_other_button
)
497 toolbar_other_button
= 0;
498 gtk_grab_remove(GTK_WIDGET(button
));
499 gtk_button_released(button
);
507 static GtkWidget
*add_button(GtkWidget
*bar
, Tool
*tool
,
508 FilerWindow
*filer_window
)
510 GtkWidget
*button
, *icon_widget
;
512 icon_widget
= gtk_image_new_from_stock(tool
->name
,
513 GTK_ICON_SIZE_LARGE_TOOLBAR
);
515 button
= gtk_toolbar_insert_element(GTK_TOOLBAR(bar
),
516 GTK_TOOLBAR_CHILD_BUTTON
,
521 NULL
, NULL
, /* CB, userdata */
522 GTK_TOOLBAR(bar
)->num_children
);
524 if (o_toolbar
.int_value
== TOOLBAR_HORIZONTAL
)
526 GtkWidget
*hbox
, *label
;
528 hbox
= GTK_BIN(button
)->child
;
529 kids
= gtk_container_get_children(GTK_CONTAINER(hbox
));
530 label
= g_list_nth_data(kids
, 1);
535 gtk_box_set_child_packing(GTK_BOX(hbox
), label
,
536 TRUE
, TRUE
, 0, GTK_PACK_END
);
537 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
541 g_object_set_data(G_OBJECT(button
), "rox-tool", tool
);
543 g_signal_connect(button
, "clicked",
544 G_CALLBACK(tool
->clicked
), filer_window
);
545 g_signal_connect(button
, "button_press_event",
546 G_CALLBACK(toolbar_button_pressed
), filer_window
);
547 g_signal_connect(button
, "button_release_event",
548 G_CALLBACK(toolbar_button_released
), filer_window
);
553 static void toggle_shaded(GtkWidget
*widget
)
555 gtk_widget_set_sensitive(widget
, !GTK_WIDGET_SENSITIVE(widget
));
556 option_check_widget(&o_toolbar_disable
);
559 /* Called during the drag when the mouse is in a widget registered
560 * as a drop target. Returns TRUE if we can accept the drop.
562 static gboolean
drag_motion(GtkWidget
*widget
,
563 GdkDragContext
*context
,
567 FilerWindow
*filer_window
)
569 GdkDragAction action
= context
->suggested_action
;
572 dest
= (DropDest
) g_object_get_data(G_OBJECT(widget
), "toolbar_dest");
574 if (dest
== DROP_TO_HOME
)
575 g_dataset_set_data(context
, "drop_dest_path",
578 g_dataset_set_data_full(context
, "drop_dest_path",
579 g_path_get_dirname(filer_window
->sym_path
),
582 g_dataset_set_data(context
, "drop_dest_type", (gpointer
) drop_dest_dir
);
583 gdk_drag_status(context
, action
, time
);
585 dnd_spring_load(context
, filer_window
);
586 gtk_button_set_relief(GTK_BUTTON(widget
), GTK_RELIEF_NORMAL
);
591 static void drag_leave(GtkWidget
*widget
,
592 GdkDragContext
*context
,
594 FilerWindow
*filer_window
)
596 gtk_button_set_relief(GTK_BUTTON(widget
), GTK_RELIEF_NONE
);
600 static void handle_drops(FilerWindow
*filer_window
,
604 make_drop_target(button
, 0);
605 g_signal_connect(button
, "drag_motion",
606 G_CALLBACK(drag_motion
), filer_window
);
607 g_signal_connect(button
, "drag_leave",
608 G_CALLBACK(drag_leave
), filer_window
);
609 g_object_set_data(G_OBJECT(button
), "toolbar_dest", (gpointer
) dest
);
612 static void tally_items(gpointer key
, gpointer value
, gpointer data
)
614 guchar
*leafname
= (guchar
*) key
;
615 int *tally
= (int *) data
;
617 if (leafname
[0] == '.')
621 static void option_notify(void)
624 gboolean changed
= FALSE
;
625 guchar
*list
= o_toolbar_disable
.value
;
627 for (i
= 0; i
< sizeof(all_tools
) / sizeof(*all_tools
); i
++)
629 Tool
*tool
= &all_tools
[i
];
630 gboolean old
= tool
->enabled
;
632 tool
->enabled
= !in_list(tool
->name
, list
);
634 if (old
!= tool
->enabled
)
638 if (changed
|| o_toolbar
.has_changed
|| o_toolbar_info
.has_changed
)
642 for (next
= all_filer_windows
; next
; next
= next
->next
)
644 FilerWindow
*filer_window
= (FilerWindow
*) next
->data
;
646 toolbar_update_toolbar(filer_window
);
651 static void update_tools(Option
*option
)
655 kids
= gtk_container_get_children(GTK_CONTAINER(option
->widget
));
657 for (next
= kids
; next
; next
= next
->next
)
659 GtkWidget
*kid
= (GtkWidget
*) next
->data
;
662 name
= g_object_get_data(G_OBJECT(kid
), "tool_name");
664 g_return_if_fail(name
!= NULL
);
666 gtk_widget_set_sensitive(GTK_BIN(kid
)->child
,
667 !in_list(name
, option
->value
));
673 static guchar
*read_tools(Option
*option
)
679 list
= g_string_new(NULL
);
681 kids
= gtk_container_get_children(GTK_CONTAINER(option
->widget
));
683 for (next
= kids
; next
; next
= next
->next
)
685 GtkObject
*kid
= (GtkObject
*) next
->data
;
688 if (!GTK_WIDGET_SENSITIVE(GTK_BIN(kid
)->child
))
690 name
= g_object_get_data(G_OBJECT(kid
), "tool_name");
691 g_return_val_if_fail(name
!= NULL
, list
->str
);
694 g_string_append(list
, ", ");
695 g_string_append(list
, name
);
701 g_string_free(list
, FALSE
);
706 static GList
*build_tool_options(Option
*option
, xmlNode
*node
, guchar
*label
)
708 guint num_tools
= G_N_ELEMENTS(all_tools
);
710 guint cols
= (num_tools
+ rows
- 1) / rows
;
712 GtkWidget
*hbox
, *tool
, *table
;
714 g_return_val_if_fail(option
!= NULL
, NULL
);
716 hbox
= gtk_hbox_new(FALSE
, 0);
717 table
= gtk_table_new(rows
, cols
, TRUE
);
719 for (i
= 0; (tool
= toolbar_tool_option(i
)) != NULL
; i
++)
721 guint left
= i
% cols
;
722 guint top
= i
/ cols
;
724 gtk_table_attach_defaults(GTK_TABLE(table
), tool
,
725 left
, left
+ 1, top
, top
+ 1);
728 gtk_box_pack_start(GTK_BOX(hbox
), table
, FALSE
, FALSE
, 0);
730 option
->update_widget
= update_tools
;
731 option
->read_widget
= read_tools
;
732 option
->widget
= table
;
734 return g_list_append(NULL
, hbox
);