~jeremywootten/pantheon-files/fix-798470-merge-files-to-folder-by-drag-drop

« back to all changes in this revision

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

  • Committer: Jeremy Wootten
  • Date: 2017-01-28 18:55:54 UTC
  • Revision ID: jeremy@elementaryos.org-20170128185554-3bx9208r2camy1xm
Remove marlin-icon-info file added in error

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
 
        if (priv->file->is_directory) { /* only show "folder-drag-accept" image for folders.  Otherwise just prelight */
479
 
            nicon = marlin_icon_info_lookup_from_name ("folder-drag-accept", priv->size);
480
 
            temp = marlin_icon_info_get_pixbuf_nodefault (nicon);
481
 
            g_object_unref (nicon);
482
 
            g_object_unref (pixbuf);
483
 
            pixbuf = temp;
484
 
        }
485
 
    } else if (priv->file->is_directory) {
486
 
        if (priv->file->is_expanded) {
487
 
            nicon = marlin_icon_info_lookup_from_name ("folder-open", priv->size);
488
 
            temp = marlin_icon_info_get_pixbuf_nodefault (nicon);
489
 
            g_object_unref (nicon);
490
 
            g_object_unref (pixbuf);
491
 
            pixbuf = temp;
492
 
        }
493
 
    }
494
 
 
495
 
    /* clipboard */
496
 
    if (marlin_clipboard_manager_has_cutted_file (priv->clipboard, priv->file))
497
 
    {
498
 
        /* 50% translucent for cutted files */
499
 
        temp = eel_gdk_pixbuf_lucent (pixbuf, 50);
500
 
        g_object_unref (pixbuf);
501
 
        pixbuf = temp;
502
 
    }
503
 
    else if (priv->file->is_hidden)
504
 
    {
505
 
        /* 75% translucent for hidden files */
506
 
        temp = eel_gdk_pixbuf_lucent (pixbuf, 75);
507
 
        g_object_unref (pixbuf);
508
 
        pixbuf = temp;
509
 
    }
510
 
 
511
 
    context = gtk_widget_get_style_context (gtk_widget_get_parent (widget));
512
 
    gtk_style_context_save (context);
513
 
    state = GTK_STATE_FLAG_NORMAL;
514
 
 
515
 
    if (!gtk_widget_get_sensitive (widget) ||
516
 
        !gtk_cell_renderer_get_sensitive (cell))
517
 
        state |= GTK_STATE_FLAG_INSENSITIVE;
518
 
    else if (priv->follow_state &&
519
 
             (flags & (GTK_CELL_RENDERER_SELECTED |
520
 
                       GTK_CELL_RENDERER_PRELIT)) != 0) {
521
 
        if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
522
 
        {
523
 
            state = GTK_STATE_FLAG_SELECTED;
524
 
            /* compute the state with the state of the widget; this way we handle the backdrop */
525
 
            state |= gtk_widget_get_state_flags (widget);
526
 
            GdkRGBA color;
527
 
            gtk_style_context_get_background_color (context, state, &color);
528
 
            temp = eel_create_colorized_pixbuf (pixbuf, &color);
529
 
            g_object_unref (pixbuf);
530
 
            pixbuf = temp;
531
 
        }
532
 
 
533
 
        if ((flags & GTK_CELL_RENDERER_PRELIT) != 0)
534
 
        {
535
 
            temp = eel_create_spotlight_pixbuf (pixbuf);
536
 
            g_object_unref (pixbuf);
537
 
            pixbuf = temp;
538
 
        }
539
 
 
540
 
        //state = gtk_cell_renderer_get_state (cell, widget, flags);
541
 
    }
542
 
 
543
 
    /*if (state != GTK_STATE_FLAG_NORMAL)
544
 
      {
545
 
      stated = create_symbolic_pixbuf (cellpixbuf, widget, state);
546
 
 
547
 
      if (!stated)
548
 
      stated = transform_pixbuf_state (pixbuf, context);
549
 
 
550
 
      g_object_unref (pixbuf);
551
 
      pixbuf = stated;
552
 
      }*/
553
 
 
554
 
    if (pixbuf != NULL) {
555
 
        if (priv->file->flags == GOF_FILE_THUMB_STATE_READY
556
 
            && gof_file_get_thumbnail_path (priv->file)
557
 
            && gof_file_thumb_can_frame (priv->file)
558
 
            && thumbnail_needs_frame (pixbuf, pix_rect.width, pix_rect.height))
559
 
        {
560
 
            cairo_make_shadow_for_rect (cr, pix_rect.x+4, pix_rect.y+4,
561
 
                                        pix_rect.width-4, pix_rect.height-6,
562
 
                                        4, 0, 0, 0, 8);
563
 
        }
564
 
 
565
 
        gtk_render_icon (context, cr, pixbuf,
566
 
                         pix_rect.x, pix_rect.y);
567
 
 
568
 
        /* let the theme draw a frame for loaded thumbnails */
569
 
        if (priv->file->flags == GOF_FILE_THUMB_STATE_READY
570
 
            && gof_file_get_thumbnail_path (priv->file)
571
 
            && gof_file_thumb_can_frame (priv->file))
572
 
        {
573
 
            gtk_render_frame (context, cr,
574
 
                              pix_rect.x, pix_rect.y,
575
 
                              pix_rect.width, pix_rect.height);
576
 
        }
577
 
 
578
 
        gtk_style_context_restore (context);
579
 
        g_object_unref (pixbuf);
580
 
    }
581
 
 
582
 
    /* add remove helpers +/- */
583
 
    GdkPixbuf *pix;
584
 
 
585
 
    /* Do not show selection helpers or emblems for very small icons */
586
 
    if (priv->selection_helpers &&
587
 
        (flags & (GTK_CELL_RENDERER_PRELIT | GTK_CELL_RENDERER_SELECTED)) != 0 &&
588
 
        priv->file != priv->drop_file)
589
 
    {
590
 
        if((flags & GTK_CELL_RENDERER_SELECTED) != 0 && (flags & GTK_CELL_RENDERER_PRELIT) != 0)
591
 
            nicon = marlin_icon_info_lookup_from_name ("selection-remove", priv->helper_size);
592
 
        else if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
593
 
            nicon = marlin_icon_info_lookup_from_name ("selection-checked", priv->helper_size);
594
 
        else if ((flags & GTK_CELL_RENDERER_PRELIT) != 0)
595
 
            nicon = marlin_icon_info_lookup_from_name ("selection-add", priv->helper_size);
596
 
 
597
 
        pix = marlin_icon_info_get_pixbuf_nodefault (nicon);
598
 
        if (pix != NULL) {
599
 
            gdk_cairo_set_source_pixbuf (cr, pix, pix_rect.x, pix_rect.y);
600
 
            cairo_paint (cr);
601
 
            g_object_unref (pix);
602
 
        }
603
 
 
604
 
        g_object_unref (nicon);
605
 
 
606
 
    }
607
 
 
608
 
    /* check if we should render emblems as well */
609
 
    /* Still show emblems when selection helpers hidden in double click mode */
610
 
    if (G_LIKELY (priv->emblems)) 
611
 
    {
612
 
        int position = 0;
613
 
        GList* emblems = g_list_first(priv->file->emblems_list);
614
 
 
615
 
        /* render the emblems
616
 
         * show number of emblems depending on the zoom lvl. */
617
 
        while (emblems != NULL && priv->zoom_level > 0 && position < priv->zoom_level)
618
 
        {
619
 
            /* check if we have the emblem in the icon theme */
620
 
            nicon = marlin_icon_info_lookup_from_name (emblems->data, MARLIN_EMBLEM_SIZE);
621
 
            pix = marlin_icon_info_get_pixbuf_nodefault (nicon);
622
 
            if (pix == NULL) {
623
 
                g_warning ("Can't load icon %s", (char *) emblems->data);
624
 
                return;
625
 
            }
626
 
 
627
 
            /* determine the dimensions of the emblem */
628
 
            emblem_area.width = gdk_pixbuf_get_width (pix);
629
 
            emblem_area.height = gdk_pixbuf_get_height (pix);
630
 
 
631
 
            /* stack emblem on a vertical line begging from the bottom */
632
 
            guint overlap = MIN (8 + priv->zoom_level, pix_rect.width / 4);
633
 
            emblem_area.x = pix_rect.x + pix_rect.width - overlap;
634
 
            emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width * (position + 1);
635
 
            /* don't show cutted emblems */
636
 
            if (emblem_area.y < background_area->y)
637
 
                break;
638
 
 
639
 
#if 0
640
 
            /* nice square shape */
641
 
            /* determine a good position for the emblem, depending on the position index */
642
 
            switch (position)
643
 
            {
644
 
            case 0: /* bottom/right */
645
 
                emblem_area.x = MIN (pix_rect.x + pix_rect.width - emblem_area.width/2, background_area->x + background_area->width - emblem_area.width);
646
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width;
647
 
                break;
648
 
            case 1: /* top/right */
649
 
                emblem_area.x = MIN (pix_rect.x + pix_rect.width - emblem_area.width/2, background_area->x + background_area->width - emblem_area.width);
650
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width * 2;
651
 
                break;
652
 
            case 2: /* bottom/left */
653
 
                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);
654
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width;
655
 
                break;
656
 
            case 3: /* top/left */
657
 
                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);
658
 
                emblem_area.y = pix_rect.y + pix_rect.height - emblem_area.width * 2;
659
 
                break;
660
 
            }
661
 
#endif
662
 
 
663
 
            gdk_cairo_set_source_pixbuf (cr, pix, emblem_area.x, emblem_area.y);
664
 
            cairo_paint (cr);
665
 
 
666
 
            position ++;
667
 
 
668
 
            emblems = g_list_next(emblems);
669
 
            g_object_unref (nicon);
670
 
            g_object_unref (pix);
671
 
        }
672
 
    }
673
 
 
674
 
    /* The render call should always be preceded by a set_property call from
675
 
       GTK. It should be safe to unreference or free the allocate memory
676
 
       here. */
677
 
    _g_object_unref0 (priv->file);
678
 
    _g_object_unref0 (priv->drop_file);
679
 
}
680
 
 
681
 
/*
682
 
 * Shadows code snippet took from synapse (ui/utils.vala) and converted to C.
683
 
 * Authored by Michal Hruby <michal.mhr@gmail.com>
684
 
 *             Alberto Aldegheri <albyrock87+dev@gmail.com>
685
 
 */
686
 
 
687
 
#define _cairo_pattern_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_pattern_destroy (var), NULL)))
688
 
 
689
 
static void
690
 
add_shadow_stops (cairo_pattern_t* pat, gdouble r, gdouble g, gdouble b, gdouble size, gdouble alpha)
691
 
{
692
 
    g_return_if_fail (pat != NULL);
693
 
 
694
 
    cairo_pattern_add_color_stop_rgba (pat, 1.0, r, g, b, (gdouble) 0);
695
 
    cairo_pattern_add_color_stop_rgba (pat, 0.8, r, g, b, alpha * 0.07);
696
 
    cairo_pattern_add_color_stop_rgba (pat, 0.6, r, g, b, alpha * 0.24);
697
 
    cairo_pattern_add_color_stop_rgba (pat, 0.4, r, g, b, alpha * 0.46);
698
 
    cairo_pattern_add_color_stop_rgba (pat, 0.2, r, g, b, alpha * 0.77);
699
 
    cairo_pattern_add_color_stop_rgba (pat, 0.0, r, g, b, alpha);
700
 
}
701
 
 
702
 
 
703
 
static void
704
 
cairo_make_shadow_for_rect (cairo_t* cr,
705
 
                            gdouble x1, gdouble y1, gdouble w, gdouble h,
706
 
                            gdouble rad, gdouble r, gdouble g, gdouble b, gdouble size)
707
 
{
708
 
    gdouble a;
709
 
    gdouble x2;
710
 
    gdouble x3;
711
 
    gdouble x4;
712
 
    gdouble y2;
713
 
    gdouble y3;
714
 
    gdouble y4;
715
 
    gdouble thick;
716
 
    cairo_pattern_t* pat = NULL;
717
 
 
718
 
    g_return_if_fail (cr != NULL);
719
 
    if (size < ((gdouble) 1))
720
 
        return;
721
 
 
722
 
    cairo_save (cr);
723
 
    a = 0.25;
724
 
    cairo_translate (cr, 0.5, 0.5);
725
 
    w -= 1;
726
 
    h -= 1;
727
 
    x2 = x1 + rad;
728
 
    x3 = x1 + w - rad;
729
 
    x4 = x1 + w;
730
 
    y2 = y1 + rad;
731
 
    y3 = y1 + h - rad;
732
 
    y4 = y1 + h;
733
 
    thick = size + rad;
734
 
 
735
 
    /* Top left corner */
736
 
    cairo_save (cr);
737
 
    _cairo_pattern_destroy0 (pat);
738
 
    pat = cairo_pattern_create_radial (x2, y2, rad, x2, y2, thick);
739
 
    add_shadow_stops (pat, r, g, b, size, a);
740
 
    cairo_set_source (cr, pat);
741
 
    cairo_rectangle (cr, x1-size, y1-size, thick, thick);
742
 
    cairo_clip (cr);
743
 
    cairo_paint (cr);
744
 
    cairo_restore (cr);
745
 
 
746
 
    /* Bottom left corner */
747
 
    cairo_save (cr);
748
 
    _cairo_pattern_destroy0 (pat);
749
 
    pat = cairo_pattern_create_radial (x2, y3, rad, x2, y3, thick);
750
 
    add_shadow_stops (pat, r, g, b, size, a);
751
 
    cairo_set_source (cr, pat);
752
 
    cairo_rectangle (cr, x1-size, y3, thick, thick);
753
 
    cairo_clip (cr);
754
 
    cairo_paint (cr);
755
 
    cairo_restore (cr);
756
 
 
757
 
    /* Top right corner */
758
 
    cairo_save (cr);
759
 
    _cairo_pattern_destroy0 (pat);
760
 
    pat = cairo_pattern_create_radial (x3, y2, rad, x3, y2, thick);
761
 
    add_shadow_stops (pat, r, g, b, size, a);
762
 
    cairo_set_source (cr, pat);
763
 
    cairo_rectangle (cr, x3, y1-size, thick, thick);
764
 
    cairo_clip (cr);
765
 
    cairo_paint (cr);
766
 
    cairo_restore (cr);
767
 
 
768
 
    /* Bottom right corner */
769
 
    cairo_save (cr);
770
 
    _cairo_pattern_destroy0 (pat);
771
 
    pat = cairo_pattern_create_radial (x3, y3, rad, x3, y3, thick);
772
 
    add_shadow_stops (pat, r, g, b, size, a);
773
 
    cairo_set_source (cr, pat);
774
 
    cairo_rectangle (cr, x3, y3, thick, thick);
775
 
    cairo_clip (cr);
776
 
    cairo_paint (cr);
777
 
    cairo_restore (cr);
778
 
 
779
 
    /* Right */
780
 
    cairo_save (cr);
781
 
    _cairo_pattern_destroy0 (pat);
782
 
    pat = cairo_pattern_create_linear (x4, 0, x4+size, 0);
783
 
    add_shadow_stops (pat, r, g, b, size, a);
784
 
    cairo_set_source (cr, pat);
785
 
    cairo_rectangle (cr, x4, y2, size, y3-y2);
786
 
    cairo_clip (cr);
787
 
    cairo_paint (cr);
788
 
    cairo_restore (cr);
789
 
 
790
 
    /* Left */
791
 
    cairo_save (cr);
792
 
    _cairo_pattern_destroy0 (pat);
793
 
    pat = cairo_pattern_create_linear (x1, 0, x1-size, 0);
794
 
    add_shadow_stops (pat, r, g, b, size, a);
795
 
    cairo_set_source (cr, pat);
796
 
    cairo_rectangle (cr, x1-size, y2, size, y3-y2);
797
 
    cairo_clip (cr);
798
 
    cairo_paint (cr);
799
 
    cairo_restore (cr);
800
 
 
801
 
    /* Bottom */
802
 
    cairo_save (cr);
803
 
    _cairo_pattern_destroy0 (pat);
804
 
    pat = cairo_pattern_create_linear (0, y4, 0, y4+size);
805
 
    add_shadow_stops (pat, r, g, b, size, a);
806
 
    cairo_set_source (cr, pat);
807
 
    cairo_rectangle (cr, x2, y4, x3-x2, size);
808
 
    cairo_clip (cr);
809
 
    cairo_paint (cr);
810
 
    cairo_restore (cr);
811
 
 
812
 
    /* Top */
813
 
    cairo_save (cr);
814
 
    _cairo_pattern_destroy0 (pat);
815
 
    pat = cairo_pattern_create_linear (0, y1, 0, y1-size);
816
 
    add_shadow_stops (pat, r, g, b, size, a);
817
 
    cairo_set_source (cr, pat);
818
 
    cairo_rectangle (cr, x2, y1-size, x3-x2, size);
819
 
    cairo_clip (cr);
820
 
    cairo_paint (cr);
821
 
    cairo_restore (cr);
822
 
 
823
 
    cairo_restore (cr);
824
 
    _cairo_pattern_destroy0 (pat);
825
 
}
826
 
 
827
 
static inline gboolean
828
 
thumbnail_needs_frame (const GdkPixbuf *thumbnail,
829
 
                       gint             width,
830
 
                       gint             height)
831
 
{
832
 
  const guchar *pixels;
833
 
  gint          rowstride;
834
 
  gint          n;
835
 
 
836
 
  /* don't add frames to small thumbnails */
837
 
  if (width < 48 && height < 48)
838
 
    return FALSE;
839
 
 
840
 
  /* always add a frame to thumbnails w/o alpha channel */
841
 
  if (G_LIKELY (!gdk_pixbuf_get_has_alpha (thumbnail)))
842
 
    return TRUE;
843
 
 
844
 
  /* get a pointer to the thumbnail data */
845
 
  pixels = gdk_pixbuf_get_pixels (thumbnail);
846
 
 
847
 
  /* check if we have a transparent pixel on the first row */
848
 
  for (n = width * 4; n > 0; n -= 4)
849
 
    if (pixels[n - 1] < 255u)
850
 
      return FALSE;
851
 
  g_debug("transparent pixel");
852
 
 
853
 
  /* determine the rowstride */
854
 
  rowstride = gdk_pixbuf_get_rowstride (thumbnail);
855
 
 
856
 
  /* skip the first row */
857
 
  pixels += rowstride;
858
 
 
859
 
  /* check if we have a transparent pixel in the first or last column */
860
 
  for (n = height - 2; n > 0; --n, pixels += rowstride)
861
 
    if (pixels[3] < 255u || pixels[width * 4 - 1] < 255u)
862
 
      return FALSE;
863
 
 
864
 
  /* check if we have a transparent pixel on the last row */
865
 
  for (n = width * 4; n > 0; n -= 4)
866
 
    if (pixels[n - 1] < 255u)
867
 
      return FALSE;
868
 
 
869
 
  return TRUE;
870
 
}