diff options
Diffstat (limited to 'libmdock/mdock-item-menu.c')
-rw-r--r-- | libmdock/mdock-item-menu.c | 185 |
1 files changed, 164 insertions, 21 deletions
diff --git a/libmdock/mdock-item-menu.c b/libmdock/mdock-item-menu.c index 3138c86..bdf0184 100644 --- a/libmdock/mdock-item-menu.c +++ b/libmdock/mdock-item-menu.c @@ -18,9 +18,15 @@ */ #include <glib/gi18n.h> - +#include "../config.h" #include "mdock-item-menu.h" +#ifdef HAVE_ZEITGEIST +#include <zeitgeist.h> +#endif + +#define NUM_RECENT_FILES 10u + #define MDOCK_ITEM_MENU_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_ITEM_MENU, MDockItemMenuPrivate)) struct _MDockItemMenuPrivate @@ -29,6 +35,9 @@ struct _MDockItemMenuPrivate GtkImageMenuItem *menu_close_all; GtkImageMenuItem *menu_pin; GtkImageMenuItem *menu_launch; + + GPtrArray *menu_recent; + GCancellable *recent_fetch; }; G_DEFINE_TYPE (MDockItemMenu, mdock_item_menu, GTK_TYPE_MENU) @@ -41,6 +50,144 @@ enum { static GParamSpec *obj_properties[N_PROPERTIES] = { NULL }; +#ifdef HAVE_ZEITGEIST + +G_DEFINE_QUARK(mdock-item-menu-file, mdock_item_menu_file) + +static void clear_recent_menu(MDockItemMenu *self) +{ + g_ptr_array_set_size(self->priv->menu_recent, 0); + gtk_widget_hide(GTK_WIDGET(self->priv->menu_sep1)); +} + +static void handle_recent_activate(MDockItemMenu *self, GtkImageMenuItem *menu_item) +{ + GFile *file = g_object_get_qdata(G_OBJECT(menu_item), mdock_item_menu_file_quark()); + g_return_if_fail(file); + + mdock_item_launch_file(self->item, file); +} + +static void recents_icon_ready(GObject *source, GAsyncResult *res, gpointer user_data) +{ + GtkImageMenuItem *menu_item = GTK_IMAGE_MENU_ITEM(user_data); + GFile *file = G_FILE(source); + GError *error = NULL; + GFileInfo *info = g_file_query_info_finish(file, res, &error); + if (info) { + + } else { + gchar *uri = g_file_get_uri(file); + g_message("Could not get icon for file '%s': %s", uri, error->message); + g_free(uri); + g_error_free(error); + return; + } + GIcon *icon = g_file_info_get_icon(info); + if (icon) { + GtkImage *image = GTK_IMAGE(gtk_image_menu_item_get_image(menu_item)); + gtk_image_set_from_gicon(image, icon, GTK_ICON_SIZE_MENU); + } + + g_object_unref(info); +} + +static void recents_result_ready(GObject *source, GAsyncResult *res, gpointer user_data) +{ + MDockItemMenu *self = MDOCK_ITEM_MENU(user_data); + ZeitgeistLog *log = ZEITGEIST_LOG(source); + GError *error = NULL; + ZeitgeistResultSet *results = zeitgeist_log_find_events_finish(log, res, &error); + if (error) { + g_warning("Could not get recents from Zeitgeist: %s", error->message); + g_error_free(error); + return; + } + g_return_if_fail(results); + + guint nelems = zeitgeist_result_set_size(results); + g_return_if_fail(nelems <= NUM_RECENT_FILES); + + g_ptr_array_set_size(self->priv->menu_recent, nelems); + + guint i = 0; + + while (zeitgeist_result_set_has_next(results)) { + ZeitgeistEvent *event = zeitgeist_result_set_next_value(results); + g_warn_if_fail(event); + g_warn_if_fail(zeitgeist_event_num_subjects(event) == 1); + ZeitgeistSubject *subject = zeitgeist_event_get_subject(event, 0); + g_warn_if_fail(subject); + GFile *file = g_file_new_for_uri(zeitgeist_subject_get_uri(subject)); + GtkImageMenuItem *menu_item = self->priv->menu_recent->pdata[i]; + if (!menu_item) { + menu_item = self->priv->menu_recent->pdata[i] = gtk_image_menu_item_new_with_label(zeitgeist_subject_get_text(subject)); + gtk_image_menu_item_set_image(menu_item, gtk_image_new()); + gtk_image_menu_item_set_always_show_image(menu_item, TRUE); + gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(menu_item)); + gtk_widget_show(GTK_WIDGET(menu_item)); + g_signal_connect_swapped(menu_item, "activate", + G_CALLBACK(handle_recent_activate), self); + } else { + gtk_menu_item_set_label(GTK_MENU_ITEM(menu_item), zeitgeist_subject_get_text(subject)); + gtk_image_clear(GTK_IMAGE(gtk_image_menu_item_get_image(menu_item))); + } + + // Takes ownership of "file" + g_object_set_qdata_full(G_OBJECT(menu_item), mdock_item_menu_file_quark(), + file, (GDestroyNotify)g_object_unref); + + g_file_query_info_async(file, G_FILE_ATTRIBUTE_STANDARD_ICON, G_FILE_QUERY_INFO_NONE, + G_PRIORITY_LOW, self->priv->recent_fetch, + recents_icon_ready, menu_item); + + g_object_unref(event); + g_object_unref(subject); + + i++; + } + + g_object_unref(results); + + g_ptr_array_set_size(self->priv->menu_recent, i); + + gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_sep1), i > 0); +} + +static void refresh_recent_menu(MDockItemMenu *self) +{ + ZeitgeistLog *log = zeitgeist_log_get_default(); + g_return_if_fail(log); + + if (self->priv->recent_fetch) { + g_cancellable_cancel(self->priv->recent_fetch); + g_clear_object(&self->priv->recent_fetch); + } + + self->priv->recent_fetch = g_cancellable_new(); + + GDesktopAppInfo *appinfo = mdock_item_get_desktop_app_info(self->item); + if (!appinfo) { + clear_recent_menu(self); + return; + } + + ZeitgeistTimeRange *range = zeitgeist_time_range_new_anytime(); + + GPtrArray *templs = g_ptr_array_new_full(1, (GDestroyNotify)g_object_unref); + ZeitgeistEvent *templ = zeitgeist_event_new(); + zeitgeist_event_set_actor_from_app_info(templ, G_APP_INFO(appinfo)); + g_ptr_array_add(templs, templ); + + zeitgeist_log_find_events(log, range, templs, ZEITGEIST_STORAGE_STATE_ANY, + NUM_RECENT_FILES, ZEITGEIST_RESULT_TYPE_MOST_RECENT_SUBJECTS, + NULL, recents_result_ready, self); + + g_object_unref(range); + g_ptr_array_unref(templs); +} +#endif + static void handle_item_pinned(MDockItemMenu *self, GParamSpec *spec, MDockItem *item) { const gboolean pinned = mdock_item_get_pinned(item); @@ -56,23 +203,9 @@ static void handle_item_desktop_app_info(MDockItemMenu *self, GParamSpec *spec, gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_launch), appinfo != NULL); if (!gtk_image_menu_item_get_image(self->priv->menu_launch) && appinfo) { - gint width, height; - if (gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height)) { - GtkIconTheme *theme = gtk_icon_theme_get_default(); - gint icon_size = MAX(width, height); - GIcon *icon = g_app_info_get_icon(G_APP_INFO(appinfo)); - GtkIconInfo *info = gtk_icon_theme_lookup_by_gicon(theme, icon, icon_size, - GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_FORCE_SIZE); - if (info) { - GdkPixbuf *pixbuf = gtk_icon_info_load_icon(info, NULL); - if (pixbuf) { - GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); - gtk_image_menu_item_set_image(self->priv->menu_launch, image); - g_object_unref(pixbuf); - } - gtk_icon_info_free(info); - } - } + GIcon *icon = g_app_info_get_icon(G_APP_INFO(appinfo)); + GtkWidget *image = gtk_image_new_from_gicon(icon, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(self->priv->menu_launch, image); } } @@ -148,6 +281,10 @@ mdock_item_menu_constructed(GObject *object) handle_item_desktop_app_info(self, NULL, self->item); handle_item_pinned(self, NULL, self->item); + +#ifdef HAVE_ZEITGEIST + refresh_recent_menu(self); +#endif } @@ -155,13 +292,17 @@ static void mdock_item_menu_dispose(GObject *object) { MDockItemMenu *self = MDOCK_ITEM_MENU(object); + g_cancellable_cancel(self->priv->recent_fetch); g_clear_object(&self->item); + g_ptr_array_free(self->priv->menu_recent, TRUE); + g_clear_object(&self->priv->recent_fetch); G_OBJECT_CLASS (mdock_item_menu_parent_class)->dispose(object); } static void mdock_item_menu_finalize (GObject *object) { + MDockItemMenu *self = MDOCK_ITEM_MENU(object); G_OBJECT_CLASS (mdock_item_menu_parent_class)->finalize (object); } @@ -170,9 +311,6 @@ mdock_item_menu_init (MDockItemMenu *self) { self->priv = MDOCK_ITEM_MENU_GET_PRIVATE (self); - self->priv->menu_sep1 = GTK_SEPARATOR_MENU_ITEM(gtk_separator_menu_item_new()); - gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_sep1)); - self->priv->menu_close_all = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, NULL)); gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_close_all)); @@ -181,6 +319,11 @@ mdock_item_menu_init (MDockItemMenu *self) self->priv->menu_launch = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(_("_New instance"))); gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_launch)); + + self->priv->menu_sep1 = GTK_SEPARATOR_MENU_ITEM(gtk_separator_menu_item_new()); + gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_sep1)); + + self->priv->menu_recent = g_ptr_array_new_with_free_func((GDestroyNotify)gtk_widget_destroy); } static void |