summaryrefslogtreecommitdiff
path: root/gtk/gtkrecentchoosermenu.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2006-08-03 20:26:31 +0000
committerEmmanuele Bassi <ebassi@src.gnome.org>2006-08-03 20:26:31 +0000
commitcace1bce281b584abb3b8d1ce61ce05c9c4fc305 (patch)
tree5a0f49b5fc3e5de2096e3886a198c740f375e8bc /gtk/gtkrecentchoosermenu.c
parent1ed82d3f1c907cd3c2eb57f22ff3c4ef078c2392 (diff)
downloadgtk+-cace1bce281b584abb3b8d1ce61ce05c9c4fc305.tar.gz
Lazily populate the menu when creating it and after the manager emits the
2006-08-03 Emmanuele Bassi <ebassi@gnome.org> * gtk/gtkrecentchoosermenu.c: (set_recent_managet), (gtk_recent_chooser_menu_populate), (idle_populate_func), (idle_populate_clean_up), (manager_changed_cb): Lazily populate the menu when creating it and after the manager emits the "changed" signal; this fixes the initial bad placing of the GtkRecentChooserMenu widget when its set as the menu of a GtkMenuToolButton. (gtk_recent_chooser_menu_map), (gtk_recent_chooser_menu_class_init): Remove the ::map method override, since it's not needed anymore.
Diffstat (limited to 'gtk/gtkrecentchoosermenu.c')
-rw-r--r--gtk/gtkrecentchoosermenu.c251
1 files changed, 147 insertions, 104 deletions
diff --git a/gtk/gtkrecentchoosermenu.c b/gtk/gtkrecentchoosermenu.c
index 57e9608748..ae5a0149c2 100644
--- a/gtk/gtkrecentchoosermenu.c
+++ b/gtk/gtkrecentchoosermenu.c
@@ -83,6 +83,8 @@ struct _GtkRecentChooserMenuPrivate
guint local_manager : 1;
gulong manager_changed_id;
+ gulong populate_id;
+
/* tooltips for our bookmark items*/
GtkTooltips *tooltips;
};
@@ -139,7 +141,7 @@ static GSList * gtk_recent_chooser_menu_list_filters (GtkRecentCh
static void gtk_recent_chooser_menu_set_current_filter (GtkRecentChooserMenu *menu,
GtkRecentFilter *filter);
-static void gtk_recent_chooser_menu_map (GtkWidget *widget);
+static void gtk_recent_chooser_menu_populate (GtkRecentChooserMenu *menu);
static void gtk_recent_chooser_menu_set_show_tips (GtkRecentChooserMenu *menu,
gboolean show_tips);
@@ -184,15 +186,12 @@ static void
gtk_recent_chooser_menu_class_init (GtkRecentChooserMenuClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
+
gobject_class->constructor = gtk_recent_chooser_menu_constructor;
gobject_class->finalize = gtk_recent_chooser_menu_finalize;
gobject_class->set_property = gtk_recent_chooser_menu_set_property;
gobject_class->get_property = gtk_recent_chooser_menu_get_property;
- widget_class->map = gtk_recent_chooser_menu_map;
-
_gtk_recent_chooser_install_properties (gobject_class);
/**
@@ -940,117 +939,156 @@ gtk_recent_chooser_menu_dispose_items (GtkRecentChooserMenu *menu)
g_list_free (children);
}
-/* GtkWidget::map method override
- *
- * We override this method in order to populate the menu with our
- * menu items linked to the recently used resources.
- */
-static void
-gtk_recent_chooser_menu_map (GtkWidget *widget)
+typedef struct
{
- GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (widget);
- GtkRecentChooserMenuPrivate *priv = menu->priv;
- GList *items, *l;
- gint count;
- gboolean has_items = FALSE;
-
- if (GTK_WIDGET_CLASS (gtk_recent_chooser_menu_parent_class)->map)
- GTK_WIDGET_CLASS (gtk_recent_chooser_menu_parent_class)->map (widget);
-
- priv->icon_size = get_icon_size_for_widget (widget);
-
- /* dispose our menu items first */
- gtk_recent_chooser_menu_dispose_items (menu);
-
- items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (menu));
-
- count = g_list_length (items);
- items = g_list_reverse (items);
+ GList *items;
+ gint n_items;
+ gint loaded_items;
+ GtkRecentChooserMenu *menu;
+} MenuPopulateData;
+
+static gboolean
+idle_populate_func (gpointer data)
+{
+ MenuPopulateData *pdata;
+ GtkRecentChooserMenuPrivate *priv;
+ GtkRecentInfo *info;
+ gboolean retval;
+ GtkWidget *item;
- for (l = items; l != NULL; l = l->next)
+ GDK_THREADS_ENTER ();
+
+ pdata = (MenuPopulateData *) data;
+
+ if (!pdata->items)
{
- GtkRecentInfo *info = (GtkRecentInfo *) l->data;
- GtkWidget *item;
+ 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);
- g_assert (info != NULL);
+ /* no items: add a placeholder menu */
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+ }
- /* skip non-local items on request */
- if (priv->local_only && !gtk_recent_info_is_local (info))
- continue;
+ /* reverse the list */
+ pdata->items = g_list_reverse (pdata->items);
- /* skip private items on request */
- if (!priv->show_private && gtk_recent_info_get_private_hint (info))
- continue;
+ pdata->n_items = g_list_length (pdata->items);
+ pdata->loaded_items = 0;
+ }
+
+ info = g_list_nth_data (pdata->items, pdata->loaded_items);
+ priv = pdata->menu->priv;
+
+ /* skip non-local items on request */
+ if (priv->local_only && !gtk_recent_info_is_local (info))
+ goto check_and_return;
- /* skip non-existing items on request */
- if (!priv->show_not_found && !gtk_recent_info_exists (info))
- continue;
+ /* skip private items on request */
+ if (!priv->show_private && gtk_recent_info_get_private_hint (info))
+ goto check_and_return;
+
+ /* skip non-existing items on request */
+ if (!priv->show_not_found && !gtk_recent_info_exists (info))
+ goto check_and_return;
- /* filter items based on the currently set filter object */
- if (get_is_recent_filtered (menu, info))
- continue;
+ /* filter items based on the currently set filter object */
+ if (get_is_recent_filtered (pdata->menu, info))
+ goto check_and_return;
- item = gtk_recent_chooser_menu_create_item (menu, info, count);
- if (!item)
- continue;
+ item = gtk_recent_chooser_menu_create_item (pdata->menu,
+ info,
+ pdata->loaded_items);
+ if (!item)
+ goto check_and_return;
- gtk_recent_chooser_menu_add_tip (menu, info, item);
+ 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 (menu), item);
- gtk_widget_show (item);
-
- /* mark the menu item as one of our own */
- g_object_set_data (G_OBJECT (item), "gtk-recent-menu-mark",
- GINT_TO_POINTER (1));
+ /* 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);
- /* attach the RecentInfo object to the menu item, and own a reference
- * to it, so that it will be destroyed with the menu item when it's
- * not needed anymore.
- */
- g_object_set_data_full (G_OBJECT (item), "gtk-recent-info",
- gtk_recent_info_ref (info),
- (GDestroyNotify) gtk_recent_info_unref);
+ /* mark the menu item as one of our own */
+ g_object_set_data (G_OBJECT (item), "gtk-recent-menu-mark",
+ GINT_TO_POINTER (1));
- /* we have at least one item */
- if (!has_items)
- has_items = TRUE;
- }
-
- /* now, the RecentInfo objects are bound to the lifetime of the menu */
- if (items)
- {
- g_list_foreach (items,
- (GFunc) gtk_recent_info_unref,
- NULL);
- g_list_free (items);
- }
-
- /* no recently used resources were found, or they were filtered out, so
- * we build an item stating that no recently used resources were found
- * (as night follows the day...).
+ /* attach the RecentInfo object to the menu item, and own a reference
+ * to it, so that it will be destroyed with the menu item when it's
+ * not needed anymore.
*/
- if (!has_items)
+ g_object_set_data_full (G_OBJECT (item), "gtk-recent-info",
+ gtk_recent_info_ref (info),
+ (GDestroyNotify) gtk_recent_info_unref);
+
+check_and_return:
+ pdata->loaded_items += 1;
+
+ if (pdata->loaded_items == pdata->n_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 (menu), item);
- gtk_widget_show (item);
+ g_list_foreach (pdata->items, (GFunc) gtk_recent_info_unref, NULL);
+ g_list_free (pdata->items);
+
+ retval = FALSE;
}
+ else
+ retval = TRUE;
+
+ GDK_THREADS_LEAVE ();
+
+ return retval;
+}
+
+static void
+idle_populate_clean_up (gpointer data)
+{
+ MenuPopulateData *pdata = data;
+
+ pdata->menu->priv->populate_id = 0;
+
+ g_slice_free (MenuPopulateData, pdata);
+}
+
+static void
+gtk_recent_chooser_menu_populate (GtkRecentChooserMenu *menu)
+{
+ MenuPopulateData *pdata;
+
+ if (menu->priv->populate_id)
+ return;
+
+ pdata = g_slice_new (MenuPopulateData);
+ pdata->items = NULL;
+ pdata->n_items = 0;
+ pdata->loaded_items = 0;
+ pdata->menu = menu;
+
+ menu->priv->icon_size = get_icon_size_for_widget (GTK_WIDGET (menu));
+
+ /* dispose our menu items first */
+ gtk_recent_chooser_menu_dispose_items (menu);
+
+ menu->priv->populate_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 30,
+ idle_populate_func,
+ pdata,
+ idle_populate_clean_up);
}
/* bounce activate signal from the recent menu item widget
@@ -1070,7 +1108,9 @@ static void
manager_changed_cb (GtkRecentManager *manager,
gpointer user_data)
{
- gtk_widget_queue_draw (GTK_WIDGET (user_data));
+ GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (user_data);
+
+ gtk_recent_chooser_menu_populate (menu);
}
static void
@@ -1078,9 +1118,10 @@ set_recent_manager (GtkRecentChooserMenu *menu,
GtkRecentManager *manager)
{
if (menu->priv->manager)
- g_signal_handler_disconnect (menu, menu->priv->manager_changed_id);
-
- menu->priv->manager = NULL;
+ {
+ g_signal_handler_disconnect (menu, menu->priv->manager_changed_id);
+ menu->priv->manager = NULL;
+ }
if (manager)
menu->priv->manager = manager;
@@ -1091,6 +1132,8 @@ set_recent_manager (GtkRecentChooserMenu *menu,
menu->priv->manager_changed_id = g_signal_connect (menu->priv->manager, "changed",
G_CALLBACK (manager_changed_cb),
menu);
+ /* (re)populate the menu */
+ gtk_recent_chooser_menu_populate (menu);
}
static gint