1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4 * Caja
5 *
6 * Copyright (C) 2004 Red Hat, Inc.
7 * Copyright (C) 2003 Marco Pesenti Gritti
8 *
9 * Caja is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * Caja is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22 *
23 * Based on ephy-navigation-action.h from Epiphany
24 *
25 * Authors: Alexander Larsson <alexl@redhat.com>
26 * Marco Pesenti Gritti
27 *
28 */
29
30 #include <config.h>
31
32 #include <gtk/gtk.h>
33
34 #include <eel/eel-gtk-extensions.h>
35
36 #include "caja-navigation-action.h"
37 #include "caja-navigation-window.h"
38 #include "caja-window-private.h"
39 #include "caja-navigation-window-slot.h"
40
41 struct _CajaNavigationActionPrivate
42 {
43 CajaNavigationWindow *window;
44 CajaNavigationDirection direction;
45 char *arrow_tooltip;
46 };
47
48 enum
49 {
50 PROP_0,
51 PROP_ARROW_TOOLTIP,
52 PROP_DIRECTION,
53 PROP_WINDOW
54 };
55
56 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
57 G_DEFINE_TYPE_WITH_PRIVATE (CajaNavigationAction, caja_navigation_action, GTK_TYPE_ACTION)
58 G_GNUC_END_IGNORE_DEPRECATIONS;
59
60 static gboolean
should_open_in_new_tab(void)61 should_open_in_new_tab (void)
62 {
63 /* FIXME this is duplicated */
64 GdkEvent *event;
65
66 event = gtk_get_current_event ();
67 if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE)
68 {
69 return event->button.button == 2;
70 }
71
72 gdk_event_free (event);
73
74 return FALSE;
75 }
76
77 static void
activate_back_or_forward_menu_item(GtkMenuItem * menu_item,CajaNavigationWindow * window,gboolean back)78 activate_back_or_forward_menu_item (GtkMenuItem *menu_item,
79 CajaNavigationWindow *window,
80 gboolean back)
81 {
82 int index;
83
84 g_assert (GTK_IS_MENU_ITEM (menu_item));
85 g_assert (CAJA_IS_NAVIGATION_WINDOW (window));
86
87 index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "user_data"));
88
89 caja_navigation_window_back_or_forward (window, back, index, should_open_in_new_tab ());
90 }
91
92 static void
activate_back_menu_item_callback(GtkMenuItem * menu_item,CajaNavigationWindow * window)93 activate_back_menu_item_callback (GtkMenuItem *menu_item, CajaNavigationWindow *window)
94 {
95 activate_back_or_forward_menu_item (menu_item, window, TRUE);
96 }
97
98 static void
activate_forward_menu_item_callback(GtkMenuItem * menu_item,CajaNavigationWindow * window)99 activate_forward_menu_item_callback (GtkMenuItem *menu_item, CajaNavigationWindow *window)
100 {
101 activate_back_or_forward_menu_item (menu_item, window, FALSE);
102 }
103
104 static void
fill_menu(CajaNavigationWindow * window,GtkWidget * menu,gboolean back)105 fill_menu (CajaNavigationWindow *window,
106 GtkWidget *menu,
107 gboolean back)
108 {
109 CajaNavigationWindowSlot *slot;
110 int index;
111 GList *list;
112 gboolean list_void;
113 GtkWidget *menu_item = NULL;
114
115 g_assert (CAJA_IS_NAVIGATION_WINDOW (window));
116
117 slot = CAJA_NAVIGATION_WINDOW_SLOT (CAJA_WINDOW (window)->details->active_pane->active_slot);
118
119 list = back ? slot->back_list : slot->forward_list;
120 index = 0;
121 list_void = TRUE;
122
123 while (list != NULL)
124 {
125 menu_item = caja_bookmark_menu_item_new (CAJA_BOOKMARK (list->data));
126
127 if (menu_item) {
128 list_void = FALSE;
129 g_object_set_data (G_OBJECT (menu_item), "user_data", GINT_TO_POINTER (index));
130 gtk_widget_show (GTK_WIDGET (menu_item));
131 g_signal_connect_object (menu_item, "activate",
132 back
133 ? G_CALLBACK (activate_back_menu_item_callback)
134 : G_CALLBACK (activate_forward_menu_item_callback),
135 window, 0);
136
137 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
138 }
139
140 list = g_list_next (list);
141 ++index;
142 }
143
144 if (list_void)
145 {
146 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
147 eel_image_menu_item_new_from_icon ("dialog-error", _("folder removed")));
148 if (back)
149 {
150 caja_navigation_window_slot_clear_back_list (slot);
151 caja_navigation_window_allow_back (window, FALSE);
152 }
153 else
154 {
155 caja_navigation_window_slot_clear_forward_list (slot);
156 caja_navigation_window_allow_forward (window, FALSE);
157 }
158 }
159 }
160
161 static void
show_menu_callback(GtkMenuToolButton * button,CajaNavigationAction * action)162 show_menu_callback (GtkMenuToolButton *button,
163 CajaNavigationAction *action)
164 {
165 CajaNavigationActionPrivate *p;
166 CajaNavigationWindow *window;
167 GtkWidget *menu;
168 GList *children;
169 GList *li;
170
171 p = action->priv;
172 window = action->priv->window;
173
174 menu = gtk_menu_tool_button_get_menu (button);
175
176 children = gtk_container_get_children (GTK_CONTAINER (menu));
177 for (li = children; li; li = li->next)
178 {
179 gtk_container_remove (GTK_CONTAINER (menu), li->data);
180 }
181 g_list_free (children);
182
183 switch (p->direction)
184 {
185 case CAJA_NAVIGATION_DIRECTION_FORWARD:
186 fill_menu (window, menu, FALSE);
187 break;
188 case CAJA_NAVIGATION_DIRECTION_BACK:
189 fill_menu (window, menu, TRUE);
190 break;
191 default:
192 g_assert_not_reached ();
193 break;
194 }
195 }
196
197 static gboolean
proxy_button_press_event_cb(GtkButton * button,GdkEventButton * event,gpointer user_data)198 proxy_button_press_event_cb (GtkButton *button,
199 GdkEventButton *event,
200 gpointer user_data)
201 {
202 if (event->button == 2)
203 {
204 g_signal_emit_by_name (button, "pressed", 0);
205 }
206
207 return FALSE;
208 }
209
210 static gboolean
proxy_button_release_event_cb(GtkButton * button,GdkEventButton * event,gpointer user_data)211 proxy_button_release_event_cb (GtkButton *button,
212 GdkEventButton *event,
213 gpointer user_data)
214 {
215 if (event->button == 2)
216 {
217 g_signal_emit_by_name (button, "released", 0);
218 }
219
220 return FALSE;
221 }
222
223 static void
connect_proxy(GtkAction * action,GtkWidget * proxy)224 connect_proxy (GtkAction *action, GtkWidget *proxy)
225 {
226 if (GTK_IS_MENU_TOOL_BUTTON (proxy))
227 {
228 CajaNavigationAction *naction = CAJA_NAVIGATION_ACTION (action);
229 GtkMenuToolButton *button = GTK_MENU_TOOL_BUTTON (proxy);
230 GtkWidget *menu;
231 GtkWidget *child;
232
233 /* set an empty menu, so the arrow button becomes sensitive */
234 menu = gtk_menu_new ();
235
236 gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
237
238 gtk_menu_tool_button_set_menu (button, menu);
239
240 gtk_menu_tool_button_set_arrow_tooltip_text (button,
241 naction->priv->arrow_tooltip);
242
243 g_signal_connect (proxy, "show-menu",
244 G_CALLBACK (show_menu_callback), action);
245
246 /* Make sure that middle click works. Note that there is some code duplication
247 * between here and caja-window-menus.c */
248 child = eel_gtk_menu_tool_button_get_button (button);
249 g_signal_connect (child, "button-press-event", G_CALLBACK (proxy_button_press_event_cb), NULL);
250 g_signal_connect (child, "button-release-event", G_CALLBACK (proxy_button_release_event_cb), NULL);
251 }
252
253 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
254 (* GTK_ACTION_CLASS (caja_navigation_action_parent_class)->connect_proxy) (action, proxy);
255 G_GNUC_END_IGNORE_DEPRECATIONS;
256 }
257
258 static void
disconnect_proxy(GtkAction * action,GtkWidget * proxy)259 disconnect_proxy (GtkAction *action, GtkWidget *proxy)
260 {
261 if (GTK_IS_MENU_TOOL_BUTTON (proxy))
262 {
263 GtkWidget *child;
264
265 g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (show_menu_callback), action);
266
267 child = eel_gtk_menu_tool_button_get_button (GTK_MENU_TOOL_BUTTON (proxy));
268 g_signal_handlers_disconnect_by_func (child, G_CALLBACK (proxy_button_press_event_cb), NULL);
269 g_signal_handlers_disconnect_by_func (child, G_CALLBACK (proxy_button_release_event_cb), NULL);
270 }
271
272 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
273 (* GTK_ACTION_CLASS (caja_navigation_action_parent_class)->disconnect_proxy) (action, proxy);
274 G_GNUC_END_IGNORE_DEPRECATIONS;
275 }
276
277 static void
caja_navigation_action_finalize(GObject * object)278 caja_navigation_action_finalize (GObject *object)
279 {
280 CajaNavigationAction *action = CAJA_NAVIGATION_ACTION (object);
281
282 g_free (action->priv->arrow_tooltip);
283
284 (* G_OBJECT_CLASS (caja_navigation_action_parent_class)->finalize) (object);
285 }
286
287 static void
caja_navigation_action_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)288 caja_navigation_action_set_property (GObject *object,
289 guint prop_id,
290 const GValue *value,
291 GParamSpec *pspec)
292 {
293 CajaNavigationAction *nav;
294
295 nav = CAJA_NAVIGATION_ACTION (object);
296
297 switch (prop_id)
298 {
299 case PROP_ARROW_TOOLTIP:
300 g_free (nav->priv->arrow_tooltip);
301 nav->priv->arrow_tooltip = g_value_dup_string (value);
302 break;
303 case PROP_DIRECTION:
304 nav->priv->direction = g_value_get_int (value);
305 break;
306 case PROP_WINDOW:
307 nav->priv->window = CAJA_NAVIGATION_WINDOW (g_value_get_object (value));
308 break;
309 }
310 }
311
312 static void
caja_navigation_action_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)313 caja_navigation_action_get_property (GObject *object,
314 guint prop_id,
315 GValue *value,
316 GParamSpec *pspec)
317 {
318 CajaNavigationAction *nav;
319
320 nav = CAJA_NAVIGATION_ACTION (object);
321
322 switch (prop_id)
323 {
324 case PROP_ARROW_TOOLTIP:
325 g_value_set_string (value, nav->priv->arrow_tooltip);
326 break;
327 case PROP_DIRECTION:
328 g_value_set_int (value, nav->priv->direction);
329 break;
330 case PROP_WINDOW:
331 g_value_set_object (value, nav->priv->window);
332 break;
333 }
334 }
335
336 static void
caja_navigation_action_class_init(CajaNavigationActionClass * class)337 caja_navigation_action_class_init (CajaNavigationActionClass *class)
338 {
339 GObjectClass *object_class = G_OBJECT_CLASS (class);
340 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
341 GtkActionClass *action_class = GTK_ACTION_CLASS (class);
342 G_GNUC_END_IGNORE_DEPRECATIONS;
343
344 object_class->finalize = caja_navigation_action_finalize;
345 object_class->set_property = caja_navigation_action_set_property;
346 object_class->get_property = caja_navigation_action_get_property;
347
348 action_class->toolbar_item_type = GTK_TYPE_MENU_TOOL_BUTTON;
349 action_class->connect_proxy = connect_proxy;
350 action_class->disconnect_proxy = disconnect_proxy;
351
352 g_object_class_install_property (object_class,
353 PROP_ARROW_TOOLTIP,
354 g_param_spec_string ("arrow-tooltip",
355 "Arrow Tooltip",
356 "Arrow Tooltip",
357 NULL,
358 G_PARAM_READWRITE));
359 g_object_class_install_property (object_class,
360 PROP_DIRECTION,
361 g_param_spec_int ("direction",
362 "Direction",
363 "Direction",
364 0,
365 G_MAXINT,
366 0,
367 G_PARAM_READWRITE));
368 g_object_class_install_property (object_class,
369 PROP_WINDOW,
370 g_param_spec_object ("window",
371 "Window",
372 "The navigation window",
373 G_TYPE_OBJECT,
374 G_PARAM_READWRITE));
375 }
376
377 static void
caja_navigation_action_init(CajaNavigationAction * action)378 caja_navigation_action_init (CajaNavigationAction *action)
379 {
380 action->priv = caja_navigation_action_get_instance_private (action);
381 }
382