gtkdragicon.c 16.2 KB
Newer Older
Matthias Clasen's avatar
Matthias Clasen committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* GTK - The GIMP Toolkit
 * Copyright 2019 Matthias Clasen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"

20
#include "gtkdragicon.h"
Matthias Clasen's avatar
Matthias Clasen committed
21
22
23

#include "gtkintl.h"
#include "gtkwidgetprivate.h"
24
25
#include "gtkcssstyleprivate.h"
#include "gtkcsstypesprivate.h"
26
#include "gtknativeprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
27
#include "gtkpicture.h"
28
#include "gtkcssboxesimplprivate.h"
29
#include "gtkcssnumbervalueprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
30

Benjamin Otte's avatar
Benjamin Otte committed
31
32
#include "gdk/gdksurfaceprivate.h"

33
34
/* for the drag icons */
#include "gtkcolorswatchprivate.h"
35
#include "gtkimage.h"
36
#include "gtklabel.h"
37
#include "gtkrendernodepaintableprivate.h"
38
39
#include "gtktextutil.h"

Matthias Clasen's avatar
Matthias Clasen committed
40

Matthias Clasen's avatar
Matthias Clasen committed
41
/**
Matthias Clasen's avatar
Matthias Clasen committed
42
 * GtkDragIcon:
Matthias Clasen's avatar
Matthias Clasen committed
43
 *
Matthias Clasen's avatar
Matthias Clasen committed
44
45
 * `GtkDragIcon` is a `GtkRoot` implementation for drag icons.
 *
Matthias Clasen's avatar
Matthias Clasen committed
46
 * A drag icon moves with the pointer during a Drag-and-Drop operation
Matthias Clasen's avatar
Matthias Clasen committed
47
 * and is destroyed when the drag ends.
Matthias Clasen's avatar
Matthias Clasen committed
48
49
 *
 * To set up a drag icon and associate it with an ongoing drag operation,
Matthias Clasen's avatar
Matthias Clasen committed
50
51
52
 * use [func@Gtk.DragIcon.get_for_drag] to get the icon for a drag. You can
 * then use it like any other widget and use [method@Gtk.DragIcon.set_child]
 * to set whatever widget should be used for the drag icon.
53
54
 *
 * Keep in mind that drag icons do not allow user input.
Matthias Clasen's avatar
Matthias Clasen committed
55
 */
Matthias Clasen's avatar
Matthias Clasen committed
56
57
58
59
60
61
struct _GtkDragIcon
{
  GtkWidget parent_instance;

  GdkSurface *surface;
  GskRenderer *renderer;
62
  GtkWidget *child;
Matthias Clasen's avatar
Matthias Clasen committed
63
64
65
66
67
68
69
70
};

struct _GtkDragIconClass
{
  GtkWidgetClass parent_class;
};

enum {
71
72
73
74
  PROP_0,
  PROP_CHILD,

  LAST_ARG
Matthias Clasen's avatar
Matthias Clasen committed
75
76
};

77
78
static GParamSpec *properties[LAST_ARG] = { NULL, };

Matthias Clasen's avatar
Matthias Clasen committed
79
80
81
static void gtk_drag_icon_root_init   (GtkRootInterface *iface);
static void gtk_drag_icon_native_init (GtkNativeInterface *iface);

82
G_DEFINE_TYPE_WITH_CODE (GtkDragIcon, gtk_drag_icon, GTK_TYPE_WIDGET,
Matthias Clasen's avatar
Matthias Clasen committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE,
                                                gtk_drag_icon_native_init)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ROOT,
                                                gtk_drag_icon_root_init))

static GdkDisplay *
gtk_drag_icon_root_get_display (GtkRoot *self)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (self);

  if (icon->surface)
    return gdk_surface_get_display (icon->surface);

  return gdk_display_get_default ();
}

static void
gtk_drag_icon_root_init (GtkRootInterface *iface)
{
  iface->get_display = gtk_drag_icon_root_get_display;
}

static GdkSurface *
gtk_drag_icon_native_get_surface (GtkNative *native)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (native);

  return icon->surface;
}

static GskRenderer *
gtk_drag_icon_native_get_renderer (GtkNative *native)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (native);

  return icon->renderer;
}

static void
gtk_drag_icon_native_get_surface_transform (GtkNative *native,
123
124
                                            double    *x,
                                            double    *y)
Matthias Clasen's avatar
Matthias Clasen committed
125
{
126
127
128
129
130
131
132
133
  GtkCssBoxes css_boxes;
  const graphene_rect_t *margin_rect;

  gtk_css_boxes_init (&css_boxes, GTK_WIDGET (native));
  margin_rect = gtk_css_boxes_get_margin_rect (&css_boxes);

  *x = - margin_rect->origin.x;
  *y = - margin_rect->origin.y;
Matthias Clasen's avatar
Matthias Clasen committed
134
135
136
137
138
139
140
141
142
143
}

static void
gtk_drag_icon_move_resize (GtkDragIcon *icon)
{
  GtkRequisition req;

  if (icon->surface)
    {
      gtk_widget_get_preferred_size (GTK_WIDGET (icon), NULL, &req);
144
145
146
      gdk_drag_surface_present (GDK_DRAG_SURFACE (icon->surface),
                                MAX (1, req.width),
                                MAX (1, req.height));
Matthias Clasen's avatar
Matthias Clasen committed
147
148
149
    }
}

150
151
152
153
static void
gtk_drag_icon_present (GtkDragIcon *icon)
{
  GtkWidget *widget = GTK_WIDGET (icon);
Matthias Clasen's avatar
Matthias Clasen committed
154
155
156
157

  if (!_gtk_widget_get_alloc_needed (widget))
    gtk_widget_ensure_allocate (widget);
  else if (gtk_widget_get_visible (widget))
158
    gtk_drag_icon_move_resize (icon);
Matthias Clasen's avatar
Matthias Clasen committed
159
160
}

161
162
163
164
165
166
167
168
static void
gtk_drag_icon_native_layout (GtkNative *native,
                             int        width,
                             int        height)
{
  gtk_widget_allocate (GTK_WIDGET (native), width, height, -1, NULL);
}

Matthias Clasen's avatar
Matthias Clasen committed
169
170
171
172
173
174
static void
gtk_drag_icon_native_init (GtkNativeInterface *iface)
{
  iface->get_surface = gtk_drag_icon_native_get_surface;
  iface->get_renderer = gtk_drag_icon_native_get_renderer;
  iface->get_surface_transform = gtk_drag_icon_native_get_surface_transform;
175
  iface->layout = gtk_drag_icon_native_layout;
176
177
}

Matthias Clasen's avatar
Matthias Clasen committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
static gboolean
surface_render (GdkSurface     *surface,
                cairo_region_t *region,
                GtkWidget      *widget)
{
  gtk_widget_render (widget, surface, region);
  return TRUE;
}

static void
gtk_drag_icon_realize (GtkWidget *widget)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (widget);

  g_warn_if_fail (icon->surface != NULL);

  gdk_surface_set_widget (icon->surface, widget);

  g_signal_connect (icon->surface, "render", G_CALLBACK (surface_render), widget);

  GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->realize (widget);

  icon->renderer = gsk_renderer_new_for_surface (icon->surface);
201
202

  gtk_native_realize (GTK_NATIVE (icon));
Matthias Clasen's avatar
Matthias Clasen committed
203
204
205
206
207
208
209
}

static void
gtk_drag_icon_unrealize (GtkWidget *widget)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (widget);

210
211
  gtk_native_unrealize (GTK_NATIVE (icon));

Matthias Clasen's avatar
Matthias Clasen committed
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->unrealize (widget);

  gsk_renderer_unrealize (icon->renderer);
  g_clear_object (&icon->renderer);

  if (icon->surface)
    {
      g_signal_handlers_disconnect_by_func (icon->surface, surface_render, widget);
      gdk_surface_set_widget (icon->surface, NULL);
    }
}

static void
gtk_drag_icon_map (GtkWidget *widget)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (widget);

229
  gtk_drag_icon_move_resize (icon);
Matthias Clasen's avatar
Matthias Clasen committed
230
231
232

  GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->map (widget);

233
234
  if (icon->child && gtk_widget_get_visible (icon->child))
    gtk_widget_map (icon->child);
Matthias Clasen's avatar
Matthias Clasen committed
235
236
237
238
239
240
241
242
243
244
245
246
}

static void
gtk_drag_icon_unmap (GtkWidget *widget)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (widget);

  g_warn_if_fail (icon->surface != NULL);
  GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->unmap (widget);
  if (icon->surface)
    gdk_surface_hide (icon->surface);

247
248
  if (icon->child)
    gtk_widget_unmap (icon->child);
Matthias Clasen's avatar
Matthias Clasen committed
249
250
251
252
253
254
255
256
257
258
259
260
261
}

static void
gtk_drag_icon_measure (GtkWidget      *widget,
                       GtkOrientation  orientation,
                       int             for_size,
                       int            *minimum,
                       int            *natural,
                       int            *minimum_baseline,
                       int            *natural_baseline)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (widget);

262
263
  if (icon->child)
    gtk_widget_measure (icon->child,
Matthias Clasen's avatar
Matthias Clasen committed
264
265
266
267
268
269
270
271
272
273
274
275
276
                        orientation, for_size,
                        minimum, natural,
                        minimum_baseline, natural_baseline);
}

static void
gtk_drag_icon_size_allocate (GtkWidget *widget,
                             int        width,
                             int        height,
                             int        baseline)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (widget);

277
278
  if (icon->child)
    gtk_widget_allocate (icon->child, width, height, baseline, NULL);
Matthias Clasen's avatar
Matthias Clasen committed
279
280
281
282
283
284
285
286
}

static void
gtk_drag_icon_show (GtkWidget *widget)
{
  _gtk_widget_set_visible_flag (widget, TRUE);
  gtk_css_node_validate (gtk_widget_get_css_node (widget));
  gtk_widget_realize (widget);
287
  gtk_drag_icon_present (GTK_DRAG_ICON (widget));
Matthias Clasen's avatar
Matthias Clasen committed
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  gtk_widget_map (widget);
}

static void
gtk_drag_icon_hide (GtkWidget *widget)
{
  _gtk_widget_set_visible_flag (widget, FALSE);
  gtk_widget_unmap (widget);
}

static void
gtk_drag_icon_dispose (GObject *object)
{
  GtkDragIcon *icon = GTK_DRAG_ICON (object);

303
  g_clear_pointer (&icon->child, gtk_widget_unparent);
Matthias Clasen's avatar
Matthias Clasen committed
304
305
306
307
308
309
310
311
312
313
314
315

  G_OBJECT_CLASS (gtk_drag_icon_parent_class)->dispose (object);

  g_clear_object (&icon->surface);
}

static void
gtk_drag_icon_get_property (GObject     *object,
                            guint        prop_id,
                            GValue      *value,
                            GParamSpec  *pspec)
{
316
317
  GtkDragIcon *self = GTK_DRAG_ICON (object);

Matthias Clasen's avatar
Matthias Clasen committed
318
319
  switch (prop_id)
    {
320
321
322
323
    case PROP_CHILD:
      g_value_set_object (value, self->child);
      break;

Matthias Clasen's avatar
Matthias Clasen committed
324
325
326
327
328
329
330
331
332
333
334
335
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_drag_icon_set_property (GObject      *object,
                            guint         prop_id,
                            const GValue *value,
                            GParamSpec    *pspec)
{
336
337
  GtkDragIcon *self = GTK_DRAG_ICON (object);

Matthias Clasen's avatar
Matthias Clasen committed
338
339
  switch (prop_id)
    {
340
341
342
343
    case PROP_CHILD:
      gtk_drag_icon_set_child (self, g_value_get_object (value));
      break;

Matthias Clasen's avatar
Matthias Clasen committed
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_drag_icon_class_init (GtkDragIconClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  object_class->dispose = gtk_drag_icon_dispose;
  object_class->get_property = gtk_drag_icon_get_property;
  object_class->set_property = gtk_drag_icon_set_property;

  widget_class->realize = gtk_drag_icon_realize;
  widget_class->unrealize = gtk_drag_icon_unrealize;
  widget_class->map = gtk_drag_icon_map;
  widget_class->unmap = gtk_drag_icon_unmap;
  widget_class->measure = gtk_drag_icon_measure;
  widget_class->size_allocate = gtk_drag_icon_size_allocate;
  widget_class->show = gtk_drag_icon_show;
  widget_class->hide = gtk_drag_icon_hide;

369
  /**
Matthias Clasen's avatar
Matthias Clasen committed
370
   * GtkDragIcon:child: (attributes org.gtk.Property.get=gtk_drag_icon_get_child org.gtk.Property.set=gtk_drag_icon_set_child)
371
372
373
374
   *
   * The widget to display as drag icon.
   */
  properties[PROP_CHILD] =
375
    g_param_spec_object ("child", NULL, NULL,
376
377
378
379
                         GTK_TYPE_WIDGET,
                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);

  g_object_class_install_properties (object_class, LAST_ARG, properties);
Matthias Clasen's avatar
Matthias Clasen committed
380
381
382
383
384
385
386

  gtk_widget_class_set_css_name (widget_class, "dnd");
}

static void
gtk_drag_icon_init (GtkDragIcon *self)
{
Matthias Clasen's avatar
Matthias Clasen committed
387
  gtk_widget_set_can_target (GTK_WIDGET (self), FALSE);
Matthias Clasen's avatar
Matthias Clasen committed
388
389
}

Matthias Clasen's avatar
Matthias Clasen committed
390
/**
391
 * gtk_drag_icon_get_for_drag:
Matthias Clasen's avatar
Matthias Clasen committed
392
 * @drag: a `GdkDrag`
393
 *
Matthias Clasen's avatar
Matthias Clasen committed
394
 * Gets the `GtkDragIcon` in use with @drag.
Matthias Clasen's avatar
Matthias Clasen committed
395
 *
396
397
 * If no drag icon exists yet, a new one will be created
 * and shown.
Matthias Clasen's avatar
Matthias Clasen committed
398
 *
Matthias Clasen's avatar
Matthias Clasen committed
399
 * Returns: (transfer none): the `GtkDragIcon`
Matthias Clasen's avatar
Matthias Clasen committed
400
 */
Matthias Clasen's avatar
Matthias Clasen committed
401
GtkWidget *
402
gtk_drag_icon_get_for_drag (GdkDrag *drag)
Matthias Clasen's avatar
Matthias Clasen committed
403
{
404
405
  static GQuark drag_icon_quark = 0;
  GtkWidget *self;
Matthias Clasen's avatar
Matthias Clasen committed
406
407
408

  g_return_val_if_fail (GDK_IS_DRAG (drag), NULL);

409
410
411
412
413
414
415
416
417
  if (G_UNLIKELY (drag_icon_quark == 0))
    drag_icon_quark = g_quark_from_static_string ("-gtk-drag-icon");

  self = g_object_get_qdata (G_OBJECT (drag), drag_icon_quark);
  if (self == NULL)
    {
      self = g_object_new (GTK_TYPE_DRAG_ICON, NULL);

      GTK_DRAG_ICON (self)->surface = g_object_ref (gdk_drag_get_drag_surface (drag));
Matthias Clasen's avatar
Matthias Clasen committed
418

419
      g_object_set_qdata_full (G_OBJECT (drag), drag_icon_quark, g_object_ref_sink (self), g_object_unref);
Matthias Clasen's avatar
Matthias Clasen committed
420

421
422
      if (GTK_DRAG_ICON (self)->child != NULL)
        gtk_widget_show (self);
423
424
425
    }

  return self;
Matthias Clasen's avatar
Matthias Clasen committed
426
427
}

Matthias Clasen's avatar
Matthias Clasen committed
428
429
/**
 * gtk_drag_icon_set_from_paintable:
Matthias Clasen's avatar
Matthias Clasen committed
430
431
 * @drag: a `GdkDrag`
 * @paintable: a `GdkPaintable` to display
Matthias Clasen's avatar
Matthias Clasen committed
432
433
434
 * @hot_x: X coordinate of the hotspot
 * @hot_y: Y coordinate of the hotspot
 *
Matthias Clasen's avatar
Matthias Clasen committed
435
436
437
438
439
 * Creates a `GtkDragIcon` that shows @paintable, and associates
 * it with the drag operation.
 *
 * The hotspot position on the paintable is aligned with the
 * hotspot of the cursor.
Matthias Clasen's avatar
Matthias Clasen committed
440
 */
Matthias Clasen's avatar
Matthias Clasen committed
441
442
443
444
445
446
447
448
449
450
451
void
gtk_drag_icon_set_from_paintable (GdkDrag      *drag,
                                  GdkPaintable *paintable,
                                  int           hot_x,
                                  int           hot_y)
{
  GtkWidget *icon;
  GtkWidget *picture;

  gdk_drag_set_hotspot (drag, hot_x, hot_y);

452
  icon = gtk_drag_icon_get_for_drag (drag);
Matthias Clasen's avatar
Matthias Clasen committed
453
454
455

  picture = gtk_picture_new_for_paintable (paintable);
  gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
456
  gtk_drag_icon_set_child (GTK_DRAG_ICON (icon), picture);
Matthias Clasen's avatar
Matthias Clasen committed
457
458
}

459
/**
Matthias Clasen's avatar
Matthias Clasen committed
460
461
 * gtk_drag_icon_set_child: (attributes org.gtk.Method.set_property=child)
 * @self: a `GtkDragIcon`
Matthias Clasen's avatar
Matthias Clasen committed
462
 * @child: (nullable): a `GtkWidget`
463
464
 *
 * Sets the widget to display as the drag icon.
Matthias Clasen's avatar
Matthias Clasen committed
465
 */
Matthias Clasen's avatar
Matthias Clasen committed
466
void
467
468
gtk_drag_icon_set_child (GtkDragIcon *self,
                         GtkWidget   *child)
Matthias Clasen's avatar
Matthias Clasen committed
469
{
470
471
472
473
  g_return_if_fail (GTK_IS_DRAG_ICON (self));
  g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));

  if (self->child == child)
Matthias Clasen's avatar
Matthias Clasen committed
474
475
    return;

476
477
  if (self->child)
    gtk_widget_unparent (self->child);
Matthias Clasen's avatar
Matthias Clasen committed
478

479
  self->child = child;
Matthias Clasen's avatar
Matthias Clasen committed
480

481
  if (self->child)
482
483
484
485
    {
      gtk_widget_set_parent (self->child, GTK_WIDGET (self));
      gtk_widget_show (GTK_WIDGET (self));
    }
486
487
488
489
490

  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHILD]);
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
491
492
 * gtk_drag_icon_get_child: (attributes org.gtk.Method.get_property=child)
 * @self: a `GtkDragIcon`
493
494
495
 *
 * Gets the widget currently used as drag icon.
 *
Matthias Clasen's avatar
Matthias Clasen committed
496
 * Returns: (nullable) (transfer none): The drag icon
497
498
499
500
501
502
503
 **/
GtkWidget *
gtk_drag_icon_get_child (GtkDragIcon *self)
{
  g_return_val_if_fail (GTK_IS_DRAG_ICON (self), NULL);

  return self->child;
Matthias Clasen's avatar
Matthias Clasen committed
504
}
505

506
507
/**
 * gtk_drag_icon_create_widget_for_value:
Matthias Clasen's avatar
Matthias Clasen committed
508
 * @value: a `GValue`
509
510
511
512
 *
 * Creates a widget that can be used as a drag icon for the given
 * @value.
 *
Matthias Clasen's avatar
Matthias Clasen committed
513
 * Supported types include strings, `GdkRGBA` and `GtkTextBuffer`.
514
515
516
 * If GTK does not know how to create a widget for a given value,
 * it will return %NULL.
 *
Matthias Clasen's avatar
Matthias Clasen committed
517
 * This method is used to set the default drag icon on drag-and-drop
Matthias Clasen's avatar
Matthias Clasen committed
518
 * operations started by `GtkDragSource`, so you don't need to set
519
520
 * a drag icon using this function there.
 *
Matthias Clasen's avatar
Matthias Clasen committed
521
522
523
 * Returns: (nullable) (transfer full): A new `GtkWidget`
 *   for displaying @value as a drag icon.
 */
524
525
526
527
528
529
530
531
532
GtkWidget *
gtk_drag_icon_create_widget_for_value (const GValue *value)
{
  g_return_val_if_fail (G_IS_VALUE (value), NULL);

  if (G_VALUE_HOLDS (value, G_TYPE_STRING))
    {
      return gtk_label_new (g_value_get_string (value));
    }
533
534
535
536
537
538
539
540
541
  else if (G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE))
    {
      GtkWidget *image;

      image = gtk_image_new_from_paintable (g_value_get_object (value));
      gtk_widget_add_css_class (image, "large-icons");

      return image;
    }
542
543
544
545
546
  else if (G_VALUE_HOLDS (value, GDK_TYPE_RGBA))
    {
      GtkWidget *swatch;

      swatch = gtk_color_swatch_new ();
547
548
      gtk_color_swatch_set_can_drag (GTK_COLOR_SWATCH (swatch), FALSE);
      gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (swatch), FALSE);
549
550
551
552
      gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (swatch), g_value_get_boxed (value));

      return swatch;
    }
553
554
555
556
557
558
559
560
561
562
563
564
  else if (G_VALUE_HOLDS (value, G_TYPE_FILE))
    {
      GFileInfo *info;
      GtkWidget *image;

      info = g_file_query_info (G_FILE (g_value_get_object (value)), "standard::icon", 0, NULL, NULL);
      image = gtk_image_new_from_gicon (g_file_info_get_icon (info));
      gtk_widget_add_css_class (image, "large-icons");
      g_object_unref (info);

      return image;
    }
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  else if (G_VALUE_HOLDS (value, GTK_TYPE_TEXT_BUFFER))
    {
      GtkTextBuffer *buffer = g_value_get_object (value);
      GtkTextIter start, end;
      GdkPaintable *paintable;
      GtkWidget *picture;

      if (buffer == NULL || !gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
        return NULL;

      picture = gtk_picture_new ();
      paintable = gtk_text_util_create_rich_drag_icon (picture, buffer, &start, &end);
      gtk_picture_set_paintable (GTK_PICTURE (picture), paintable);
      gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
      g_object_unref (paintable);

      return picture;
    }
583
584
585
586
587
588
589
590
591
592
  else if (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE))
    {
      GskRenderNode *node;
      GdkPaintable *paintable;
      graphene_rect_t bounds;
      GtkWidget *image;

      node = gsk_value_get_render_node (value);
      if (node == NULL)
        return NULL;
Matthias Clasen's avatar
Matthias Clasen committed
593

594
595
596
597
598
599
600
601
      gsk_render_node_get_bounds (node, &bounds);
      paintable = gtk_render_node_paintable_new (node, &bounds);
      image = gtk_image_new_from_paintable (paintable);
      gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
      g_object_unref (paintable);

      return image;
    }
602
603
604
605
606
607
  else
    {
      return NULL;
    }
}