1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* egg-recent-action widget
5 * Copyright (C) Naba Kumar <naba@gnome.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 #include <gtk/gtkwidget.h>
24 #include <gtk/gtktoggletoolbutton.h>
25 #include <libegg/recent-files/egg-recent-view.h>
26 #include <libegg/recent-files/egg-recent-view-gtk.h>
27 #include "egg-recent-action.h"
33 struct _EggRecentActionPriv
40 static void egg_recent_action_init (EggRecentAction
*action
);
41 static void egg_recent_action_class_init (EggRecentActionClass
*class);
43 static GtkWidget
* create_tool_item (GtkAction
*action
);
44 static GtkWidget
* create_menu_item (GtkAction
*action
);
45 static void connect_proxy (GtkAction
*action
,
47 static void disconnect_proxy (GtkAction
*action
,
49 static void egg_recent_action_finalize (GObject
*object
);
50 static void egg_recent_action_dispose (GObject
*object
);
51 static gboolean
on_recent_select (EggRecentView
*recent
, EggRecentItem
*item
,
52 EggRecentAction
*plugin
);
54 static GObjectClass
*parent_class
= NULL
;
57 egg_recent_action_get_type (void)
59 static GtkType type
= 0;
63 static const GTypeInfo type_info
=
65 sizeof (EggRecentActionClass
),
67 (GBaseFinalizeFunc
) NULL
,
68 (GClassInitFunc
) egg_recent_action_class_init
,
69 (GClassFinalizeFunc
) NULL
,
72 sizeof (EggRecentAction
),
74 (GInstanceInitFunc
) egg_recent_action_init
,
77 type
= g_type_register_static (GTK_TYPE_ACTION
,
85 egg_recent_action_class_init (EggRecentActionClass
*class)
87 GtkActionClass
*action_class
;
88 GObjectClass
*object_class
;
90 parent_class
= g_type_class_peek_parent (class);
91 action_class
= GTK_ACTION_CLASS (class);
92 object_class
= G_OBJECT_CLASS (class);
94 object_class
->finalize
= egg_recent_action_finalize
;
95 object_class
->dispose
= egg_recent_action_dispose
;
97 action_class
->connect_proxy
= connect_proxy
;
98 action_class
->disconnect_proxy
= disconnect_proxy
;
99 action_class
->menu_item_type
= GTK_TYPE_MENU_ITEM
;
100 action_class
->toolbar_item_type
= GTK_TYPE_TOOL_ITEM
;
101 action_class
->create_tool_item
= create_tool_item
;
102 action_class
->create_menu_item
= create_menu_item
;
106 egg_recent_action_init (EggRecentAction
*action
)
108 action
->priv
= g_new0 (EggRecentActionPriv
, 1);
109 action
->priv
->recent_models
= NULL
;
110 action
->priv
->selected_uri
= NULL
;
114 egg_recent_action_dispose (GObject
*object
)
116 EggRecentActionPriv
*priv
;
118 priv
= EGG_RECENT_ACTION (object
)->priv
;
119 if (priv
->recent_models
)
122 node
= priv
->recent_models
;
125 g_object_unref (node
->data
);
126 node
= g_list_next (node
);
128 g_list_free (priv
->recent_models
);
129 priv
->recent_models
= NULL
;
131 if (parent_class
->dispose
)
132 parent_class
->dispose (object
);
136 egg_recent_action_finalize (GObject
*object
)
138 g_free (EGG_RECENT_ACTION (object
)->priv
->selected_uri
);
139 g_free (EGG_RECENT_ACTION (object
)->priv
);
140 if (parent_class
->finalize
)
141 parent_class
->finalize (object
);
145 on_recent_select (EggRecentView
*view
, EggRecentItem
*item
,
146 EggRecentAction
*action
)
151 uri
= egg_recent_item_get_uri (item
);
154 g_free (action
->priv
->selected_uri
);
155 action
->priv
->selected_uri
= g_strdup (uri
);
157 gtk_action_activate (GTK_ACTION (action
));
163 on_recent_files_tooltip (GtkTooltips
*tooltips
, GtkWidget
*menu_item
,
164 EggRecentItem
*item
, gpointer user_data
)
168 uri
= egg_recent_item_get_uri_for_display (item
);
169 tip
= g_strdup_printf ("Open '%s'", uri
);
171 gtk_tooltips_set_tip (tooltips
, menu_item
, tip
, NULL
);
178 update_recent_submenu (EggRecentAction
*action
, GtkWidget
*submenu
,
179 EggRecentModel
*model
, gint id
)
181 EggRecentViewGtk
*recent_view
;
182 GtkWidget
*sep
= NULL
;
187 sep
= gtk_menu_item_new ();
188 gtk_widget_show (sep
);
189 gtk_menu_shell_append (GTK_MENU_SHELL (submenu
), sep
);
191 recent_view
= egg_recent_view_gtk_new (submenu
, sep
);
192 egg_recent_view_gtk_set_tooltip_func (recent_view
,
193 on_recent_files_tooltip
, NULL
);
194 egg_recent_view_set_model (EGG_RECENT_VIEW (recent_view
),
196 snprintf (buff
, 64, "recent-view-%d", id
);
197 g_object_set_data_full (G_OBJECT (submenu
), buff
, recent_view
,
199 g_signal_connect (G_OBJECT (recent_view
), "activate",
200 G_CALLBACK (on_recent_select
), action
);
204 create_recent_submenu (EggRecentAction
*action
)
210 submenu
= gtk_menu_new ();
211 node
= action
->priv
->recent_models
;
215 update_recent_submenu (action
, submenu
, node
->data
, id
);
217 node
= g_list_next (node
);
223 on_reposition_menu (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
,
226 gint x1
, y1
, w
, h
, d
;
227 GtkWidget
*button
= GTK_WIDGET (data
);
228 gdk_window_get_origin (button
->window
, x
, y
);
229 gdk_window_get_geometry (button
->window
, &x1
, &y1
, &w
, &h
, &d
);
230 *y
+= button
->allocation
.height
;
231 if (GTK_WIDGET_NO_WINDOW (button
))
233 *x
+= button
->allocation
.x
;
234 *y
+= button
->allocation
.y
;
239 on_selection_done_menu (GtkMenu
*menu
, GtkWidget
*button
)
241 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), FALSE
);
245 on_button_pressed (GtkToggleToolButton
*button
, EggRecentAction
*action
)
249 /* g_message ("Recent toolitem toggled"); */
250 submenu
= g_object_get_data (G_OBJECT (button
), "submenu");
253 submenu
= create_recent_submenu (action
);
254 g_object_set_data_full (G_OBJECT (button
), "submenu", submenu
,
255 (GDestroyNotify
)gtk_widget_destroy
);
256 g_object_set_data (G_OBJECT (submenu
), "thebutton", button
);
257 g_signal_connect (G_OBJECT (submenu
), "selection-done",
258 G_CALLBACK (on_selection_done_menu
), button
);
259 gtk_widget_show (submenu
);
261 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button
)))
263 gtk_menu_popup (GTK_MENU (submenu
), NULL
, NULL
, on_reposition_menu
,
264 button
, 0, gtk_get_current_event_time ());
265 gtk_menu_reposition (GTK_MENU (submenu
));
269 gtk_menu_popdown (GTK_MENU (submenu
));
274 create_tool_item (GtkAction
*action
)
280 g_return_val_if_fail (EGG_IS_RECENT_ACTION (action
), NULL
);
281 /* g_message ("Creating recent toolitem"); */
283 item
= gtk_tool_item_new ();
284 gtk_widget_show(GTK_WIDGET (item
));
285 button
= gtk_toggle_button_new ();
286 gtk_button_set_relief (GTK_BUTTON (button
), GTK_RELIEF_NONE
);
287 gtk_container_add (GTK_CONTAINER (item
), button
);
288 gtk_widget_show(GTK_WIDGET (button
));
289 arrow
= gtk_arrow_new (GTK_ARROW_DOWN
, GTK_SHADOW_NONE
);
290 gtk_widget_show (arrow
);
291 gtk_container_add (GTK_CONTAINER (button
), arrow
);
292 return GTK_WIDGET (item
);
296 create_menu_item (GtkAction
*action
)
298 GtkWidget
*menuitem
, *submenu
;
299 menuitem
= (* GTK_ACTION_CLASS (parent_class
)->create_menu_item
) (action
);
300 submenu
= create_recent_submenu (EGG_RECENT_ACTION (action
));
301 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem
), submenu
);
306 connect_proxy (GtkAction
*action
, GtkWidget
*proxy
)
308 EggRecentAction
*recent_action
;
310 recent_action
= EGG_RECENT_ACTION (action
);
312 /* do this before hand, so that we don't call the "activate" handler */
313 if (GTK_IS_TOOL_ITEM (proxy
))
315 g_signal_connect (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy
))), "toggled",
316 G_CALLBACK (on_button_pressed
), action
);
318 (* GTK_ACTION_CLASS (parent_class
)->connect_proxy
) (action
, proxy
);
322 disconnect_proxy (GtkAction
*action
, GtkWidget
*proxy
)
324 EggRecentAction
*recent_action
;
326 recent_action
= EGG_RECENT_ACTION (action
);
328 /* do this before hand, so that we don't call the "activate" handler */
329 if (GTK_IS_TOOL_ITEM (proxy
))
331 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy
))),
332 G_CALLBACK (on_button_pressed
), action
);
334 (* GTK_ACTION_CLASS (parent_class
)->connect_proxy
) (action
, proxy
);
338 * egg_recent_action_set_model:
339 * @action: the action object
340 * @model: a GtkTreeModel
342 * Sets a model in the action.
345 egg_recent_action_add_model (EggRecentAction
*action
, EggRecentModel
*model
)
349 g_return_if_fail (EGG_IS_RECENT_ACTION (action
));
350 g_return_if_fail (EGG_IS_RECENT_MODEL (model
));
352 g_object_ref (model
);
353 action
->priv
->recent_models
=
354 g_list_append (action
->priv
->recent_models
, model
);
356 for (slist
= gtk_action_get_proxies (GTK_ACTION(action
));
357 slist
; slist
= slist
->next
)
359 GtkWidget
*proxy
= slist
->data
;
361 gtk_action_block_activate_from (GTK_ACTION (action
), proxy
);
363 if (GTK_IS_MENU_ITEM (proxy
))
367 submenu
= gtk_menu_item_get_submenu (GTK_MENU_ITEM(proxy
));
368 update_recent_submenu (action
, submenu
, model
,
369 g_list_length (action
->priv
->recent_models
)-1);
371 else if (GTK_IS_TOOL_ITEM (proxy
))
375 submenu
= g_object_get_data (G_OBJECT (gtk_bin_get_child(GTK_BIN(proxy
))), "submenu");
376 update_recent_submenu (action
, submenu
, model
,
377 g_list_length (action
->priv
->recent_models
)-1);
381 g_warning ("Don't know how to set popdown for `%s' widgets",
382 G_OBJECT_TYPE_NAME (proxy
));
384 gtk_action_unblock_activate_from (GTK_ACTION (action
), proxy
);
389 egg_recent_action_get_selected_uri (EggRecentAction
*action
)
391 return action
->priv
->selected_uri
;