summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2015-01-25 01:12:13 +0100
committerJavier <dev.git@javispedro.com>2015-01-25 01:12:13 +0100
commit8251c0a4623e281fe25e420820f57b4c727a5bd2 (patch)
treec38ee196754c6b62887400826a65c0c60e5ae779
parentfe69cfd1ad1e98508be79b85a34a7f0c04190c91 (diff)
downloadmdock-8251c0a4623e281fe25e420820f57b4c727a5bd2.tar.gz
mdock-8251c0a4623e281fe25e420820f57b4c727a5bd2.zip
add recent items to context menu
-rw-r--r--configure.ac20
-rw-r--r--libmdock/Makefile.am18
-rw-r--r--libmdock/mdock-enums.c.template38
-rw-r--r--libmdock/mdock-enums.h.template24
-rw-r--r--libmdock/mdock-item-menu.c185
-rw-r--r--libmdock/mdock-item-window-selector.c6
-rw-r--r--libmdock/mdock-item.c20
-rw-r--r--libmdock/mdock-item.h2
-rw-r--r--libmdock/mdock-widget.c11
9 files changed, 223 insertions, 101 deletions
diff --git a/configure.ac b/configure.ac
index 5e64854..5a205be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,6 +14,11 @@ AC_ARG_ENABLE([mate-applet],
[],
[enable_mate_applet=check])
+AC_ARG_WITH([zeitgeist],
+ [AS_HELP_STRING([--with-zeitgeist], [use libzeitgeist to populate recent items menu @<:@default=check@:>@])],
+ [],
+ [with_zeitgeist=check])
+
# Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
@@ -31,7 +36,7 @@ PKG_CHECK_MODULES([GTOP], [libgtop-2.0])
AS_IF([test "x$enable_mate_applet" != xno],
[PKG_CHECK_MODULES([MATEPANELAPPLET], [libmatepanelapplet-4.0],
[
- AC_DEFINE([HAVE_MATEPANELAPPLET], [1], [Define if you have libmatepanelapplet])
+ AC_DEFINE([HAVE_MATEPANELAPPLET], [1], [Define to 1 if you have libmatepanelapplet])
enable_mate_applet=yes
],
[if test "x$enable_mate_applet" = xyes; then
@@ -40,6 +45,19 @@ AS_IF([test "x$enable_mate_applet" != xno],
)]
)
+AS_IF([test "x$with_zeitgeist" != xno],
+ [PKG_CHECK_MODULES([ZEITGEIST], [zeitgeist-2.0],
+ [
+ AC_DEFINE([HAVE_ZEITGEIST], [1], [Define to 1 if you have libzeitgeist])
+ with_zeitgeist=yes
+ ],
+ [if test "x$with_zeitgeist" = xyes; then
+ AC_MSG_FAILURE([--with-zeitgeist was given, but test for zeitgeist-2.0 failed])
+ fi]
+ )]
+)
+
+
AM_CONDITIONAL([WANT_MATE_APPLET], [test x$enable_mate_applet = xyes])
# Output files
diff --git a/libmdock/Makefile.am b/libmdock/Makefile.am
index 3abcc9d..25c0fff 100644
--- a/libmdock/Makefile.am
+++ b/libmdock/Makefile.am
@@ -1,20 +1,10 @@
lib_LTLIBRARIES = libmdock.la
-libmdock_la_SOURCES = mdock-widget.h mdock-widget.c mdock-enums.h mdock-enums.c mdock-item.h mdock-item.c mdock-item-menu.c mdock-item-menu.h mdock-item-window-selector.c mdock-item-window-selector.h mdock-window.h mdock-window.c matcher.h matcher.c app-id.h app-id.c thumbnailer.h thumbnailer.c
-libmdock_la_CPPFLAGS = $(GTK_CFLAGS) $(GIO_CFLAGS) $(WNCK_CFLAGS) $(GTOP_CFLAGS) -D_GNU_SOURCE -DG_LOG_DOMAIN=\"libmdock\"
-libmdock_la_LIBADD = $(GTK_LIBS) $(GIO_LIBS) $(WNCK_LIBS) $(GTOP_LIBS)
+libmdock_la_SOURCES = mdock-widget.h mdock-widget.c mdock-item.h mdock-item.c mdock-item-menu.c mdock-item-menu.h mdock-item-window-selector.c mdock-item-window-selector.h mdock-window.h mdock-window.c matcher.h matcher.c app-id.h app-id.c thumbnailer.h thumbnailer.c
+libmdock_la_CPPFLAGS = $(GTK_CFLAGS) $(GIO_CFLAGS) $(WNCK_CFLAGS) $(GTOP_CFLAGS) $(ZEITGEIST_CFLAGS) -D_GNU_SOURCE -DG_LOG_DOMAIN=\"libmdock\"
+libmdock_la_LIBADD = $(GTK_LIBS) $(GIO_LIBS) $(WNCK_LIBS) $(GTOP_LIBS) $(ZEITGEIST_LIBS)
gsettings_SCHEMAS = com.javispedro.mdock.widget.gschema.xml
-include_HEADERS = mdock-widget.h mdock-item.h
-CLEANFILES = mdock-enums.c mdock-enums.h
-
-EXTRA_DIST = mdock-enums.h.template mdock-enums.c.template
-BUILT_SOURCES = mdock-enums.h mdock-enums.c
-
-mdock-enums.c: mdock-enums.c.template $(include_HEADERS)
- glib-mkenums --template $< $(include_HEADERS) > $@
-
-mdock-enums.h: mdock-enums.h.template $(include_HEADERS)
- glib-mkenums --template $< $(include_HEADERS) > $@
+include_HEADERS = mdock-widget.h
@GSETTINGS_RULES@
diff --git a/libmdock/mdock-enums.c.template b/libmdock/mdock-enums.c.template
deleted file mode 100644
index 551a860..0000000
--- a/libmdock/mdock-enums.c.template
+++ /dev/null
@@ -1,38 +0,0 @@
-/*** BEGIN file-header ***/
-#include "mdock-enums.h"
-#include "mdock-widget.h"
-#include "mdock-item.h"
-
-/*** END file-header ***/
-
-/*** BEGIN file-production ***/
-/* enumerations from "@filename@" */
-/*** END file-production ***/
-
-/*** BEGIN value-header ***/
-GType
-@enum_name@_get_type (void)
-{
- static volatile gsize g_define_type_id__volatile = 0;
-
- if (g_once_init_enter (&g_define_type_id__volatile))
- {
- static const G@Type@Value values[] = {
-/*** END value-header ***/
-
-/*** BEGIN value-production ***/
- { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
-/*** END value-production ***/
-
-/*** BEGIN value-tail ***/
- { 0, NULL, NULL }
- };
- GType g_define_type_id =
- g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
- g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
- }
-
- return g_define_type_id__volatile;
-}
-
-/*** END value-tail ***/
diff --git a/libmdock/mdock-enums.h.template b/libmdock/mdock-enums.h.template
deleted file mode 100644
index d669580..0000000
--- a/libmdock/mdock-enums.h.template
+++ /dev/null
@@ -1,24 +0,0 @@
-/*** BEGIN file-header ***/
-#ifndef _MDOCK_ENUMS_H_
-#define _MDOCK_ENUMS_H_
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-/*** END file-header ***/
-
-/*** BEGIN file-production ***/
-
-/* enumerations from "@filename@" */
-/*** END file-production ***/
-
-/*** BEGIN value-header ***/
-GLIB_AVAILABLE_IN_ALL GType @enum_name@_get_type (void) G_GNUC_CONST;
-#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
-/*** END value-header ***/
-
-/*** BEGIN file-tail ***/
-G_END_DECLS
-
-#endif /* _MDOCK_ENUMS_H_ */
-/*** END file-tail ***/
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
diff --git a/libmdock/mdock-item-window-selector.c b/libmdock/mdock-item-window-selector.c
index ea5ceb8..2885a76 100644
--- a/libmdock/mdock-item-window-selector.c
+++ b/libmdock/mdock-item-window-selector.c
@@ -64,6 +64,8 @@ static GSequenceIter * find_window(MDockItemWindowSelector *self, WnckWindow *wi
static gboolean handle_window_button_release(MDockItemWindowSelector *self, GdkEventButton *event, MDockWindow *window)
{
+ g_debug("window item button release");
+
switch (event->button) {
case 1:
wnck_window_activate_transient(window->window, event->time);
@@ -201,6 +203,10 @@ void mdock_item_window_selector_remove_window(MDockItemWindowSelector *self, Wnc
if (g_sequence_get_length(self->priv->windows) == 0) {
gtk_widget_show(GTK_WIDGET(self->priv->app_label));
}
+
+ GtkRequisition requisition;
+ gtk_widget_size_request(GTK_WIDGET(self), &requisition);
+ gtk_window_resize(GTK_WINDOW(self), requisition.width, requisition.height);
}
void mdock_item_window_selector_set_active_window(MDockItemWindowSelector *self, WnckWindow *window)
diff --git a/libmdock/mdock-item.c b/libmdock/mdock-item.c
index 67f581f..67d3638 100644
--- a/libmdock/mdock-item.c
+++ b/libmdock/mdock-item.c
@@ -17,7 +17,6 @@
* along with MDock. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "mdock-enums.h"
#include "mdock-item.h"
#define MDOCK_ITEM_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_ITEM, MDockItemPrivate))
@@ -293,12 +292,13 @@ void mdock_item_set_desktop_app_info(MDockItem *self, GDesktopAppInfo *app_info)
g_object_set(self, "desktop-app-info", app_info, NULL);
}
-void mdock_item_launch(MDockItem *self)
+void mdock_item_launch_files(MDockItem *self, GList *files)
{
g_return_if_fail(self->priv->appinfo);
GError *error = NULL;
g_debug("Launching '%s'", g_app_info_get_commandline(G_APP_INFO(self->priv->appinfo)));
- if (!g_app_info_launch(G_APP_INFO(self->priv->appinfo), NULL, NULL, &error)) {
+
+ if (!g_app_info_launch(G_APP_INFO(self->priv->appinfo), files, NULL, &error)) {
GtkWidget *msg;
g_warning("Cannot launch '%s': %s",
@@ -319,6 +319,20 @@ void mdock_item_launch(MDockItem *self)
gtk_widget_show_all(msg);
g_error_free(error);
}
+
+
+}
+
+void mdock_item_launch_file(MDockItem *self, GFile *file)
+{
+ GList *files = g_list_append(NULL, file);
+ mdock_item_launch_files(self, files);
+ g_list_free(files);
+}
+
+void mdock_item_launch(MDockItem *self)
+{
+ mdock_item_launch_files(self, NULL);
}
const gchar *mdock_item_get_display_name(MDockItem *self)
diff --git a/libmdock/mdock-item.h b/libmdock/mdock-item.h
index 0048a8d..7379687 100644
--- a/libmdock/mdock-item.h
+++ b/libmdock/mdock-item.h
@@ -58,6 +58,8 @@ void mdock_item_toggle_pinned(MDockItem *self);
GDesktopAppInfo *mdock_item_get_desktop_app_info(MDockItem *self);
void mdock_item_set_desktop_app_info(MDockItem *self, GDesktopAppInfo *app_info);
+void mdock_item_launch_files(MDockItem *self, GList *files);
+void mdock_item_launch_file(MDockItem *self, GFile *file);
void mdock_item_launch(MDockItem *self);
const gchar *mdock_item_get_display_name(MDockItem *self);
diff --git a/libmdock/mdock-widget.c b/libmdock/mdock-widget.c
index 004a590..5b3daed 100644
--- a/libmdock/mdock-widget.c
+++ b/libmdock/mdock-widget.c
@@ -22,12 +22,17 @@
#define WNCK_I_KNOW_THIS_IS_UNSTABLE 1
#include <libwnck/libwnck.h>
+#include "../config.h"
#include "mdock-widget.h"
#include "mdock-item-window-selector.h"
#include "mdock-item-menu.h"
#include "mdock-item.h"
#include "matcher.h"
+#ifdef HAVE_ZEITGEIST
+#include <zeitgeist.h>
+#endif
+
#define POPUP_SHOW_TIMEOUT 200
#define POPUP_HIDE_TIMEOUT 500
@@ -769,6 +774,12 @@ static void mdock_widget_init(MDockWidget *self)
{
self->priv = MDOCK_WIDGET_GET_PRIVATE(self);
+#ifdef HAVE_ZEITGEIST
+ // Initialize zeitgeist now,
+ // since hilarity ensues if you try to do it on a Wnck callback...
+ zeitgeist_log_get_default();
+#endif
+
gtk_drag_dest_set(GTK_WIDGET(self), 0,
drag_types, G_N_ELEMENTS(drag_types),
GDK_ACTION_MOVE);