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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, 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
);
177 update_recent_submenu (EggRecentAction
*action
, GtkWidget
*submenu
,
178 EggRecentModel
*model
, gint id
)
180 EggRecentViewGtk
*recent_view
;
181 GtkWidget
*sep
= NULL
;
186 sep
= gtk_menu_item_new ();
187 gtk_widget_show (sep
);
188 gtk_menu_shell_append (GTK_MENU_SHELL (submenu
), sep
);
190 recent_view
= egg_recent_view_gtk_new (submenu
, sep
);
191 egg_recent_view_gtk_set_tooltip_func (recent_view
,
192 on_recent_files_tooltip
, NULL
);
193 egg_recent_view_set_model (EGG_RECENT_VIEW (recent_view
),
195 snprintf (buff
, 64, "recent-view-%d", id
);
196 g_object_set_data_full (G_OBJECT (submenu
), buff
, recent_view
,
198 g_signal_connect (G_OBJECT (recent_view
), "activate",
199 G_CALLBACK (on_recent_select
), action
);
203 create_recent_submenu (EggRecentAction
*action
)
209 submenu
= gtk_menu_new ();
210 node
= action
->priv
->recent_models
;
214 update_recent_submenu (action
, submenu
, node
->data
, id
);
216 node
= g_list_next (node
);
222 on_reposition_menu (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
,
225 gint x1
, y1
, w
, h
, d
;
226 GtkWidget
*button
= GTK_WIDGET (data
);
227 gdk_window_get_origin (button
->window
, x
, y
);
228 gdk_window_get_geometry (button
->window
, &x1
, &y1
, &w
, &h
, &d
);
229 *y
+= button
->allocation
.height
;
230 if (GTK_WIDGET_NO_WINDOW (button
))
232 *x
+= button
->allocation
.x
;
233 *y
+= button
->allocation
.y
;
238 on_selection_done_menu (GtkMenu
*menu
, GtkWidget
*button
)
240 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), FALSE
);
244 on_button_pressed (GtkToggleToolButton
*button
, EggRecentAction
*action
)
248 /* g_message ("Recent toolitem toggled"); */
249 submenu
= g_object_get_data (G_OBJECT (button
), "submenu");
252 submenu
= create_recent_submenu (action
);
253 g_object_set_data_full (G_OBJECT (button
), "submenu", submenu
,
254 (GDestroyNotify
)gtk_widget_destroy
);
255 g_object_set_data (G_OBJECT (submenu
), "thebutton", button
);
256 g_signal_connect (G_OBJECT (submenu
), "selection-done",
257 G_CALLBACK (on_selection_done_menu
), button
);
258 gtk_widget_show (submenu
);
260 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button
)))
262 gtk_menu_popup (GTK_MENU (submenu
), NULL
, NULL
, on_reposition_menu
,
263 button
, 0, gtk_get_current_event_time ());
264 gtk_menu_reposition (GTK_MENU (submenu
));
268 gtk_menu_popdown (GTK_MENU (submenu
));
273 create_tool_item (GtkAction
*action
)
279 g_return_val_if_fail (EGG_IS_RECENT_ACTION (action
), NULL
);
280 /* g_message ("Creating recent toolitem"); */
282 item
= gtk_tool_item_new ();
283 gtk_widget_show(GTK_WIDGET (item
));
284 button
= gtk_toggle_button_new ();
285 gtk_button_set_relief (GTK_BUTTON (button
), GTK_RELIEF_NONE
);
286 gtk_container_add (GTK_CONTAINER (item
), button
);
287 gtk_widget_show(GTK_WIDGET (button
));
288 arrow
= gtk_arrow_new (GTK_ARROW_DOWN
, GTK_SHADOW_NONE
);
289 gtk_widget_show (arrow
);
290 gtk_container_add (GTK_CONTAINER (button
), arrow
);
291 return GTK_WIDGET (item
);
295 create_menu_item (GtkAction
*action
)
297 GtkWidget
*menuitem
, *submenu
;
298 menuitem
= (* GTK_ACTION_CLASS (parent_class
)->create_menu_item
) (action
);
299 submenu
= create_recent_submenu (EGG_RECENT_ACTION (action
));
300 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem
), submenu
);
305 connect_proxy (GtkAction
*action
, GtkWidget
*proxy
)
307 EggRecentAction
*recent_action
;
309 recent_action
= EGG_RECENT_ACTION (action
);
311 /* do this before hand, so that we don't call the "activate" handler */
312 if (GTK_IS_TOOL_ITEM (proxy
))
314 g_signal_connect (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy
))), "toggled",
315 G_CALLBACK (on_button_pressed
), action
);
317 (* GTK_ACTION_CLASS (parent_class
)->connect_proxy
) (action
, proxy
);
321 disconnect_proxy (GtkAction
*action
, GtkWidget
*proxy
)
323 EggRecentAction
*recent_action
;
325 recent_action
= EGG_RECENT_ACTION (action
);
327 /* do this before hand, so that we don't call the "activate" handler */
328 if (GTK_IS_TOOL_ITEM (proxy
))
330 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy
))),
331 G_CALLBACK (on_button_pressed
), action
);
333 (* GTK_ACTION_CLASS (parent_class
)->connect_proxy
) (action
, proxy
);
337 * egg_recent_action_set_model:
338 * @action: the action object
339 * @model: a GtkTreeModel
341 * Sets a model in the action.
344 egg_recent_action_add_model (EggRecentAction
*action
, EggRecentModel
*model
)
348 g_return_if_fail (EGG_IS_RECENT_ACTION (action
));
349 g_return_if_fail (EGG_IS_RECENT_MODEL (model
));
351 g_object_ref (model
);
352 action
->priv
->recent_models
=
353 g_list_append (action
->priv
->recent_models
, model
);
355 for (slist
= gtk_action_get_proxies (GTK_ACTION(action
));
356 slist
; slist
= slist
->next
)
358 GtkWidget
*proxy
= slist
->data
;
360 gtk_action_block_activate_from (GTK_ACTION (action
), proxy
);
362 if (GTK_IS_MENU_ITEM (proxy
))
366 submenu
= gtk_menu_item_get_submenu (GTK_MENU_ITEM(proxy
));
367 update_recent_submenu (action
, submenu
, model
,
368 g_list_length (action
->priv
->recent_models
)-1);
370 else if (GTK_IS_TOOL_ITEM (proxy
))
374 submenu
= g_object_get_data (G_OBJECT (gtk_bin_get_child(GTK_BIN(proxy
))), "submenu");
375 update_recent_submenu (action
, submenu
, model
,
376 g_list_length (action
->priv
->recent_models
)-1);
380 g_warning ("Don't know how to set popdown for `%s' widgets",
381 G_OBJECT_TYPE_NAME (proxy
));
383 gtk_action_unblock_activate_from (GTK_ACTION (action
), proxy
);
388 egg_recent_action_get_selected_uri (EggRecentAction
*action
)
390 return action
->priv
->selected_uri
;