~jeremywootten/pantheon-files/fix-1658417-long-name-in-grid-view

« back to all changes in this revision

Viewing changes to src/marlin-icon-renderer.c

  • Committer: Jeremy Wootten
  • Date: 2017-02-04 13:48:29 UTC
  • mfrom: (2460.1.10 pantheon-files)
  • Revision ID: jeremy@elementaryos.org-20170204134829-2npkf7kaarm37vvs
Merge trunk to r2470

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3
 
 * Copyright (c) 2011  ammonkey <am.monkeyd@gmail.com>
4
 
 *
5
 
 * Originaly Written in gtk+: gtkcellrendererpixbuf.h
6
 
 *
7
 
 * This library is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU Library General Public
9
 
 * License as published by the Free Software Foundation; either
10
 
 * version 2 of the License, or (at your option) any later version.
11
 
 *
12
 
 * This library is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
 * Library General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU Library General Public
18
 
 * License along with this library; if not, write to the
19
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
 
 * Boston, MA 02111-1307, USA.
21
 
 */
22
 
 
23
 
#ifdef HAVE_CONFIG_H
24
 
#include <config.h>
25
 
#endif
26
 
 
27
 
#include <glib-object.h>
28
 
#include <gtk/gtk.h>
29
 
#include "marlin-icon-renderer.h"
30
 
#include "eel-gdk-pixbuf-extensions.h"
31
 
#include "marlin-vala.h"
32
 
 
33
 
 
34
 
#define EXO_PARAM_READWRITE (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
35
 
 
36
 
#define MARLIN_EMBLEM_SIZE 16
37
 
 
38
 
static void marlin_icon_renderer_get_property  (GObject                    *object,
39
 
                                                guint                       param_id,
40
 
                                                GValue                     *value,
41
 
                                                GParamSpec                 *pspec);
42
 
static void marlin_icon_renderer_set_property  (GObject                    *object,
43
 
                                                guint                       param_id,
44
 
                                                const GValue               *value,
45
 
                                                GParamSpec                 *pspec);
46
 
static void marlin_icon_renderer_finalize   (GObject                    *object);
47
 
static void marlin_icon_renderer_get_size   (GtkCellRenderer            *cell,
48
 
                                             GtkWidget                  *widget,
49
 
                                             const GdkRectangle         *rectangle,
50
 
                                             gint                       *x_offset,
51
 
                                             gint                       *y_offset,
52
 
                                             gint                       *width,
53
 
                                             gint                       *height);
54
 
static void marlin_icon_renderer_render     (GtkCellRenderer            *cell,
55
 
                                             cairo_t                    *cr,
56
 
                                             GtkWidget                  *widget,
57
 
                                             const GdkRectangle         *background_area,
58
 
                                             const GdkRectangle         *cell_area,
59
 
                                             GtkCellRendererState        flags);
60
 
static inline gboolean thumbnail_needs_frame   (const GdkPixbuf             *thumbnail,
61
 
                                                gint                        width,
62
 
                                                gint                        height);
63
 
 
64
 
 
65
 
enum {
66
 
    PROP_0,
67
 
    //PROP_PIXBUF,
68
 
    PROP_DROP_FILE,
69
 
    PROP_FILE,
70
 
    PROP_SIZE,
71
 
    PROP_ZOOM_LEVEL,
72
 
    PROP_EMBLEMS,
73
 
    PROP_FOLLOW_STATE,
74
 
    PROP_SELECTION_HELPERS,
75
 
};
76
 
 
77
 
 
78
 
struct _MarlinIconRendererPrivate
79
 
{
80
 
    GdkPixbuf *pixbuf;
81
 
    GOFFile   *file;
82
 
    GOFFile   *drop_file;
83
 
    gint      size;
84
 
    gint      helper_size;
85
 
    MarlinZoomLevel zoom_level;
86
 
    double scale;
87
 
 
88
 
    gboolean emblems;
89
 
    gboolean follow_state;
90
 
    gboolean selection_helpers;
91
 
 
92
 
    MarlinClipboardManager *clipboard;
93
 
};
94
 
 
95
 
 
96
 
G_DEFINE_TYPE (MarlinIconRenderer, marlin_icon_renderer, GTK_TYPE_CELL_RENDERER);
97
 
 
98
 
static gpointer _g_object_ref0 (gpointer self) {
99
 
    return self ? g_object_ref (self) : NULL;
100
 
}
101
 
 
102
 
static void
103
 
marlin_icon_renderer_init (MarlinIconRenderer *cellpixbuf)
104
 
{
105
 
    MarlinIconRendererPrivate *priv;
106
 
 
107
 
    cellpixbuf->priv = G_TYPE_INSTANCE_GET_PRIVATE (cellpixbuf,
108
 
                                                    MARLIN_TYPE_ICON_RENDERER,
109
 
                                                    MarlinIconRendererPrivate);
110
 
    priv = cellpixbuf->priv;
111
 
 
112
 
    priv->clipboard = marlin_clipboard_manager_get_for_display (gdk_display_get_default ());
113
 
    priv->emblems = TRUE;
114
 
}
115
 
 
116
 
static void
117
 
marlin_icon_renderer_class_init (MarlinIconRendererClass *class)
118
 
{
119
 
    GObjectClass *object_class = G_OBJECT_CLASS (class);
120
 
    GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
121
 
 
122
 
    object_class->finalize = marlin_icon_renderer_finalize;
123
 
 
124
 
    object_class->get_property = marlin_icon_renderer_get_property;
125
 
    object_class->set_property = marlin_icon_renderer_set_property;
126
 
 
127
 
    cell_class->get_size = marlin_icon_renderer_get_size;
128
 
    cell_class->render = marlin_icon_renderer_render;
129
 
 
130
 
    /*g_object_class_install_property (object_class,
131
 
      PROP_PIXBUF,
132
 
      g_param_spec_object ("pixbuf",
133
 
      "Pixbuf Object",
134
 
      "The pixbuf to render",
135
 
      GDK_TYPE_PIXBUF,
136
 
      EXO_PARAM_READWRITE));*/
137
 
 
138
 
    g_object_class_install_property (object_class,
139
 
                                     PROP_SIZE,
140
 
                                     g_param_spec_enum ("size", "size", "size",
141
 
                                                        MARLIN_TYPE_ICON_SIZE,
142
 
                                                        MARLIN_ICON_SIZE_SMALL,
143
 
                                                        G_PARAM_CONSTRUCT | EXO_PARAM_READWRITE));
144
 
 
145
 
    g_object_class_install_property (object_class,
146
 
                                     PROP_ZOOM_LEVEL,
147
 
                                     g_param_spec_enum ("zoom-level", "zoom-level", "zoom-level",
148
 
                                                        MARLIN_TYPE_ZOOM_LEVEL,
149
 
                                                        MARLIN_ZOOM_LEVEL_NORMAL,
150
 
                                                        EXO_PARAM_READWRITE));
151
 
 
152
 
    g_object_class_install_property (object_class,
153
 
                                     PROP_DROP_FILE,
154
 
                                     g_param_spec_object ("drop-file", "drop-file", "drop-file",
155
 
                                                          GOF_TYPE_FILE,
156
 
                                                          EXO_PARAM_READWRITE));
157
 
 
158
 
    g_object_class_install_property (object_class,
159
 
                                     PROP_FILE,
160
 
                                     g_param_spec_object ("file", "file", "file",
161
 
                                                          GOF_TYPE_FILE,
162
 
                                                          EXO_PARAM_READWRITE));
163
 
 
164
 
 
165
 
    /**
166
 
     * MarlinIconRenderer:emblems:
167
 
     *
168
 
     * Specifies whether to render emblems in addition to the file icons.
169
 
     */
170
 
    g_object_class_install_property (object_class,
171
 
                                     PROP_EMBLEMS,
172
 
                                     g_param_spec_boolean ("emblems",
173
 
                                                           "emblems",
174
 
                                                           "emblems",
175
 
                                                           TRUE,
176
 
                                                           EXO_PARAM_READWRITE));
177
 
 
178
 
    /**
179
 
     * MarlinIconRenderer:follow-state:
180
 
     *
181
 
     * Specifies whether the rendered pixbuf should be colorized
182
 
     * according to the #GtkCellRendererState.
183
 
     *
184
 
     * Since: 2.8
185
 
     */
186
 
    g_object_class_install_property (object_class,
187
 
                                     PROP_FOLLOW_STATE,
188
 
                                     g_param_spec_boolean ("follow-state",
189
 
                                                           "Follow State",
190
 
                                                           "Whether the rendered pixbuf should be "
191
 
                                                           "colorized according to the state",
192
 
                                                           FALSE,
193
 
                                                           EXO_PARAM_READWRITE));
194
 
 
195
 
    g_object_class_install_property (object_class,
196
 
                                     PROP_SELECTION_HELPERS,
197
 
                                     g_param_spec_boolean ("selection-helpers",
198
 
                                                           "Selection Helpers",
199
 
                                                           "Whether the selection helpers +/- aree rendered",
200
 
                                                           FALSE,
201
 
                                                           EXO_PARAM_READWRITE));
202
 
 
203
 
 
204
 
    g_type_class_add_private (object_class, sizeof (MarlinIconRendererPrivate));
205
 
}
206
 
 
207
 
static void
208
 
marlin_icon_renderer_finalize (GObject *object)
209
 
{
210
 
    MarlinIconRenderer *cellpixbuf = MARLIN_ICON_RENDERER (object);
211
 
    MarlinIconRendererPrivate *priv = cellpixbuf->priv;
212
 
 
213
 
    /*if (priv->pixbuf)
214
 
      g_object_unref (priv->pixbuf);*/
215
 
    if (priv->file)
216
 
        g_object_unref (priv->file);
217
 
    if (priv->drop_file)
218
 
        g_object_unref (priv->drop_file);
219
 
 
220
 
    g_object_unref (priv->clipboard);
221
 
 
222
 
    G_OBJECT_CLASS (marlin_icon_renderer_parent_class)->finalize (object);
223
 
}
224
 
 
225
 
static void
226
 
marlin_icon_renderer_get_property (GObject        *object,
227
 
                                   guint           param_id,
228
 
                                   GValue         *value,
229
 
                                   GParamSpec     *pspec)
230
 
{
231
 
    MarlinIconRenderer *cellpixbuf = MARLIN_ICON_RENDERER (object);
232
 
    MarlinIconRendererPrivate *priv = cellpixbuf->priv;
233
 
 
234
 
    switch (param_id)
235
 
    {
236
 
        /*case PROP_PIXBUF:
237
 
          g_value_set_object (value, priv->pixbuf);
238
 
          break;*/
239
 
    case PROP_DROP_FILE:
240
 
        g_value_set_object (value, priv->drop_file);
241
 
        break;
242
 
    case PROP_FILE:
243
 
        g_value_set_object (value, priv->file);
244
 
        break;
245
 
    case PROP_SIZE:
246
 
        g_value_set_enum (value, priv->size);
247
 
        break;
248
 
    case PROP_ZOOM_LEVEL:
249
 
        g_value_set_enum (value, priv->zoom_level);
250
 
        break;
251
 
    case PROP_EMBLEMS:
252
 
        g_value_set_boolean (value, priv->emblems);
253
 
        break;
254
 
    case PROP_FOLLOW_STATE:
255
 
        g_value_set_boolean (value, priv->follow_state);
256
 
        break;
257
 
    case PROP_SELECTION_HELPERS:
258
 
        g_value_set_boolean (value, priv->selection_helpers);
259
 
        break;
260
 
    default:
261
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
262
 
        break;
263
 
    }
264
 
}
265
 
 
266
 
static void
267
 
marlin_icon_renderer_set_property (GObject      *object,
268
 
                                   guint         param_id,
269
 
                                   const GValue *value,
270
 
                                   GParamSpec   *pspec)
271
 
{
272
 
    MarlinIconRenderer *cellpixbuf = MARLIN_ICON_RENDERER (object);
273
 
    MarlinIconRendererPrivate *priv = cellpixbuf->priv;
274
 
 
275
 
    switch (param_id)
276
 
    {
277
 
        /*case PROP_PIXBUF:
278
 
          if (priv->pixbuf)
279
 
          g_object_unref (priv->pixbuf);
280
 
          priv->pixbuf = (GdkPixbuf*) g_value_dup_object (value);
281
 
          break;*/
282
 
    case PROP_DROP_FILE:
283
 
        if (G_LIKELY (priv->drop_file != NULL))
284
 
            g_object_unref (G_OBJECT (priv->drop_file));
285
 
        priv->drop_file = (gpointer) g_value_dup_object (value);
286
 
        break;
287
 
    case PROP_FILE:
288
 
        //_g_object_unref0 (priv->pixbuf);
289
 
        _g_object_unref0 (priv->file);
290
 
        priv->file = (GOFFile*) g_value_dup_object (value);
291
 
        if (priv->file) {
292
 
            gof_file_update_icon (priv->file, priv->size);
293
 
            priv->pixbuf = priv->file->pix;
294
 
        }
295
 
        break;
296
 
    case PROP_SIZE:
297
 
        priv->size = g_value_get_enum (value);
298
 
        break;
299
 
    case PROP_ZOOM_LEVEL:
300
 
        priv->zoom_level = g_value_get_enum (value);
301
 
        priv->helper_size = (priv->zoom_level > MARLIN_ZOOM_LEVEL_NORMAL) ? 24 : 16;
302
 
        break;
303
 
    case PROP_EMBLEMS:
304
 
        priv->emblems = g_value_get_boolean (value);
305
 
        break;
306
 
    case PROP_FOLLOW_STATE:
307
 
        priv->follow_state = g_value_get_boolean (value);
308
 
        break;
309
 
    case PROP_SELECTION_HELPERS:
310
 
        priv->selection_helpers = g_value_get_boolean (value);
311
 
        break;
312
 
    default:
313
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
314
 
        break;
315
 
    }
316
 
}
317
 
 
318
 
/**
319
 
 * marlin_icon_renderer_new:
320
 
 *
321
 
 * Creates a new #MarlinIconRenderer. Adjust rendering
322
 
 * parameters using object properties. Object properties can be set
323
 
 * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you
324
 
 * can bind a property to a value in a #GtkTreeModel. For example, you
325
 
 * can bind the "pixbuf" property on the cell renderer to a pixbuf value
326
 
 * in the model, thus rendering a different image in each row of the
327
 
 * #GtkTreeView.
328
 
 *
329
 
 * Return value: the new cell renderer
330
 
**/
331
 
GtkCellRenderer *
332
 
marlin_icon_renderer_new (void)
333
 
{
334
 
    return g_object_new (MARLIN_TYPE_ICON_RENDERER, NULL);
335
 
}
336
 
 
337
 
static void
338
 
invalidate_size (gint *width, gint *height)
339
 
{
340
 
    if (width)
341
 
        *width = -1;
342
 
    if (height)
343
 
        *height = -1;
344
 
}
345
 
 
346
 
guint
347
 
marlin_icon_renderer_get_helper_size (MarlinIconRenderer *renderer) {
348
 
    return renderer->priv->helper_size;
349
 
}
350
 
 
351
 
static void
352
 
marlin_icon_renderer_get_size (GtkCellRenderer    *cell,
353
 
                               GtkWidget          *widget,
354
 
                               const GdkRectangle *cell_area,
355
 
                               gint               *x_offset,
356
 
                               gint               *y_offset,
357
 
                               gint               *width,
358
 
                               gint               *height)
359
 
{
360
 
    MarlinIconRenderer *cellpixbuf = (MarlinIconRenderer *) cell;
361
 
    MarlinIconRendererPrivate *priv = cellpixbuf->priv;
362
 
    gint pixbuf_width  = 0;
363
 
    gint pixbuf_height = 0;
364
 
    gint calc_width;
365
 
    gint calc_height;
366
 
    gint xpad, ypad;
367
 
 
368
 
    //g_return_if_fail (priv->pixbuf);
369
 
    if (!(priv->pixbuf && GDK_IS_PIXBUF (priv->pixbuf))) {
370
 
        invalidate_size (width, height);
371
 
        return;
372
 
    }
373
 
 
374
 
    if (priv->pixbuf)
375
 
    {
376
 
        pixbuf_width  = gdk_pixbuf_get_width (priv->pixbuf);
377
 
        pixbuf_height = gdk_pixbuf_get_height (priv->pixbuf);
378
 
    }
379
 
 
380
 
    gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
381
 
    calc_width  = (gint) xpad * 2 + pixbuf_width;
382
 
    calc_height = (gint) ypad * 2 + pixbuf_height;
383
 
 
384
 
    if (cell_area && pixbuf_width > 0 && pixbuf_height > 0)
385
 
    {
386
 
        gfloat xalign, yalign;
387
 
 
388
 
        gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
389
 
        if (x_offset)
390
 
        {
391
 
            *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
392
 
                          (1.0 - xalign) : xalign) *
393
 
                         (cell_area->width - calc_width));
394
 
            *x_offset = MAX (*x_offset, 0);
395
 
        }
396
 
        if (y_offset)
397
 
        {
398
 
            *y_offset = (yalign *
399
 
                         (cell_area->height - calc_height));
400
 
            *y_offset = MAX (*y_offset, 0);
401
 
        }
402
 
    }
403
 
    else
404
 
    {
405
 
        if (x_offset) *x_offset = 0;
406
 
        if (y_offset) *y_offset = 0;
407
 
    }
408
 
 
409
 
    /* Even if the last new pixbuf corresponding to the last requested size isn't generated
410
 
       yet, we can still determine its dimensions. This allow to asyncronously load the thumbnails
411
 
       pixbuf */
412
 
    int s = MAX (pixbuf_width, pixbuf_height);
413
 
    priv->scale = MIN (1, (double)priv->size / s);
414
 
 
415
 
    if (width)
416
 
        *width = calc_width * priv->scale;
417
 
 
418
 
    if (height)
419
 
        *height = calc_height * priv->scale;
420
 
 
421
 
}
422
 
 
423
 
static void
424
 
cairo_make_shadow_for_rect (cairo_t* cr,
425
 
                            gdouble x1, gdouble y1, gdouble w, gdouble h,
426
 
                            gdouble rad, gdouble r, gdouble g, gdouble b, gdouble size);
427
 
 
428
 
static void
429
 
marlin_icon_renderer_render (GtkCellRenderer      *cell,
430
 
                             cairo_t              *cr,
431
 
                             GtkWidget            *widget,
432
 
                             const GdkRectangle   *background_area,
433
 
                             const GdkRectangle   *cell_area,
434
 
                             GtkCellRendererState  flags)
435
 
 
436
 
{
437
 
    MarlinIconRenderer *cellpixbuf = (MarlinIconRenderer *) cell;
438
 
    MarlinIconRendererPrivate *priv = cellpixbuf->priv;
439
 
    GtkStyleContext *context;
440
 
    GdkPixbuf *pixbuf, *stated;
441
 
    GdkPixbuf *temp;
442
 
    GdkRectangle pix_rect;
443
 
    GdkRectangle emblem_area;
444
 
    GdkRectangle draw_rect;
445
 
    gint xpad, ypad;
446
 
    GtkStateFlags state;
447
 
    MarlinIconInfo *nicon;
448
 
 
449
 
    if (!(priv->file && priv->pixbuf))
450
 
      return;  /* return silently - this is not an error - could be rendering blank line (e.g. expanded empty subdirectory */
451
 
 
452
 
    g_return_if_fail (GDK_IS_PIXBUF (priv->pixbuf));
453
 
    g_return_if_fail (priv->size >= 1);
454
 
 
455
 
 
456
 
    marlin_icon_renderer_get_size (cell, widget, (GdkRectangle *) cell_area,
457
 
                                   &pix_rect.x,
458
 
                                   &pix_rect.y,
459
 
                                   &pix_rect.width,
460
 
                                   &pix_rect.height);
461
 
 
462
 
    gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
463
 
    pix_rect.x += cell_area->x + xpad;
464
 
    pix_rect.y += cell_area->y + ypad;
465
 
    pix_rect.width -= xpad * 2;
466
 
    pix_rect.height -= ypad * 2;
467
 
 
468
 
    if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect))
469
 
        return;
470
 
 
471
 
    pixbuf = g_object_ref (priv->pixbuf);
472
 
 
473
 
    //g_debug ("%s %s %u %u\n", G_STRFUNC, priv->file->uri, G_OBJECT (priv->file)->ref_count, G_OBJECT (priv->pixbuf)->ref_count);
474
 
 
475
 
    /* drop state */
476
 
    if (priv->file == priv->drop_file) {
477
 
        flags |= GTK_CELL_RENDERER_PRELIT;
478
 
        nicon = marlin_icon_info_lookup_from_name ("folder-drag-accept", priv->size);
479
 
        temp = marlin_icon_info_get_pixbuf_nodefault (nicon);
480
 
        g_object_unref (nicon);
481
 
        g_object_unref (pixbuf);
482
 
        pixbuf = temp;
483
 
    } else if (priv->file->is_directory) {
484
 
        if (priv->file->is_expanded) {
485
 
            nicon = marlin_icon_info_lookup_from_name ("folder-open", priv->size);
486
 
            temp = marlin_icon_info_get_pixbuf_nodefault (nicon);
487
 
            g_object_unref (nicon);
488
 
            g_object_unref (pixbuf);
489
 
            pixbuf = temp;
490
 
        }
491
 
    }
492
 
 
493
 
    /* clipboard */
494
 
    if (marlin_clipboard_manager_has_cutted_file (priv->clipboard, priv->file))
495
 
    {
496
 
        /* 50% translucent for cutted files */
497
 
        temp = eel_gdk_pixbuf_lucent (pixbuf, 50);
498
 
        g_object_unref (pixbuf);
499
 
        pixbuf = temp;
500
 
    }
501
 
    else if (priv->file->is_hidden)
502
 
    {
503
 
        /* 75% translucent for hidden files */
504
 
        temp = eel_gdk_pixbuf_lucent (pixbuf, 75);
505
 
        g_object_unref (pixbuf);
506
 
        pixbuf = temp;
507
 
    }
508
 
 
509
 
    context = gtk_widget_get_style_context (gtk_widget_get_parent (widget));
510
 
    gtk_style_context_save (context);
511
 
    state = GTK_STATE_FLAG_NORMAL;
512
 
 
513
 
    if (!gtk_widget_get_sensitive (widget) ||
514
 
        !gtk_cell_renderer_get_sensitive (cell))
515
 
        state |= GTK_STATE_FLAG_INSENSITIVE;
516
 
    else if (priv->follow_state &&
517
 
             (flags & (GTK_CELL_RENDERER_SELECTED |
518
 
                       GTK_CELL_RENDERER_PRELIT)) != 0) {
519
 
        if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
520
 
        {
521
 
            state = GTK_STATE_FLAG_SELECTED;
522
 
            /* compute the state with the state of the widget; this way we handle the backdrop */
523
 
            state |= gtk_widget_get_state_flags (widget);
524
 
            GdkRGBA color;
525
 
            gtk_style_context_get_background_color (context, state, &color);
526
 
            temp = eel_create_colorized_pixbuf (pixbuf, &color);
527
 
            g_object_unref (pixbuf);
528
 
            pixbuf = temp;
529
 
        }
530
 
 
531
 
        if ((flags & GTK_CELL_RENDERER_PRELIT) != 0)
532
 
        {
533
 
            temp = eel_create_spotlight_pixbuf (pixbuf);
534
 
            g_object_unref (pixbuf);
535
 
            pixbuf = temp;
536
 
        }
537
 
 
538
 
        //state = gtk_cell_renderer_get_state (cell, widget, flags);
539
 
    }
540
 
 
541
 
    /*if (state != GTK_STATE_FLAG_NORMAL)
542
 
      {
543
 
      stated = create_symbolic_pixbuf (cellpixbuf, widget, state);
544
 
 
545
 
      if (!stated)
546
 
      stated = transform_pixbuf_state (pixbuf, context);
547
 
 
548
 
      g_object_unref (pixbuf);
549
 
      pixbuf = stated;
550
 
      }*/
551
 
 
552
 
    if (pixbuf != NULL) {
553
 
        if (priv->file->flags == GOF_FILE_THUMB_STATE_READY
554
 
            && gof_file_get_thumbnail_path (priv->file)
555
 
            && gof_file_thumb_can_frame (priv->file)
556
 
            && thumbnail_needs_frame (pixbuf, pix_rect.width, pix_rect.height))
557
 
        {
558
 
            cairo_make_shadow_for_rect (cr, pix_rect.x+4, pix_rect.y+4,
559
 
                                        pix_rect.width-4, pix_rect.height-6,
560
 
                                        4, 0, 0, 0, 8);
561
 
        }
562
 
 
563
 
        gtk_render_icon (context, cr, pixbuf,
564
 
                         pix_rect.x, pix_rect.y);
565
 
 
566
 
        /* let the theme draw a frame for loaded thumbnails */
567
 
        if (priv->file->flags == GOF_FILE_THUMB_STATE_READY
568
 
            && gof_file_get_thumbnail_path (priv->file)
569
 
            && gof_file_thumb_can_frame (priv->file))
570
 
        {
571
 
            gtk_render_frame (context, cr,
572
 
                              pix_rect.x, pix_rect.y,
573
 
                              pix_rect.width, pix_rect.height);
574
 
        }
575
 
 
576
 
        gtk_style_context_restore (context);
577
 
        g_object_unref (pixbuf);
578
 
    }
579
 
 
580
 
    /* add remove helpers +/- */
581
 
    GdkPixbuf *pix;
582
 
 
583
 
    /* Do not show selection helpers or emblems for very small icons */
584
 
    if (priv->selection_helpers &&
585
 
        (flags & (GTK_CELL_RENDERER_PRELIT | GTK_CELL_RENDERER_SELECTED)) != 0 &&
586
 
        priv->file != priv->drop_file)
587
 
    {
588
 
        if((flags & GTK_CELL_RENDERER_SELECTED) != 0 && (flags & GTK_CELL_RENDERER_PRELIT) != 0)
589
 
            nicon = marlin_icon_info_lookup_from_name ("selection-remove", priv->helper_size);
590
 
        else if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
591
 
            nicon = marlin_icon_info_lookup_from_name ("selection-checked", priv->helper_size);
592
 
        else if ((flags & GTK_CELL_RENDERER_PRELIT) != 0)
593
 
            nicon = marlin_icon_info_lookup_from_name ("selection-add", priv->helper_size);
594
 
 
595
 
        pix = marlin_icon_info_get_pixbuf_nodefault (nicon);
596
 
        if (pix != NULL) {
597
 
            gdk_cairo_set_source_pixbuf (cr, pix, pix_rect.x, pix_rect.y);
598
 
            cairo_paint (cr);
599
 
            g_object_unref (pix);
600
 
        }
601
 
 
602
 
        g_object_unref (nicon);
603
 
 
604
 
    }
605
 
 
606
 
    /* check if we should render emblems as well */
607
 
    /* Still show emblems when selection helpers hidden in double click mode */
608
 
    if (G_LIKELY (priv->emblems)) 
609
 
    {
610
 
        int position = 0;
611
 
        GList* emblems = g_list_first(priv->file->emblems_list);
612
 
 
613
 
        /* render the emblems
614
 
         * show number of emblems depending on the zoom lvl. */
615
 
        while (emblems != NULL && priv->zoom_level > 0 && position < priv->zoom_level)
616
 
        {
617
 
            /* check if we have the emblem in the icon theme */
618
 
            nicon = marlin_icon_info_lookup_from_name (emblems->data, MARLIN_EMBLEM_SIZE);
619
 
            pix = marlin_icon_info_get_pixbuf_nodefault (nicon);
620
 
            if (pix == NULL) {
621
 
                g_warning ("Can't load icon %s", (char *) emblems->data);
622
 
                return;
623
 
            }
624
 
 
625
 
            /* determine the dimensions of the emblem */
626
 
            emblem_area.width = gdk_pixbuf_get_width (pix);
627
 
            emblem_area.height = gdk_pixbuf_get_height (pix);
628
 
 
629
 
            /* stack emblem on a vertical line begging from the bottom */
630
 
            guint overlap = MIN (8 + priv->zoom_level, pix_rect.width / 4);
631
 
            emblem_area.x = pix_rect.x + pix_rect.width - overlap;
632
 
            emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width * (position + 1);
633
 
            /* don't show cutted emblems */
634
 
            if (emblem_area.y < background_area->y)
635
 
                break;
636
 
 
637
 
#if 0
638
 
            /* nice square shape */
639
 
            /* determine a good position for the emblem, depending on the position index */
640
 
            switch (position)
641
 
            {
642
 
            case 0: /* bottom/right */
643
 
                emblem_area.x = MIN (pix_rect.x + pix_rect.width - emblem_area.width/2, background_area->x + background_area->width - emblem_area.width);
644
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width;
645
 
                break;
646
 
            case 1: /* top/right */
647
 
                emblem_area.x = MIN (pix_rect.x + pix_rect.width - emblem_area.width/2, background_area->x + background_area->width - emblem_area.width);
648
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width * 2;
649
 
                break;
650
 
            case 2: /* bottom/left */
651
 
                emblem_area.x = MIN (pix_rect.x + pix_rect.width - emblem_area.width/2 - emblem_area.width, background_area->x + background_area->width - 2 * emblem_area.width);
652
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width;
653
 
                break;
654
 
            case 3: /* top/left */
655
 
                emblem_area.x = MIN (pix_rect.x + pix_rect.width - emblem_area.width/2 - emblem_area.width, background_area->x + background_area->width - 2 * emblem_area.width);
656
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width * 2;
657
 
                break;
658
 
            }
659
 
#endif
660
 
 
661
 
            gdk_cairo_set_source_pixbuf (cr, pix, emblem_area.x, emblem_area.y);
662
 
            cairo_paint (cr);
663
 
 
664
 
            position ++;
665
 
 
666
 
            emblems = g_list_next(emblems);
667
 
            g_object_unref (nicon);
668
 
            g_object_unref (pix);
669
 
        }
670
 
    }
671
 
 
672
 
    /* The render call should always be preceded by a set_property call from
673
 
       GTK. It should be safe to unreference or free the allocate memory
674
 
       here. */
675
 
    _g_object_unref0 (priv->file);
676
 
    _g_object_unref0 (priv->drop_file);
677
 
}
678
 
 
679
 
/*
680
 
 * Shadows code snippet took from synapse (ui/utils.vala) and converted to C.
681
 
 * Authored by Michal Hruby <michal.mhr@gmail.com>
682
 
 *             Alberto Aldegheri <albyrock87+dev@gmail.com>
683
 
 */
684
 
 
685
 
#define _cairo_pattern_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_pattern_destroy (var), NULL)))
686
 
 
687
 
static void
688
 
add_shadow_stops (cairo_pattern_t* pat, gdouble r, gdouble g, gdouble b, gdouble size, gdouble alpha)
689
 
{
690
 
    g_return_if_fail (pat != NULL);
691
 
 
692
 
    cairo_pattern_add_color_stop_rgba (pat, 1.0, r, g, b, (gdouble) 0);
693
 
    cairo_pattern_add_color_stop_rgba (pat, 0.8, r, g, b, alpha * 0.07);
694
 
    cairo_pattern_add_color_stop_rgba (pat, 0.6, r, g, b, alpha * 0.24);
695
 
    cairo_pattern_add_color_stop_rgba (pat, 0.4, r, g, b, alpha * 0.46);
696
 
    cairo_pattern_add_color_stop_rgba (pat, 0.2, r, g, b, alpha * 0.77);
697
 
    cairo_pattern_add_color_stop_rgba (pat, 0.0, r, g, b, alpha);
698
 
}
699
 
 
700
 
 
701
 
static void
702
 
cairo_make_shadow_for_rect (cairo_t* cr,
703
 
                            gdouble x1, gdouble y1, gdouble w, gdouble h,
704
 
                            gdouble rad, gdouble r, gdouble g, gdouble b, gdouble size)
705
 
{
706
 
    gdouble a;
707
 
    gdouble x2;
708
 
    gdouble x3;
709
 
    gdouble x4;
710
 
    gdouble y2;
711
 
    gdouble y3;
712
 
    gdouble y4;
713
 
    gdouble thick;
714
 
    cairo_pattern_t* pat = NULL;
715
 
 
716
 
    g_return_if_fail (cr != NULL);
717
 
    if (size < ((gdouble) 1))
718
 
        return;
719
 
 
720
 
    cairo_save (cr);
721
 
    a = 0.25;
722
 
    cairo_translate (cr, 0.5, 0.5);
723
 
    w -= 1;
724
 
    h -= 1;
725
 
    x2 = x1 + rad;
726
 
    x3 = x1 + w - rad;
727
 
    x4 = x1 + w;
728
 
    y2 = y1 + rad;
729
 
    y3 = y1 + h - rad;
730
 
    y4 = y1 + h;
731
 
    thick = size + rad;
732
 
 
733
 
    /* Top left corner */
734
 
    cairo_save (cr);
735
 
    _cairo_pattern_destroy0 (pat);
736
 
    pat = cairo_pattern_create_radial (x2, y2, rad, x2, y2, thick);
737
 
    add_shadow_stops (pat, r, g, b, size, a);
738
 
    cairo_set_source (cr, pat);
739
 
    cairo_rectangle (cr, x1-size, y1-size, thick, thick);
740
 
    cairo_clip (cr);
741
 
    cairo_paint (cr);
742
 
    cairo_restore (cr);
743
 
 
744
 
    /* Bottom left corner */
745
 
    cairo_save (cr);
746
 
    _cairo_pattern_destroy0 (pat);
747
 
    pat = cairo_pattern_create_radial (x2, y3, rad, x2, y3, thick);
748
 
    add_shadow_stops (pat, r, g, b, size, a);
749
 
    cairo_set_source (cr, pat);
750
 
    cairo_rectangle (cr, x1-size, y3, thick, thick);
751
 
    cairo_clip (cr);
752
 
    cairo_paint (cr);
753
 
    cairo_restore (cr);
754
 
 
755
 
    /* Top right corner */
756
 
    cairo_save (cr);
757
 
    _cairo_pattern_destroy0 (pat);
758
 
    pat = cairo_pattern_create_radial (x3, y2, rad, x3, y2, thick);
759
 
    add_shadow_stops (pat, r, g, b, size, a);
760
 
    cairo_set_source (cr, pat);
761
 
    cairo_rectangle (cr, x3, y1-size, thick, thick);
762
 
    cairo_clip (cr);
763
 
    cairo_paint (cr);
764
 
    cairo_restore (cr);
765
 
 
766
 
    /* Bottom right corner */
767
 
    cairo_save (cr);
768
 
    _cairo_pattern_destroy0 (pat);
769
 
    pat = cairo_pattern_create_radial (x3, y3, rad, x3, y3, thick);
770
 
    add_shadow_stops (pat, r, g, b, size, a);
771
 
    cairo_set_source (cr, pat);
772
 
    cairo_rectangle (cr, x3, y3, thick, thick);
773
 
    cairo_clip (cr);
774
 
    cairo_paint (cr);
775
 
    cairo_restore (cr);
776
 
 
777
 
    /* Right */
778
 
    cairo_save (cr);
779
 
    _cairo_pattern_destroy0 (pat);
780
 
    pat = cairo_pattern_create_linear (x4, 0, x4+size, 0);
781
 
    add_shadow_stops (pat, r, g, b, size, a);
782
 
    cairo_set_source (cr, pat);
783
 
    cairo_rectangle (cr, x4, y2, size, y3-y2);
784
 
    cairo_clip (cr);
785
 
    cairo_paint (cr);
786
 
    cairo_restore (cr);
787
 
 
788
 
    /* Left */
789
 
    cairo_save (cr);
790
 
    _cairo_pattern_destroy0 (pat);
791
 
    pat = cairo_pattern_create_linear (x1, 0, x1-size, 0);
792
 
    add_shadow_stops (pat, r, g, b, size, a);
793
 
    cairo_set_source (cr, pat);
794
 
    cairo_rectangle (cr, x1-size, y2, size, y3-y2);
795
 
    cairo_clip (cr);
796
 
    cairo_paint (cr);
797
 
    cairo_restore (cr);
798
 
 
799
 
    /* Bottom */
800
 
    cairo_save (cr);
801
 
    _cairo_pattern_destroy0 (pat);
802
 
    pat = cairo_pattern_create_linear (0, y4, 0, y4+size);
803
 
    add_shadow_stops (pat, r, g, b, size, a);
804
 
    cairo_set_source (cr, pat);
805
 
    cairo_rectangle (cr, x2, y4, x3-x2, size);
806
 
    cairo_clip (cr);
807
 
    cairo_paint (cr);
808
 
    cairo_restore (cr);
809
 
 
810
 
    /* Top */
811
 
    cairo_save (cr);
812
 
    _cairo_pattern_destroy0 (pat);
813
 
    pat = cairo_pattern_create_linear (0, y1, 0, y1-size);
814
 
    add_shadow_stops (pat, r, g, b, size, a);
815
 
    cairo_set_source (cr, pat);
816
 
    cairo_rectangle (cr, x2, y1-size, x3-x2, size);
817
 
    cairo_clip (cr);
818
 
    cairo_paint (cr);
819
 
    cairo_restore (cr);
820
 
 
821
 
    cairo_restore (cr);
822
 
    _cairo_pattern_destroy0 (pat);
823
 
}
824
 
 
825
 
static inline gboolean
826
 
thumbnail_needs_frame (const GdkPixbuf *thumbnail,
827
 
                       gint             width,
828
 
                       gint             height)
829
 
{
830
 
  const guchar *pixels;
831
 
  gint          rowstride;
832
 
  gint          n;
833
 
 
834
 
  /* don't add frames to small thumbnails */
835
 
  if (width < 48 && height < 48)
836
 
    return FALSE;
837
 
 
838
 
  /* always add a frame to thumbnails w/o alpha channel */
839
 
  if (G_LIKELY (!gdk_pixbuf_get_has_alpha (thumbnail)))
840
 
    return TRUE;
841
 
 
842
 
  /* get a pointer to the thumbnail data */
843
 
  pixels = gdk_pixbuf_get_pixels (thumbnail);
844
 
 
845
 
  /* check if we have a transparent pixel on the first row */
846
 
  for (n = width * 4; n > 0; n -= 4)
847
 
    if (pixels[n - 1] < 255u)
848
 
      return FALSE;
849
 
  g_debug("transparent pixel");
850
 
 
851
 
  /* determine the rowstride */
852
 
  rowstride = gdk_pixbuf_get_rowstride (thumbnail);
853
 
 
854
 
  /* skip the first row */
855
 
  pixels += rowstride;
856
 
 
857
 
  /* check if we have a transparent pixel in the first or last column */
858
 
  for (n = height - 2; n > 0; --n, pixels += rowstride)
859
 
    if (pixels[3] < 255u || pixels[width * 4 - 1] < 255u)
860
 
      return FALSE;
861
 
 
862
 
  /* check if we have a transparent pixel on the last row */
863
 
  for (n = width * 4; n > 0; n -= 4)
864
 
    if (pixels[n - 1] < 255u)
865
 
      return FALSE;
866
 
 
867
 
  return TRUE;
868
 
}