diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2007-02-09 14:24:19 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@src.gnome.org> | 2007-02-09 14:24:19 +0000 |
commit | 4a559d6ec8c1400b5d14913e2bd77621a86a0dc3 (patch) | |
tree | 98afd8f8ba6f08a71fc2b446acae7b72400ccd45 /gtk/gtkrecentchoosermenu.c | |
parent | 661a6bc0211f5db1678e1892a4976f19bfbfa436 (diff) | |
download | gtk+-4a559d6ec8c1400b5d14913e2bd77621a86a0dc3.tar.gz |
Add support for both prepending and appending custom menu items.
2007-02-09 Emmanuele Bassi <ebassi@gnome.org>
* gtk/gtkrecentchoosermenu.c: Add support for both prepending
and appending custom menu items.
(gtk_recent_chooser_menu_constructor): Add a placeholder menu
item for the empty menu case, and for giving us a starting
point for the recent items populating process.
(gtk_recent_chooser_menu_insert_item),
(gtk_recent_chooser_menu_dispose_items): Insert an item at
the position following the placeholder (and find that position
if needed).
(idle_populate_func), (idle_populate_clean_up): Show the
placeholder menu item, instead of creating one each time.
(gtk_recent_chooser_menu_populate): Kill some indirections
and hide the placeholder before populating the menu.
(set_recent_manager): Remember to remove the idle population
source if the manager changes.
* tests/testrecentchoosermenu.c: Test the appending and
prepending of the menu items to the recent chooser menu
widget.
svn path=/trunk/; revision=17281
Diffstat (limited to 'gtk/gtkrecentchoosermenu.c')
-rw-r--r-- | gtk/gtkrecentchoosermenu.c | 160 |
1 files changed, 103 insertions, 57 deletions
diff --git a/gtk/gtkrecentchoosermenu.c b/gtk/gtkrecentchoosermenu.c index 7ccfb05efe..f11541a782 100644 --- a/gtk/gtkrecentchoosermenu.c +++ b/gtk/gtkrecentchoosermenu.c @@ -59,6 +59,9 @@ struct _GtkRecentChooserMenuPrivate /* max size of the menu item label */ gint label_width; + gint first_recent_item_pos; + GtkWidget *placeholder; + /* RecentChooser properties */ gint limit; guint show_private : 1; @@ -237,6 +240,9 @@ gtk_recent_chooser_menu_init (GtkRecentChooserMenu *menu) priv->label_width = DEFAULT_LABEL_WIDTH; + priv->first_recent_item_pos = -1; + priv->placeholder = NULL; + priv->current_filter = NULL; priv->tooltips = gtk_tooltips_new (); @@ -300,19 +306,43 @@ gtk_recent_chooser_menu_dispose (GObject *object) static GObject * gtk_recent_chooser_menu_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_params) + guint n_params, + GObjectConstructParam *params) { GtkRecentChooserMenu *menu; + GtkRecentChooserMenuPrivate *priv; + GObjectClass *parent_class; GObject *object; - object = G_OBJECT_CLASS (gtk_recent_chooser_menu_parent_class)->constructor (type, - n_construct_properties, - construct_params); + parent_class = G_OBJECT_CLASS (gtk_recent_chooser_menu_parent_class); + object = parent_class->constructor (type, n_params, params); menu = GTK_RECENT_CHOOSER_MENU (object); + priv = menu->priv; - g_assert (menu->priv->manager); - + g_assert (priv->manager); + + /* we create a placeholder menuitem, to be used in the case + * were the menu is empty. this placeholder will stay around + * for the entire lifetime of the menu, and we just hide it + * when it's not used. we have to do this, and do it here, + * because we need a marker for the beginning of the recent + * items list, so that we can insert the new items at the + * right place when populating the menu, in case the user + * appended or prepended custom menuitems to the recent + * chooser menu widget. + */ + priv->placeholder = gtk_menu_item_new_with_label (_("No items found")); + gtk_widget_set_sensitive (priv->placeholder, FALSE); + g_object_set_data (G_OBJECT (priv->placeholder), + "gtk-recent-menu-placeholder", + GINT_TO_POINTER (TRUE)); + + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), priv->placeholder, 0); + gtk_widget_show (priv->placeholder); + + /* (re)populate the menu */ + gtk_recent_chooser_menu_populate (menu); + return object; } @@ -962,6 +992,41 @@ gtk_recent_chooser_menu_create_item (GtkRecentChooserMenu *menu, return item; } +static void +gtk_recent_chooser_menu_insert_item (GtkRecentChooserMenu *menu, + GtkWidget *menuitem, + gint position) +{ + GtkRecentChooserMenuPrivate *priv = menu->priv; + gint real_position; + GList *children, *l; + + if (priv->first_recent_item_pos == -1) + { + children = gtk_container_get_children (GTK_CONTAINER (menu)); + for (real_position = 0, l = children; + l != NULL; + real_position += 1, l = l->next) + { + GtkWidget *child = l->data; + gint mark = 0; + + mark = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), + "gtk-recent-menu-placeholder")); + if (mark == 1) + break; + } + g_list_free (children); + priv->first_recent_item_pos = real_position; + } + else + real_position = priv->first_recent_item_pos; + + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, + real_position + position); + gtk_widget_show (menuitem); +} + /* removes the items we own from the menu */ static void gtk_recent_chooser_menu_dispose_items (GtkRecentChooserMenu *menu) @@ -992,6 +1057,9 @@ gtk_recent_chooser_menu_dispose_items (GtkRecentChooserMenu *menu) } } + /* recalculate the position of the first recent item */ + menu->priv->first_recent_item_pos = -1; + g_list_free (children); } @@ -1023,29 +1091,15 @@ idle_populate_func (gpointer data) pdata->items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (pdata->menu)); if (!pdata->items) { - item = gtk_menu_item_new_with_label (_("No items found")); - gtk_widget_set_sensitive (item, FALSE); - - /* we also mark this item, so that it gets removed when rebuilding - * the menu on the next map event - */ - g_object_set_data (G_OBJECT (item), "gtk-recent-menu-mark", - GINT_TO_POINTER (1)); - - gtk_menu_shell_prepend (GTK_MENU_SHELL (pdata->menu), item); - gtk_widget_show (item); - + /* show the placeholder here */ + gtk_widget_show (priv->placeholder); pdata->displayed_items = 1; - /* no items: add a placeholder menu */ GDK_THREADS_LEAVE (); return FALSE; } - /* reverse the list */ - pdata->items = g_list_reverse (pdata->items); - pdata->n_items = g_list_length (pdata->items); pdata->loaded_items = 0; } @@ -1085,16 +1139,9 @@ idle_populate_func (gpointer data) goto check_and_return; gtk_recent_chooser_menu_add_tip (pdata->menu, info, item); - - /* FIXME - * - * We should really place our items taking into account user - * defined menu items; this would also remove the need of - * reverting the scan order. - */ - gtk_menu_shell_prepend (GTK_MENU_SHELL (pdata->menu), item); - gtk_widget_show (item); - + gtk_recent_chooser_menu_insert_item (pdata->menu, item, + pdata->displayed_items); + pdata->displayed_items += 1; /* mark the menu item as one of our own */ @@ -1129,23 +1176,13 @@ static void idle_populate_clean_up (gpointer data) { MenuPopulateData *pdata = data; + GtkRecentChooserMenuPrivate *priv = pdata->menu->priv; + /* show the placeholder in case no item survived + * the filtering process in the idle loop + */ if (!pdata->displayed_items) - { - GtkWidget *item; - - item = gtk_menu_item_new_with_label (_("No items found")); - gtk_widget_set_sensitive (item, FALSE); - - /* we also mark this item, so that it gets removed when rebuilding - * the menu on the next map event - */ - g_object_set_data (G_OBJECT (item), "gtk-recent-menu-mark", - GINT_TO_POINTER (1)); - - gtk_menu_shell_prepend (GTK_MENU_SHELL (pdata->menu), item); - gtk_widget_show (item); - } + gtk_widget_show (priv->placeholder); g_slice_free (MenuPopulateData, data); } @@ -1154,6 +1191,7 @@ static void gtk_recent_chooser_menu_populate (GtkRecentChooserMenu *menu) { MenuPopulateData *pdata; + GtkRecentChooserMenuPrivate *priv = menu->priv; if (menu->priv->populate_id) return; @@ -1165,15 +1203,16 @@ gtk_recent_chooser_menu_populate (GtkRecentChooserMenu *menu) pdata->displayed_items = 0; pdata->menu = menu; - menu->priv->icon_size = get_icon_size_for_widget (GTK_WIDGET (menu)); + priv->icon_size = get_icon_size_for_widget (GTK_WIDGET (menu)); - /* dispose our menu items first */ + /* remove our menu items first and hide the placeholder */ gtk_recent_chooser_menu_dispose_items (menu); + gtk_widget_hide (priv->placeholder); - menu->priv->populate_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30, - idle_populate_func, - pdata, - idle_populate_clean_up); + priv->populate_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30, + idle_populate_func, + pdata, + idle_populate_clean_up); } /* bounce activate signal from the recent menu item widget @@ -1207,7 +1246,16 @@ set_recent_manager (GtkRecentChooserMenu *menu, if (priv->manager) { if (priv->manager_changed_id) - g_signal_handler_disconnect (priv->manager, priv->manager_changed_id); + { + g_signal_handler_disconnect (priv->manager, priv->manager_changed_id); + priv->manager_changed_id = 0; + } + + if (priv->populate_id) + { + g_source_remove (priv->populate_id); + priv->populate_id = 0; + } priv->manager = NULL; } @@ -1221,8 +1269,6 @@ set_recent_manager (GtkRecentChooserMenu *menu, priv->manager_changed_id = g_signal_connect (priv->manager, "changed", G_CALLBACK (manager_changed_cb), menu); - /* (re)populate the menu */ - gtk_recent_chooser_menu_populate (menu); } static gint |