1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of the
6 * License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18 * James Willcox <jwillcox@cs.indiana.edu>
29 #include <libgnomevfs/gnome-vfs.h>
30 #ifndef USE_STABLE_LIBGNOMEUI
31 #include <libgnomeui/gnome-icon-theme.h>
33 #include <gconf/gconf-client.h>
34 #include "egg-recent-model.h"
35 #include "egg-recent-view.h"
36 #include "egg-recent-view-gtk.h"
37 #include "egg-recent-util.h"
38 #include "egg-recent-item.h"
40 struct _EggRecentViewGtk {
41 GObject parent_instance; /* We emit signals */
44 GtkWidget *start_menu_item;
47 gboolean trailing_sep;
54 gboolean show_numbers;
55 #ifndef USE_STABLE_LIBGNOMEUI
56 GnomeIconTheme *theme;
59 GtkTooltips *tooltips;
60 EggRecentViewGtkTooltipFunc tooltip_func;
61 gpointer tooltip_func_data;
63 EggRecentModel *model;
65 GtkIconSize icon_size;
70 struct _EggRecentViewGtkMenuData {
71 EggRecentViewGtk *view;
75 typedef struct _EggRecentViewGtkMenuData EggRecentViewGtkMenuData;
82 /* GObject properties */
91 static guint view_signals[LAST_SIGNAL] = { 0 };
95 egg_recent_view_gtk_clear (EggRecentViewGtk *view)
100 gint *menu_data=NULL;
102 if (view->menu == NULL)
105 menu_children = gtk_container_get_children (GTK_CONTAINER (view->menu));
109 menu_item = (GObject *)p->data;
111 menu_data = (gint *)g_object_get_data (menu_item,
115 gtk_container_remove (GTK_CONTAINER (view->menu),
116 GTK_WIDGET (menu_item));
126 egg_recent_view_gtk_find_menu_offset (EggRecentViewGtk *view)
129 GList *menu_children;
131 GtkWidget *menu_item;
134 g_return_val_if_fail (view, 0);
136 menu_children = GTK_MENU_SHELL (view->menu)->children;
141 menu_item = (GtkWidget *)p->data;
143 if (menu_item == view->start_menu_item) {
156 egg_recent_view_gtk_menu_cb (GtkWidget *menu, gpointer data)
158 EggRecentViewGtkMenuData *md = (EggRecentViewGtkMenuData *) data;
161 g_return_if_fail (md);
162 g_return_if_fail (md->item);
163 g_return_if_fail (md->view);
164 g_return_if_fail (EGG_IS_RECENT_VIEW_GTK (md->view));
168 egg_recent_item_ref (item);
170 g_signal_emit (G_OBJECT(md->view), view_signals[ACTIVATE], 0,
173 egg_recent_item_unref (item);
177 egg_recent_view_gtk_destroy_cb (gpointer data, GClosure *closure)
179 EggRecentViewGtkMenuData *md = data;
181 egg_recent_item_unref (md->item);
186 egg_recent_view_gtk_new_separator (EggRecentViewGtk *view)
190 g_return_val_if_fail (view, NULL);
192 retval = gtk_separator_menu_item_new ();
195 * this is a tag so we can distinguish our menu items
196 * from others that may be in the menu.
198 g_object_set_data (G_OBJECT (retval),
200 GINT_TO_POINTER (1));
203 gtk_widget_show (retval);
209 egg_recent_view_gtk_new_menu_item (EggRecentViewGtk *view,
213 GtkWidget *menu_item;
214 EggRecentViewGtkMenuData *md;
222 g_return_val_if_fail (view, NULL);
223 g_return_val_if_fail (item, NULL);
225 short_name = egg_recent_item_get_short_name (item);
229 escaped = egg_recent_util_escape_underlines (short_name);
232 if (view->show_numbers) {
233 /* avoid having conflicting mnemonics */
235 text = g_strdup_printf ("%d. %s", index,
238 text = g_strdup_printf ("_%d. %s", index,
245 mime_type = egg_recent_item_get_mime_type (item);
246 #ifndef USE_STABLE_LIBGNOMEUI
251 gtk_icon_size_lookup_for_settings
252 (gtk_widget_get_settings (view->menu),
256 uri = egg_recent_item_get_uri (item);
257 pixbuf = egg_recent_util_get_icon (view->theme, uri,
265 image = gtk_image_new_from_pixbuf (pixbuf);
267 g_object_unref (pixbuf);
269 if (view->show_icons)
270 gtk_widget_show (image);
272 menu_item = gtk_image_menu_item_new_with_mnemonic (text);
273 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
276 md = g_new0 (EggRecentViewGtkMenuData, 1);
278 md->item = egg_recent_item_ref (item);
280 g_signal_connect_data (G_OBJECT (menu_item), "activate",
281 G_CALLBACK (egg_recent_view_gtk_menu_cb),
283 (GClosureNotify)egg_recent_view_gtk_destroy_cb,
290 * this is a tag so we can distinguish our menu items
291 * from others that may be in the menu.
293 g_object_set_data (G_OBJECT (menu_item),
295 GINT_TO_POINTER (1));
298 gtk_widget_show (menu_item);
304 egg_recent_view_gtk_add_to_menu (EggRecentViewGtk *view,
309 GtkWidget *menu_item;
312 g_return_if_fail (view);
313 g_return_if_fail (view->menu);
315 menu_offset = egg_recent_view_gtk_find_menu_offset (view);
318 menu_item = egg_recent_view_gtk_new_menu_item (view, item, display);
320 menu_item = egg_recent_view_gtk_new_separator (view);
322 if (view->tooltip_func != NULL && menu_item != NULL) {
323 view->tooltip_func (view->tooltips, menu_item,
324 item, view->tooltip_func_data);
328 gtk_menu_shell_insert (GTK_MENU_SHELL (view->menu), menu_item,
333 egg_recent_view_gtk_set_list (EggRecentViewGtk *view, GList *list)
340 if (view->menu == NULL)
343 egg_recent_view_gtk_clear (view);
345 if (view->leading_sep) {
346 egg_recent_view_gtk_add_to_menu (view, NULL, display, index);
352 item = (EggRecentItem *)p->data;
354 egg_recent_view_gtk_add_to_menu (view, item, display, index);
361 if (view->trailing_sep)
362 egg_recent_view_gtk_add_to_menu (view, NULL, display, index);
366 model_changed_cb (EggRecentModel *model, GList *list, EggRecentViewGtk *view)
369 egg_recent_view_gtk_set_list (view, list);
371 egg_recent_view_gtk_clear (view);
374 static EggRecentModel *
375 egg_recent_view_gtk_get_model (EggRecentView *view_parent)
377 EggRecentViewGtk *view;
379 g_return_val_if_fail (view_parent != NULL, NULL);
380 view = EGG_RECENT_VIEW_GTK (view_parent);
385 egg_recent_view_gtk_set_model (EggRecentView *view_parent,
386 EggRecentModel *model)
388 EggRecentViewGtk *view;
390 g_return_if_fail (view_parent != NULL);
391 view = EGG_RECENT_VIEW_GTK (view_parent);
393 if (view->model != NULL) {
394 g_object_unref (view->model);
395 g_signal_handler_disconnect (G_OBJECT (model),
396 view->changed_cb_id);
400 g_object_ref (view->model);
402 view->changed_cb_id = g_signal_connect_object (G_OBJECT (model),
404 G_CALLBACK (model_changed_cb),
407 egg_recent_model_changed (view->model);
411 egg_recent_view_gtk_set_leading_sep (EggRecentViewGtk *view, gboolean val)
413 view->leading_sep = val;
415 egg_recent_view_gtk_clear (view);
418 egg_recent_model_changed (view->model);
422 egg_recent_view_gtk_set_trailing_sep (EggRecentViewGtk *view, gboolean val)
424 view->trailing_sep = val;
426 egg_recent_view_gtk_clear (view);
429 egg_recent_model_changed (view->model);
433 egg_recent_view_gtk_set_property (GObject *object,
438 EggRecentViewGtk *view = EGG_RECENT_VIEW_GTK (object);
443 egg_recent_view_gtk_set_menu (view,
444 GTK_WIDGET (g_value_get_object (value)));
446 case PROP_START_MENU_ITEM:
447 egg_recent_view_gtk_set_start_menu_item (view,
448 g_value_get_object (value));
450 case PROP_SHOW_ICONS:
451 egg_recent_view_gtk_show_icons (view,
452 g_value_get_boolean (value));
454 case PROP_SHOW_NUMBERS:
455 egg_recent_view_gtk_show_numbers (view,
456 g_value_get_boolean (value));
459 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
465 egg_recent_view_gtk_get_property (GObject *object,
470 EggRecentViewGtk *view = EGG_RECENT_VIEW_GTK (object);
475 g_value_set_object (value, view->menu);
477 case PROP_START_MENU_ITEM:
478 g_value_set_object (value, view->start_menu_item);
480 case PROP_SHOW_ICONS:
481 g_value_set_boolean (value, view->show_icons);
483 case PROP_SHOW_NUMBERS:
484 g_value_set_boolean (value, view->show_numbers);
487 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
493 egg_recent_view_gtk_finalize (GObject *object)
495 EggRecentViewGtk *view = EGG_RECENT_VIEW_GTK (object);
497 g_signal_handler_disconnect (G_OBJECT (view->model),
498 view->changed_cb_id);
502 g_object_unref (view->model);
503 #ifndef USE_STABLE_LIBGNOMEUI
504 g_object_unref (view->theme);
506 g_object_unref (view->client);
508 g_object_unref (view->tooltips);
512 egg_recent_view_gtk_class_init (EggRecentViewGtkClass * klass)
514 GObjectClass *object_class;
516 object_class = G_OBJECT_CLASS (klass);
518 object_class->set_property = egg_recent_view_gtk_set_property;
519 object_class->get_property = egg_recent_view_gtk_get_property;
520 object_class->finalize = egg_recent_view_gtk_finalize;
522 view_signals[ACTIVATE] = g_signal_new ("activate",
523 G_OBJECT_CLASS_TYPE (object_class),
525 G_STRUCT_OFFSET (EggRecentViewGtkClass, activate),
527 g_cclosure_marshal_VOID__BOXED,
529 EGG_TYPE_RECENT_ITEM);
531 g_object_class_install_property (object_class,
533 g_param_spec_object ("menu",
535 "The GtkMenuShell this object will update.",
538 g_object_class_install_property (object_class,
539 PROP_START_MENU_ITEM,
540 g_param_spec_object ("start-menu-item",
542 "The menu item that precedes where are menu items will go",
543 gtk_menu_item_get_type (),
546 g_object_class_install_property (object_class,
548 g_param_spec_boolean ("show-icons",
550 "Whether or not to show icons",
554 g_object_class_install_property (object_class,
556 g_param_spec_boolean ("show-numbers",
558 "Whether or not to show numbers",
562 klass->activate = NULL;
566 egg_recent_view_init (EggRecentViewClass *iface)
568 iface->do_get_model = egg_recent_view_gtk_get_model;
569 iface->do_set_model = egg_recent_view_gtk_set_model;
573 show_menus_changed_cb (GConfClient *client,
576 EggRecentViewGtk *view)
580 value = gconf_entry_get_value (entry);
582 g_return_if_fail (value->type == GCONF_VALUE_BOOL);
584 egg_recent_view_gtk_show_icons (view,
585 gconf_value_get_bool (value));
589 #ifndef USE_STABLE_LIBGNOMEUI
591 theme_changed_cb (GnomeIconTheme *theme, EggRecentViewGtk *view)
593 if (view->model != NULL)
594 egg_recent_model_changed (view->model);
599 egg_recent_view_gtk_init (EggRecentViewGtk * view)
601 view->client = gconf_client_get_default ();
604 gconf_client_get_bool (view->client,
605 "/desktop/gnome/interface/menus_have_icons",
608 gconf_client_add_dir (view->client, "/desktop/gnome/interface",
609 GCONF_CLIENT_PRELOAD_NONE,
611 gconf_client_notify_add (view->client,
612 "/desktop/gnome/interface/menus_have_icons",
613 (GConfClientNotifyFunc)show_menus_changed_cb,
617 view->leading_sep = FALSE;
618 view->trailing_sep = FALSE;
620 view->uid = egg_recent_util_get_unique_id ();
621 #ifndef USE_STABLE_LIBGNOMEUI
622 view->theme = gnome_icon_theme_new ();
623 gnome_icon_theme_set_allow_svg (view->theme, TRUE);
624 g_signal_connect_object (view->theme, "changed",
625 G_CALLBACK (theme_changed_cb), view, 0);
627 view->tooltips = gtk_tooltips_new ();
628 g_object_ref (view->tooltips);
629 gtk_object_sink (GTK_OBJECT (view->tooltips));
630 view->tooltip_func = NULL;
631 view->tooltip_func_data = NULL;
633 view->icon_size = GTK_ICON_SIZE_MENU;
637 egg_recent_view_gtk_set_icon_size (EggRecentViewGtk *view,
638 GtkIconSize icon_size)
640 if (view->icon_size != icon_size) {
641 view->icon_size = icon_size;
642 egg_recent_model_changed (view->model);
644 view->icon_size = icon_size;
649 egg_recent_view_gtk_get_icon_size (EggRecentViewGtk *view)
651 return view->icon_size;
655 egg_recent_view_gtk_show_icons (EggRecentViewGtk *view, gboolean show)
657 view->show_icons = show;
660 egg_recent_model_changed (view->model);
664 egg_recent_view_gtk_show_numbers (EggRecentViewGtk *view, gboolean show)
666 view->show_numbers = show;
669 egg_recent_model_changed (view->model);
673 egg_recent_view_gtk_set_tooltip_func (EggRecentViewGtk *view,
674 EggRecentViewGtkTooltipFunc func,
677 view->tooltip_func = func;
678 view->tooltip_func_data = user_data;
681 egg_recent_model_changed (view->model);
685 * egg_recent_view_gtk_set_menu:
686 * @view: A EggRecentViewGtk object.
687 * @menu: The GtkMenuShell to put the menu items in.
689 * Use this function to change the GtkMenuShell that the recent
690 * documents appear in.
694 egg_recent_view_gtk_set_menu (EggRecentViewGtk *view,
697 g_return_if_fail (view);
698 g_return_if_fail (EGG_IS_RECENT_VIEW_GTK (view));
700 if (view->menu != NULL)
701 g_object_remove_weak_pointer (G_OBJECT (view->menu),
702 (gpointer *) &view->menu);
706 if (view->menu != NULL)
707 g_object_add_weak_pointer (G_OBJECT (view->menu),
708 (gpointer *) &view->menu);
712 * egg_recent_view_gtk_set_start_menu_item:
713 * @view: A EggRecentViewGtk object.
714 * @start_menu_item: The menu item that appears just before where our menu
715 * items should appear
719 egg_recent_view_gtk_set_start_menu_item (EggRecentViewGtk *view,
720 GtkWidget *menu_item)
722 g_return_if_fail (view);
723 g_return_if_fail (EGG_IS_RECENT_VIEW_GTK (view));
725 view->start_menu_item = menu_item;
729 * egg_recent_view_gtk_get_menu:
730 * @view: A EggRecentViewGtk object.
734 egg_recent_view_gtk_get_menu (EggRecentViewGtk *view)
740 * egg_recent_view_gtk_get_start_menu_item
741 * @view: A EggRecentViewGtk object.
745 egg_recent_view_gtk_get_start_menu_item (EggRecentViewGtk *view)
747 return view->start_menu_item;
752 * egg_recent_view_gtk_new:
753 * @appname: The name of your application.
754 * @limit: The maximum number of items allowed.
756 * This creates a new EggRecentViewGtk object.
758 * Returns: a EggRecentViewGtk object
761 egg_recent_view_gtk_new (GtkWidget *menu, GtkWidget *start_menu_item)
763 EggRecentViewGtk *view;
765 g_return_val_if_fail (menu, NULL);
767 view = EGG_RECENT_VIEW_GTK (g_object_new (egg_recent_view_gtk_get_type (),
771 "show-numbers", TRUE, NULL));
773 g_return_val_if_fail (view, NULL);
779 * egg_recent_view_gtk_get_type:
781 * This returns a GType representing a EggRecentViewGtk object.
786 egg_recent_view_gtk_get_type (void)
788 static GType egg_recent_view_gtk_type = 0;
790 if(!egg_recent_view_gtk_type) {
791 static const GTypeInfo egg_recent_view_gtk_info = {
792 sizeof (EggRecentViewGtkClass),
793 NULL, /* base init */
794 NULL, /* base finalize */
795 (GClassInitFunc)egg_recent_view_gtk_class_init, /* class init */
796 NULL, /* class finalize */
797 NULL, /* class data */
798 sizeof (EggRecentViewGtk),
800 (GInstanceInitFunc) egg_recent_view_gtk_init
803 static const GInterfaceInfo view_info =
805 (GInterfaceInitFunc) egg_recent_view_init,
810 egg_recent_view_gtk_type = g_type_register_static (G_TYPE_OBJECT,
812 &egg_recent_view_gtk_info, 0);
813 g_type_add_interface_static (egg_recent_view_gtk_type,
814 EGG_TYPE_RECENT_VIEW,
818 return egg_recent_view_gtk_type;