22 #include <glib/gi18n.h>
24 #include <gdk-pixbuf/gdk-pixbuf.h>
25 #include <cairo-gobject.h>
36 #ifdef HAVE_LIBGNOME_DESKTOP
37 #define GNOME_DESKTOP_USE_UNSTABLE_API
38 #include <libgnome-desktop/gnome-desktop-thumbnail.h>
57 #ifdef HAVE_LIBGNOME_DESKTOP
58 GnomeDesktopThumbnailFactory *thumbnail_factory;
71 #define ICON_VIEW_SIZE 128
72 #define MAX_RECENT_VIEW_ITEMS 20
78 GtkTreeRowReference *
row;
81 guint needs_metadata : 1;
82 guint needs_thumbnail : 1;
94 g_object_unref (data->
job);
100 path = gtk_tree_row_reference_get_path (data->
row);
102 gtk_tree_model_get_iter (GTK_TREE_MODEL (data->
ev_recent_view->priv->model), &iter, path);
106 gtk_tree_path_free (path);
108 gtk_tree_row_reference_free (data->
row);
134 gtk_tree_model_foreach (GTK_TREE_MODEL (priv->
model),
138 gtk_list_store_clear (priv->
model);
149 g_object_unref (priv->
model);
160 #ifdef HAVE_LIBGNOME_DESKTOP
161 g_clear_object (&priv->thumbnail_factory);
164 G_OBJECT_CLASS (ev_recent_view_parent_class)->dispose (obj);
171 gboolean has_ev_a, has_ev_b;
172 const gchar *evince = g_get_application_name ();
174 has_ev_a = gtk_recent_info_has_application (a, evince);
175 has_ev_b = gtk_recent_info_has_application (b, evince);
177 if (has_ev_a && has_ev_b) {
178 time_t time_a, time_b;
180 time_a = gtk_recent_info_get_modified (a);
181 time_b = gtk_recent_info_get_modified (b);
183 return (time_b - time_a);
184 }
else if (has_ev_a) {
186 }
else if (has_ev_b) {
197 gboolean keyboard_tip,
204 GtkTreePath *path = NULL;
207 model = gtk_icon_view_get_model (GTK_ICON_VIEW (priv->
view));
208 if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (priv->
view),
209 &x, &y, keyboard_tip,
210 &model, &path, &iter))
213 gtk_tree_model_get (GTK_TREE_MODEL (priv->
model), &iter,
217 gtk_tooltip_set_text (tooltip, uri);
220 gtk_icon_view_set_tooltip_item (GTK_ICON_VIEW (priv->
view),
222 gtk_tree_path_free (path);
229 GdkEventButton *event,
236 if (event->type != GDK_BUTTON_RELEASE)
242 path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (priv->
view), event->x, event->y);
248 gtk_icon_view_item_activated (GTK_ICON_VIEW (priv->
view), path);
249 gtk_tree_path_free (path);
255 gtk_tree_path_free (path);
262 GdkEventButton *event,
269 gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (priv->
view), event->x, event->y);
283 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->
model), &iter, path))
286 gtk_tree_model_get (GTK_TREE_MODEL (priv->
model), &iter,
295 cairo_surface_t *thumbnail)
301 cairo_surface_t *surface;
311 "resource:///org/gnome/evince/shell/ui/thumbnail-frame.png",
314 path = gtk_tree_row_reference_get_path (data->
row);
316 gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->
model), &iter, path);
317 gtk_list_store_set (priv->
model, &iter,
320 gtk_tree_path_free (path);
323 cairo_surface_destroy (surface);
326 #ifdef HAVE_LIBGNOME_DESKTOP
328 ev_rencent_view_ensure_desktop_thumbnail_factory (
EvRecentView *ev_recent_view)
330 if (ev_recent_view->priv->thumbnail_factory)
333 ev_recent_view->priv->thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
337 save_thumbnail_in_cache_thread (GTask *task,
340 GCancellable *cancellable)
342 GdkPixbuf *thumbnail;
343 cairo_surface_t *surface;
346 thumbnail = gdk_pixbuf_get_from_surface (surface, 0, 0,
347 cairo_image_surface_get_width (surface),
348 cairo_image_surface_get_height (surface));
350 gnome_desktop_thumbnail_factory_save_thumbnail (ev_recent_view->priv->thumbnail_factory,
352 g_object_unref (thumbnail);
354 g_task_return_boolean (task,
TRUE);
358 save_thumbnail_in_cache_cb (
EvRecentView *ev_recent_view,
359 GAsyncResult *result,
369 #ifdef HAVE_LIBGNOME_DESKTOP
372 ev_rencent_view_ensure_desktop_thumbnail_factory (data->
ev_recent_view);
374 (GAsyncReadyCallback)save_thumbnail_in_cache_cb, data);
375 g_task_set_task_data (task, data, NULL);
376 g_task_run_in_thread (task, (GTaskThreadFunc)save_thumbnail_in_cache_thread);
377 g_object_unref (task);
387 if (g_cancellable_is_cancelled (data->
cancellable) ||
404 if (g_cancellable_is_cancelled (data->
cancellable) ||
410 g_clear_object (&data->
job);
413 gdouble width, height;
414 gint target_width, target_height;
417 if (height < width) {
428 g_signal_connect (data->
job,
"finished",
439 GFileInfo *file_info = g_file_info_new ();
441 path = gtk_tree_row_reference_get_path (data->
row);
443 gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->
model), &iter, path);
448 gtk_list_store_set (priv->
model, &iter,
452 g_file_info_set_attribute_string (file_info,
"metadata::evince::title", info->title);
454 g_file_info_set_attribute_string (file_info,
"metadata::evince::title",
"");
458 gtk_list_store_set (priv->
model, &iter,
462 g_file_info_set_attribute_string (file_info,
"metadata::evince::author", info->author);
464 g_file_info_set_attribute_string (file_info,
"metadata::evince::author",
"");
467 gtk_tree_path_free (path);
469 file = g_file_new_for_uri (data->
uri);
470 g_file_set_attributes_async (file, file_info, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
471 g_object_unref (file);
482 g_signal_connect (data->
job,
"finished",
488 #ifdef HAVE_LIBGNOME_DESKTOP
490 get_thumbnail_from_cache_thread (GTask *task,
493 GCancellable *cancellable)
498 GdkPixbuf *thumbnail;
499 cairo_surface_t *surface = NULL;
501 if (g_task_return_error_if_cancelled (task))
504 file = g_file_new_for_uri (data->
uri);
505 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE,
507 g_object_unref (file);
510 g_task_return_pointer (task, NULL, NULL);
514 data->
mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
515 g_object_unref (info);
517 path = gnome_desktop_thumbnail_factory_lookup (ev_recent_view->priv->thumbnail_factory,
520 g_task_return_pointer (task, NULL, NULL);
524 thumbnail = gdk_pixbuf_new_from_file (path, NULL);
529 gint target_width, target_height;
531 width = gdk_pixbuf_get_width (thumbnail);
532 height = gdk_pixbuf_get_height (thumbnail);
534 if (height < width) {
542 if (width < target_width || height < target_height) {
545 scaled = gdk_pixbuf_scale_simple (thumbnail,
549 g_object_unref (thumbnail);
551 }
else if (width != target_width || height != target_height) {
554 scaled = gdk_pixbuf_scale_simple (thumbnail,
558 g_object_unref (thumbnail);
563 g_object_unref (thumbnail);
566 g_task_return_pointer (task, surface, (GDestroyNotify)cairo_surface_destroy);
570 get_thumbnail_from_cache_cb (
EvRecentView *ev_recent_view,
571 GAsyncResult *result,
574 GTask *task = G_TASK (result);
575 cairo_surface_t *thumbnail;
577 if (g_cancellable_is_cancelled (data->
cancellable)) {
582 thumbnail = g_task_propagate_pointer (task, NULL);
585 cairo_surface_destroy (thumbnail);
598 #ifdef HAVE_LIBGNOME_DESKTOP
601 ev_rencent_view_ensure_desktop_thumbnail_factory (data->
ev_recent_view);
603 (GAsyncReadyCallback)get_thumbnail_from_cache_cb, data);
604 g_task_set_task_data (task, data, NULL);
605 g_task_run_in_thread (task, (GTaskThreadFunc)get_thumbnail_from_cache_thread);
606 g_object_unref (task);
630 GAsyncResult *result,
634 const char *title = NULL;
635 const char *author = NULL;
639 if (g_cancellable_is_cancelled (data->
cancellable)) {
644 info = g_file_query_info_finish (file, result, NULL);
650 if (!g_file_info_has_namespace (info,
"metadata")) {
652 g_object_unref (info);
657 attrs = g_file_info_list_attributes (info,
"metadata");
658 for (i = 0; attrs[i]; i++) {
659 if (g_str_equal (attrs[i],
"metadata::evince::title")) {
660 title = g_file_info_get_attribute_string (info, attrs[i]);
661 }
else if (g_str_equal (attrs[i],
"metadata::evince::author")) {
662 author = g_file_info_get_attribute_string (info, attrs[i]);
670 if (title || author) {
675 path = gtk_tree_row_reference_get_path (data->
row);
679 gtk_tree_model_get_iter (GTK_TREE_MODEL (data->
ev_recent_view->priv->model), &iter, path);
681 if (title && title[0] !=
'\0') {
687 if (author && author[0] !=
'\0') {
693 gtk_tree_path_free (path);
697 g_object_unref (info);
712 data->
uri = g_strdup (uri);
713 data->
row = gtk_tree_row_reference_new (GTK_TREE_MODEL (ev_recent_view->priv->model), path);;
718 file = g_file_new_for_uri (uri);
719 g_file_query_info_async (file,
"metadata::*", G_FILE_QUERY_INFO_NONE,
723 g_object_unref (file);
733 const gchar *evince = g_get_application_name ();
739 gtk_list_store_clear (priv->
model);
741 for (l = items; l && l->data; l = g_list_next (l)) {
747 cairo_surface_t *thumbnail = NULL;
750 info = (GtkRecentInfo *) l->data;
752 if (!gtk_recent_info_has_application (info, evince))
755 if (gtk_recent_info_is_local (info) && !gtk_recent_info_exists (info))
758 uri = gtk_recent_info_get_uri (info);
762 g_object_unref (pixbuf);
765 gtk_list_store_append (priv->
model, &iter);
766 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->
model), &iter);
768 gtk_tree_path_free (path);
770 gtk_list_store_set (priv->
model, &iter,
778 if (thumbnail != NULL)
779 cairo_surface_destroy (thumbnail);
785 g_list_free_full (items, (GDestroyNotify)gtk_recent_info_unref);
793 GtkCellRenderer *renderer;
795 G_OBJECT_CLASS (ev_recent_view_parent_class)->constructed (
object);
797 priv->
view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (priv->
model));
799 gtk_icon_view_set_column_spacing (GTK_ICON_VIEW (priv->
view), 20);
800 gtk_icon_view_set_margin (GTK_ICON_VIEW (priv->
view), 16);
801 gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (priv->
view), GTK_SELECTION_NONE);
802 gtk_widget_set_hexpand (priv->
view,
TRUE);
803 gtk_widget_set_vexpand (priv->
view,
TRUE);
804 gtk_widget_set_has_tooltip (priv->
view,
TRUE);
806 renderer = gtk_cell_renderer_pixbuf_new ();
807 g_object_set (renderer,
"xalign", 0.5,
"yalign", 0.5, NULL);
809 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->
view), renderer,
FALSE);
810 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->
view), renderer,
814 g_object_set (renderer,
816 "alignment", PANGO_ALIGN_CENTER,
817 "wrap-mode", PANGO_WRAP_WORD_CHAR,
821 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->
view), renderer,
FALSE);
822 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->
view), renderer,
824 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->
view), renderer,
827 g_signal_connect (priv->
view,
"button-press-event",
830 g_signal_connect (priv->
view,
"button-release-event",
833 g_signal_connect (priv->
view,
"item-activated",
836 g_signal_connect (priv->
view,
"query-tooltip",
840 gtk_style_context_add_class (gtk_widget_get_style_context (priv->
view),
"content-view");
841 gtk_container_add (GTK_CONTAINER (ev_recent_view), priv->
view);
842 gtk_widget_show (priv->
view);
854 priv = ev_recent_view->priv;
860 CAIRO_GOBJECT_TYPE_SURFACE,
863 gtk_widget_set_hexpand (GTK_WIDGET (ev_recent_view),
TRUE);
864 gtk_widget_set_vexpand (GTK_WIDGET (ev_recent_view),
TRUE);
865 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ev_recent_view),
867 GTK_POLICY_AUTOMATIC);
878 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
884 g_signal_new (
"item-activated",
888 g_cclosure_marshal_generic,