summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis Pohlmann <jannis@xfce.org>2010-10-05 16:21:35 +0200
committerJannis Pohlmann <jannis@xfce.org>2010-10-05 16:21:35 +0200
commite3e7a6dc0a963a26014839d5c3bd90b262c4e88f (patch)
tree597c3cad4e305da3145100a97ef78f9dd946e393
parent4ffb5b3c2ac77c8ff44f6aeee191b37cf7cecfbe (diff)
downloadthunar-jannis/lazy-icon-renderer.tar.gz
Implement ThunarIconRenderer as an ExoLazyCellRenderer.jannis/lazy-icon-renderer
This is inspired by bug #1266 and still has a few issues as sometimes, the resize shows now effect until the user starts scrolling or resizing the window.
-rw-r--r--configure.in.in8
-rw-r--r--thunar/Makefile.am1
-rw-r--r--thunar/thunar-icon-factory.c28
-rw-r--r--thunar/thunar-icon-renderer.c376
4 files changed, 377 insertions, 36 deletions
diff --git a/configure.in.in b/configure.in.in
index 8b1f2aa4..9cc5aaeb 100644
--- a/configure.in.in
+++ b/configure.in.in
@@ -117,10 +117,10 @@ AC_SYS_LARGEFILE()
dnl **********************************
dnl *** Check for standard headers ***
dnl **********************************
-AC_CHECK_HEADERS([ctype.h errno.h fcntl.h grp.h limits.h locale.h memory.h \
- paths.h pwd.h sched.h signal.h stdarg.h stdlib.h string.h \
- sys/mman.h sys/param.h sys/stat.h sys/time.h sys/types.h \
- sys/uio.h sys/wait.h time.h])
+AC_CHECK_HEADERS([ctype.h errno.h fcntl.h grp.h limits.h locale.h math.h \
+ memory.h paths.h pwd.h sched.h signal.h stdarg.h stdlib.h \
+ string.h sys/mman.h sys/param.h sys/stat.h sys/time.h \
+ sys/types.h sys/uio.h sys/wait.h time.h])
dnl ************************************
dnl *** Check for standard functions ***
diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 70d6df57..d32223ce 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -237,6 +237,7 @@ Thunar_CFLAGS = \
Thunar_LDFLAGS = \
-no-undefined \
+ -lm \
$(LIBSM_LDFLAGS) \
$(PLATFORM_LDFLAGS)
diff --git a/thunar/thunar-icon-factory.c b/thunar/thunar-icon-factory.c
index bf7fc9e2..8af6de51 100644
--- a/thunar/thunar-icon-factory.c
+++ b/thunar/thunar-icon-factory.c
@@ -26,6 +26,9 @@
#include <config.h>
#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
@@ -454,11 +457,10 @@ thunar_icon_factory_load_from_file (ThunarIconFactory *factory,
needs_frame = (strstr (path, G_DIR_SEPARATOR_S ".thumbnails" G_DIR_SEPARATOR_S) != NULL)
&& (size >= 36) && thumbnail_needs_frame (pixbuf, width, height);
- /* be sure to make framed thumbnails fit into the size */
if (G_LIKELY (needs_frame))
{
- max_width = size - (3 + 6);
- max_height = size - (3 + 6);
+ max_width = MAX (size - (3 + 6), 1);
+ max_height = MAX (size - (3 + 6), 1);
}
else
{
@@ -466,11 +468,27 @@ thunar_icon_factory_load_from_file (ThunarIconFactory *factory,
max_height = size;
}
- /* scale down the icon (if required) */
+ /* perform the scaling first (if required) */
if (G_LIKELY (width > max_width || height > max_height))
{
+ /* determine which axis needs to be scaled down more */
+ gdouble wratio = (gdouble) width / (gdouble) max_width;
+ gdouble hratio = (gdouble) height / (gdouble) max_height;
+
+ /* adjust along both axes */
+ if (hratio > wratio)
+ {
+ width = rint (width / hratio);
+ height = max_height;
+ }
+ else
+ {
+ height = rint (height / wratio);
+ width = max_width;
+ }
+
/* scale down to the required size */
- tmp = exo_gdk_pixbuf_scale_down (pixbuf, TRUE, max_height, max_height);
+ tmp = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = tmp;
}
diff --git a/thunar/thunar-icon-renderer.c b/thunar/thunar-icon-renderer.c
index d3fed33e..d4b91975 100644
--- a/thunar/thunar-icon-renderer.c
+++ b/thunar/thunar-icon-renderer.c
@@ -41,33 +41,50 @@ enum
-static void thunar_icon_renderer_finalize (GObject *object);
-static void thunar_icon_renderer_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void thunar_icon_renderer_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void thunar_icon_renderer_get_size (GtkCellRenderer *renderer,
- GtkWidget *widget,
- GdkRectangle *rectangle,
- gint *x_offset,
- gint *y_offset,
- gint *width,
- gint *height);
-static void thunar_icon_renderer_render (GtkCellRenderer *renderer,
- GdkWindow *window,
- GtkWidget *widget,
- GdkRectangle *background_area,
- GdkRectangle *cell_area,
- GdkRectangle *expose_area,
- GtkCellRendererState flags);
-
-
-
-G_DEFINE_TYPE (ThunarIconRenderer, thunar_icon_renderer, GTK_TYPE_CELL_RENDERER)
+static void thunar_icon_renderer_lazy_cell_renderer_init (ExoLazyCellRendererIface *iface);
+static void thunar_icon_renderer_finalize (GObject *object);
+static void thunar_icon_renderer_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void thunar_icon_renderer_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void thunar_icon_renderer_get_size (GtkCellRenderer *renderer,
+ GtkWidget *widget,
+ GdkRectangle *rectangle,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height);
+static void thunar_icon_renderer_render (GtkCellRenderer *renderer,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags);
+static gboolean thunar_icon_renderer_render_and_resize (ExoLazyCellRenderer *lazy_cell_renderer,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height);
+
+
+
+G_DEFINE_TYPE_EXTENDED (ThunarIconRenderer,
+ thunar_icon_renderer,
+ GTK_TYPE_CELL_RENDERER,
+ 0,
+ G_IMPLEMENT_INTERFACE (EXO_TYPE_LAZY_CELL_RENDERER,
+ thunar_icon_renderer_lazy_cell_renderer_init));
@@ -167,6 +184,14 @@ thunar_icon_renderer_init (ThunarIconRenderer *icon_renderer)
static void
+thunar_icon_renderer_lazy_cell_renderer_init (ExoLazyCellRendererIface *iface)
+{
+ iface->render_and_resize = thunar_icon_renderer_render_and_resize;
+}
+
+
+
+static void
thunar_icon_renderer_finalize (GObject *object)
{
ThunarIconRenderer *icon_renderer = THUNAR_ICON_RENDERER (object);
@@ -307,6 +332,7 @@ thunar_icon_renderer_get_size (GtkCellRenderer *renderer,
+#if 0
static void
thunar_icon_renderer_render (GtkCellRenderer *renderer,
GdkWindow *window,
@@ -541,6 +567,302 @@ thunar_icon_renderer_render (GtkCellRenderer *renderer,
/* release our reference on the icon factory */
g_object_unref (G_OBJECT (icon_factory));
}
+#endif
+
+
+
+static void
+thunar_icon_renderer_render (GtkCellRenderer *renderer,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+{
+ thunar_icon_renderer_render_and_resize (EXO_LAZY_CELL_RENDERER (renderer), window,
+ widget, background_area, cell_area,
+ expose_area, flags, NULL, NULL, NULL, NULL);
+}
+
+
+
+
+static gboolean
+thunar_icon_renderer_render_and_resize (ExoLazyCellRenderer *lazy_cell_renderer,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+ ThunarClipboardManager *clipboard;
+ ThunarFileIconState icon_state;
+ ThunarIconRenderer *icon_renderer = THUNAR_ICON_RENDERER (lazy_cell_renderer);
+ ThunarIconFactory *icon_factory;
+ GtkIconSource *icon_source;
+ GtkIconTheme *icon_theme;
+ GdkRectangle emblem_area;
+ GdkRectangle icon_area;
+ GdkRectangle draw_area;
+ GtkStateType state;
+ GdkPixbuf *emblem;
+ GdkPixbuf *icon;
+ GdkPixbuf *temp;
+ GList *emblems;
+ GList *lp;
+ gint max_emblems;
+ gint position;
+
+ if (G_UNLIKELY (icon_renderer->file == NULL))
+ return FALSE;
+
+ /* determine the icon state */
+ icon_state = (icon_renderer->drop_file != icon_renderer->file)
+ ? GTK_CELL_RENDERER (lazy_cell_renderer)->is_expanded
+ ? THUNAR_FILE_ICON_STATE_OPEN
+ : THUNAR_FILE_ICON_STATE_DEFAULT
+ : THUNAR_FILE_ICON_STATE_DROP;
+
+ /* load the main icon */
+ icon_theme = gtk_icon_theme_get_for_screen (gdk_drawable_get_screen (window));
+ icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
+ icon = thunar_icon_factory_load_file_icon (icon_factory, icon_renderer->file, icon_state, icon_renderer->size);
+ if (G_UNLIKELY (icon == NULL))
+ {
+ g_object_unref (G_OBJECT (icon_factory));
+ return FALSE;
+ }
+
+ /* pre-light the item if we're dragging about it */
+ if (G_UNLIKELY (icon_state == THUNAR_FILE_ICON_STATE_DROP))
+ flags |= GTK_CELL_RENDERER_PRELIT;
+
+ /* determine the real icon size */
+ icon_area.width = gdk_pixbuf_get_width (icon);
+ icon_area.height = gdk_pixbuf_get_height (icon);
+
+ /* scale down the icon on-demand */
+#if 0
+#if 1
+ if (G_UNLIKELY (icon_area.width > cell_area->width || icon_area.height > cell_area->height))
+ {
+ /* scale down to fit */
+ temp = exo_gdk_pixbuf_scale_down (icon, TRUE, cell_area->width, cell_area->height);
+ g_object_unref (G_OBJECT (icon));
+ icon = temp;
+
+ /* determine the icon dimensions again */
+ icon_area.width = gdk_pixbuf_get_width (icon);
+ icon_area.height = gdk_pixbuf_get_height (icon);
+ }
+#else
+ if (G_UNLIKELY (icon_area.width > cell_area->width - 2 * GTK_CELL_RENDERER (icon_renderer)->xpad
+ || icon_area.height > cell_area->height - 2 * GTK_CELL_RENDERER (icon_renderer)->ypad))
+ {
+ if ((gdouble) icon_area.height * (cell_area->width - 2 * GTK_CELL_RENDERER (icon_renderer)->xpad)
+ > (gdouble) icon_area.width * (cell_area->height - 2 * GTK_CELL_RENDERER (icon_renderer)->ypad))
+ {
+ icon_area.width = 0.5 + (gdouble) icon_area.width * (gdouble) (cell_area->height - 2 * GTK_CELL_RENDERER (icon_renderer)->ypad) / (gdouble) icon_area.height;
+ icon_area.height = cell_area->height - 2 * GTK_CELL_RENDERER (icon_renderer)->ypad;
+ }
+ else
+ {
+ icon_area.height = 0.5 + (gdouble) icon_area.height * (gdouble) (cell_area->width - 2 * GTK_CELL_RENDERER (icon_renderer)->ypad) / (gdouble) icon_area.width;
+ icon_area.width = cell_area->width - 2 * GTK_CELL_RENDERER (icon_renderer)->xpad;
+ }
+
+ temp = gdk_pixbuf_scale_simple (icon, icon_area.width, icon_area.height, GDK_INTERP_BILINEAR);
+ g_object_unref (G_OBJECT (icon));
+ icon = temp;
+ }
+#endif
+#endif
+
+ icon_area.x = cell_area->x + (cell_area->width - icon_area.width) / 2;
+ icon_area.y = cell_area->y + (cell_area->height - icon_area.height) / 2;
+
+ /* tell the view about the new dimensions */
+ if (G_LIKELY (x_offset != NULL))
+ *x_offset = icon_area.x - cell_area->x;
+ if (G_LIKELY (y_offset != NULL))
+ *y_offset = icon_area.y - cell_area->y;
+ if (G_LIKELY (width != NULL))
+ *width = icon_area.width + 2 * GTK_CELL_RENDERER (icon_renderer)->xpad;
+ if (G_LIKELY (height != NULL))
+ *height = icon_area.height + 2 * GTK_CELL_RENDERER (icon_renderer)->ypad;
+
+ /* check whether the icon is affected by the expose event */
+ if (gdk_rectangle_intersect (expose_area, &icon_area, &draw_area))
+ {
+ /* use a translucent icon to represent cutted and hidden files to the user */
+ clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (widget));
+ if (thunar_clipboard_manager_has_cutted_file (clipboard, icon_renderer->file))
+ {
+ /* 50% translucent for cutted files */
+ temp = exo_gdk_pixbuf_lucent (icon, 50);
+ g_object_unref (G_OBJECT (icon));
+ icon = temp;
+ }
+ else if (thunar_file_is_hidden (icon_renderer->file))
+ {
+ /* 75% translucent for hidden files */
+ temp = exo_gdk_pixbuf_lucent (icon, 75);
+ g_object_unref (G_OBJECT (icon));
+ icon = temp;
+ }
+ g_object_unref (G_OBJECT (clipboard));
+
+ /* colorize the icon if we should follow the selection state */
+ if ((flags & (GTK_CELL_RENDERER_SELECTED | GTK_CELL_RENDERER_PRELIT)) != 0 && icon_renderer->follow_state)
+ {
+ if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
+ {
+ state = GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE;
+ temp = exo_gdk_pixbuf_colorize (icon, &widget->style->base[state]);
+ g_object_unref (G_OBJECT (icon));
+ icon = temp;
+ }
+
+ if ((flags & GTK_CELL_RENDERER_PRELIT) != 0)
+ {
+ temp = exo_gdk_pixbuf_spotlight (icon);
+ g_object_unref (G_OBJECT (icon));
+ icon = temp;
+ }
+ }
+
+ /* check if we should render an insensitive icon */
+ if (G_UNLIKELY (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE
+ || !GTK_CELL_RENDERER (lazy_cell_renderer)->sensitive))
+ {
+ /* allocate an icon source */
+ icon_source = gtk_icon_source_new ();
+ gtk_icon_source_set_pixbuf (icon_source, icon);
+ gtk_icon_source_set_size_wildcarded (icon_source, FALSE);
+ gtk_icon_source_set_size (icon_source, GTK_ICON_SIZE_SMALL_TOOLBAR);
+
+ /* render the insensitive icon */
+ temp = gtk_style_render_icon (widget->style, icon_source, gtk_widget_get_direction (widget),
+ GTK_STATE_INSENSITIVE, -1, widget, "gtkcellrendererpixbuf");
+ g_object_unref (G_OBJECT (icon));
+ icon = temp;
+
+ /* release the icon source */
+ gtk_icon_source_free (icon_source);
+ }
+
+ /* render the invalid parts of the icon */
+ gdk_draw_pixbuf (window, widget->style->black_gc, icon,
+ draw_area.x - icon_area.x, draw_area.y - icon_area.y,
+ draw_area.x, draw_area.y, draw_area.width, draw_area.height,
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+ }
+
+ /* release the file's icon */
+ g_object_unref (G_OBJECT (icon));
+
+ /* check if we should render emblems as well */
+ if (G_LIKELY (icon_renderer->emblems))
+ {
+ /* display the primary emblem as well (if any) */
+ emblems = thunar_file_get_emblem_names (icon_renderer->file);
+ if (G_UNLIKELY (emblems != NULL))
+ {
+ /* render up to four emblems for sizes from 48 onwards, else up to 2 emblems */
+ max_emblems = (icon_renderer->size < 48) ? 2 : 4;
+
+ /* render the emblems */
+ for (lp = emblems, position = 0; lp != NULL && position < max_emblems; lp = lp->next)
+ {
+ /* check if we have the emblem in the icon theme */
+ emblem = thunar_icon_factory_load_icon (icon_factory, lp->data, icon_renderer->size, NULL, FALSE);
+ if (G_UNLIKELY (emblem == NULL))
+ continue;
+
+ /* determine the dimensions of the emblem */
+ emblem_area.width = gdk_pixbuf_get_width (emblem);
+ emblem_area.height = gdk_pixbuf_get_height (emblem);
+
+ /* shrink insane emblems */
+ if (G_UNLIKELY (MAX (emblem_area.width, emblem_area.height) > (gint) MIN ((2 * icon_renderer->size) / 3, 36)))
+ {
+ /* scale down the emblem */
+ temp = exo_gdk_pixbuf_scale_ratio (emblem, MIN ((2 * icon_renderer->size) / 3, 36));
+ g_object_unref (G_OBJECT (emblem));
+ emblem = temp;
+
+ /* determine the size again */
+ emblem_area.width = gdk_pixbuf_get_width (emblem);
+ emblem_area.height = gdk_pixbuf_get_height (emblem);
+ }
+
+ /* determine a good position for the emblem, depending on the position index */
+ switch (position)
+ {
+ case 0: /* right/bottom */
+ emblem_area.x = MIN (icon_area.x + icon_area.width - emblem_area.width / 2,
+ cell_area->x + cell_area->width - emblem_area.width);
+ emblem_area.y = MIN (icon_area.y + icon_area.height - emblem_area.height / 2,
+ cell_area->y + cell_area->height -emblem_area.height);
+ break;
+
+ case 1: /* left/bottom */
+ emblem_area.x = MAX (icon_area.x - emblem_area.width / 2,
+ cell_area->x);
+ emblem_area.y = MIN (icon_area.y + icon_area.height - emblem_area.height / 2,
+ cell_area->y + cell_area->height -emblem_area.height);
+ break;
+
+ case 2: /* left/top */
+ emblem_area.x = MAX (icon_area.x - emblem_area.width / 2,
+ cell_area->x);
+ emblem_area.y = MAX (icon_area.y - emblem_area.height / 2,
+ cell_area->y);
+ break;
+
+ case 3: /* right/top */
+ emblem_area.x = MIN (icon_area.x + icon_area.width - emblem_area.width / 2,
+ cell_area->x + cell_area->width - emblem_area.width);
+ emblem_area.y = MAX (icon_area.y - emblem_area.height / 2,
+ cell_area->y);
+ break;
+
+ default:
+ _thunar_assert_not_reached ();
+ }
+
+ /* render the emblem */
+ if (gdk_rectangle_intersect (expose_area, &emblem_area, &draw_area))
+ {
+ gdk_draw_pixbuf (window, widget->style->black_gc, emblem,
+ draw_area.x - emblem_area.x, draw_area.y - emblem_area.y,
+ draw_area.x, draw_area.y, draw_area.width, draw_area.height,
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+ }
+
+ /* release the emblem */
+ g_object_unref (G_OBJECT (emblem));
+
+ /* advance the position index */
+ ++position;
+ }
+
+ /* release the emblem name list */
+ g_list_free (emblems);
+ }
+ }
+
+ /* release our reference on the icon factory */
+ g_object_unref (G_OBJECT (icon_factory));
+
+ return TRUE;
+}