summaryrefslogtreecommitdiff
path: root/libmdock/mdock-item-menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmdock/mdock-item-menu.c')
-rw-r--r--libmdock/mdock-item-menu.c185
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