gtkimage.c 36.1 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2
3
4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6
7
8
9
10
11
 * 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
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17
18

/*
19
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20
21
22
23
24
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

25
#include "config.h"
26

Benjamin Otte's avatar
Benjamin Otte committed
27
#include "gtkimageprivate.h"
28

Cosimo Cecchi's avatar
Cosimo Cecchi committed
29
#include "gtkiconhelperprivate.h"
30
#include "gtkicontheme.h"
Havoc Pennington's avatar
Havoc Pennington committed
31
#include "gtkintl.h"
32
#include "gtkprivate.h"
Benjamin Otte's avatar
Benjamin Otte committed
33
#include "gtksnapshot.h"
34
#include "gtktypebuiltins.h"
35
#include "gtkwidgetprivate.h"
36
#include "gdkpixbufutilsprivate.h"
Elliot Lee's avatar
Elliot Lee committed
37

Benjamin Otte's avatar
Benjamin Otte committed
38
39
40
41
#include <math.h>
#include <string.h>
#include <cairo-gobject.h>

42
/**
43
 * GtkImage:
44
 *
45
46
 * The `GtkImage` widget displays an image.
 *
Matthias Clasen's avatar
Matthias Clasen committed
47
 * ![An example GtkImage](image.png)
48
49
50
51
52
53
 *
 * Various kinds of object can be displayed as an image; most typically,
 * you would load a `GdkTexture` from a file, using the convenience function
 * [ctor@Gtk.Image.new_from_file], for instance:
 *
 * ```c
54
 * GtkWidget *image = gtk_image_new_from_file ("myfile.png");
55
56
 * ```
 *
57
 * If the file isn’t loaded successfully, the image will contain a
William Jon McCann's avatar
William Jon McCann committed
58
 * “broken image” icon similar to that used in many web browsers.
59
 *
60
61
 * If you want to handle errors in loading the file yourself,
 * for example by displaying an error message, then load the image with
Matthias Clasen's avatar
Matthias Clasen committed
62
 * [ctor@Gdk.Texture.new_from_file], then create the `GtkImage` with
63
 * [ctor@Gtk.Image.new_from_paintable].
64
65
 *
 * Sometimes an application will want to avoid depending on external data
66
67
68
69
 * files, such as image files. See the documentation of `GResource` inside
 * GIO, for details. In this case, [property@Gtk.Image:resource],
 * [ctor@Gtk.Image.new_from_resource], and [method@Gtk.Image.set_from_resource]
 * should be used.
70
 *
71
72
73
 * `GtkImage` displays its image as an icon, with a size that is determined
 * by the application. See [class@Gtk.Picture] if you want to show an image
 * at is actual size.
Matthias Clasen's avatar
Matthias Clasen committed
74
 *
75
 * ## CSS nodes
76
 *
77
78
79
 * `GtkImage` has a single CSS node with the name `image`. The style classes
 * `.normal-icons` or `.large-icons` may appear, depending on the
 * [property@Gtk.Image:icon-size] property.
80
 *
81
 * ## Accessibility
82
 *
83
 * `GtkImage` uses the `GTK_ACCESSIBLE_ROLE_IMG` role.
84
85
 */

Matthias Clasen's avatar
Matthias Clasen committed
86
87
88
89
90
91
typedef struct _GtkImageClass GtkImageClass;

struct _GtkImage
{
  GtkWidget parent_instance;

92
  GtkIconHelper *icon_helper;
93
  GtkIconSize icon_size;
Cosimo Cecchi's avatar
Cosimo Cecchi committed
94

95
  float baseline_align;
96

97
98
  char *filename;
  char *resource_path;
99
100
101
102
103
104
105
};

struct _GtkImageClass
{
  GtkWidgetClass parent_class;
};

106

107
108
static void gtk_image_snapshot             (GtkWidget    *widget,
                                            GtkSnapshot  *snapshot);
109
static void gtk_image_unrealize            (GtkWidget    *widget);
110
111
112
113
114
115
116
static void gtk_image_measure (GtkWidget      *widget,
                               GtkOrientation  orientation,
                               int            for_size,
                               int           *minimum,
                               int           *natural,
                               int           *minimum_baseline,
                               int           *natural_baseline);
Matthias Clasen's avatar
Matthias Clasen committed
117

118
119
static void gtk_image_css_changed          (GtkWidget    *widget,
                                            GtkCssStyleChange *change);
120
static void gtk_image_system_setting_changed (GtkWidget        *widget,
121
                                              GtkSystemSetting  setting);
122
static void gtk_image_finalize             (GObject      *object);
123
124
125
126
127
128
129
130
131
132

static void gtk_image_set_property         (GObject      *object,
                                            guint         prop_id,
                                            const GValue *value,
                                            GParamSpec   *pspec);
static void gtk_image_get_property         (GObject      *object,
                                            guint         prop_id,
                                            GValue       *value,
                                            GParamSpec   *pspec);

Havoc Pennington's avatar
Havoc Pennington committed
133
134
135
enum
{
  PROP_0,
136
  PROP_PAINTABLE,
Havoc Pennington's avatar
Havoc Pennington committed
137
138
  PROP_FILE,
  PROP_ICON_SIZE,
139
140
  PROP_PIXEL_SIZE,
  PROP_ICON_NAME,
141
  PROP_STORAGE_TYPE,
142
  PROP_GICON,
143
  PROP_RESOURCE,
144
145
  PROP_USE_FALLBACK,
  NUM_PROPERTIES
Havoc Pennington's avatar
Havoc Pennington committed
146
147
};

148
149
static GParamSpec *image_props[NUM_PROPERTIES] = { NULL, };

150
G_DEFINE_TYPE (GtkImage, gtk_image, GTK_TYPE_WIDGET)
Elliot Lee's avatar
Elliot Lee committed
151
152
153
154

static void
gtk_image_class_init (GtkImageClass *class)
{
Havoc Pennington's avatar
Havoc Pennington committed
155
  GObjectClass *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
156
157
  GtkWidgetClass *widget_class;

Havoc Pennington's avatar
Havoc Pennington committed
158
  gobject_class = G_OBJECT_CLASS (class);
159

Havoc Pennington's avatar
Havoc Pennington committed
160
161
  gobject_class->set_property = gtk_image_set_property;
  gobject_class->get_property = gtk_image_get_property;
162
  gobject_class->finalize = gtk_image_finalize;
163

Havoc Pennington's avatar
Havoc Pennington committed
164
  widget_class = GTK_WIDGET_CLASS (class);
165
  widget_class->snapshot = gtk_image_snapshot;
166
  widget_class->measure = gtk_image_measure;
167
  widget_class->unrealize = gtk_image_unrealize;
168
  widget_class->css_changed = gtk_image_css_changed;
169
  widget_class->system_setting_changed = gtk_image_system_setting_changed;
170

Matthias Clasen's avatar
Matthias Clasen committed
171
  /**
172
   * GtkImage:paintable: (attributes org.gtk.Property.get=gtk_image_get_paintable org.gtk.Property.set=gtk_image_set_from_paintable)
Matthias Clasen's avatar
Matthias Clasen committed
173
174
175
   *
   * The `GdkPaintable` to display.
   */
176
177
178
179
180
181
182
  image_props[PROP_PAINTABLE] =
      g_param_spec_object ("paintable",
                           P_("Paintable"),
                           P_("A GdkPaintable to display"),
                           GDK_TYPE_PAINTABLE,
                           GTK_PARAM_READWRITE);

Matthias Clasen's avatar
Matthias Clasen committed
183
  /**
184
   * GtkImage:file: (attributes org.gtk.Property.set=gtk_image_set_from_file)
Matthias Clasen's avatar
Matthias Clasen committed
185
186
187
   *
   * The `GFile to display.
   */
188
189
190
191
192
193
  image_props[PROP_FILE] =
      g_param_spec_string ("file",
                           P_("Filename"),
                           P_("Filename to load and display"),
                           NULL,
                           GTK_PARAM_READWRITE);
Havoc Pennington's avatar
Havoc Pennington committed
194

Matthias Clasen's avatar
Matthias Clasen committed
195
  /**
196
   * GtkImage:icon-size: (attributes org.gtk.Property.get=gtk_image_get_icon_size org.gtk.Property.set=gtk_image_set_icon_size org.gtk.Property.set=gtk_image_set_icon_size)
Matthias Clasen's avatar
Matthias Clasen committed
197
198
199
   *
   * The symbolic size to display icons at.
   */
200
  image_props[PROP_ICON_SIZE] =
Matthias Clasen's avatar
Matthias Clasen committed
201
202
203
204
205
206
      g_param_spec_enum ("icon-size",
                         P_("Icon size"),
                         P_("Symbolic size to use for icon set or named icon"),
                         GTK_TYPE_ICON_SIZE,
                         GTK_ICON_SIZE_INHERIT,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
207

208
  /**
209
   * GtkImage:pixel-size: (attributes org.gtk.Property.get=gtk_image_get_pixel_size org.gtk.Property.set=gtk_image_set_pixel_size)
210
   *
Matthias Clasen's avatar
Matthias Clasen committed
211
212
213
214
215
   * The size in pixels to display icons at.
   *
   * If set to a value != -1, this property overrides the
   * [property@Gtk.Image:icon-size] property for images of type
   * `GTK_IMAGE_ICON_NAME`.
216
   */
217
218
219
220
221
222
223
224
  image_props[PROP_PIXEL_SIZE] =
      g_param_spec_int ("pixel-size",
                        P_("Pixel size"),
                        P_("Pixel size to use for named icon"),
                        -1, G_MAXINT,
                        -1,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

225
  /**
226
   * GtkImage:icon-name: (attributes org.gtk.Property.get=gtk_image_get_icon_name org.gtk.Property.set=gtk_image_set_from_icon_name)
227
   *
Matthias Clasen's avatar
Matthias Clasen committed
228
229
230
   * The name of the icon in the icon theme.
   *
   * If the icon theme is changed, the image will be updated automatically.
231
   */
232
233
234
235
236
237
238
  image_props[PROP_ICON_NAME] =
      g_param_spec_string ("icon-name",
                           P_("Icon Name"),
                           P_("The name of the icon from the icon theme"),
                           NULL,
                           GTK_PARAM_READWRITE);

239
  /**
240
   * GtkImage:gicon: (attributes org.gtk.Property.get=gtk_image_get_gicon org.gtk.Property.set=gtk_image_set_from_gicon)
241
   *
Matthias Clasen's avatar
Matthias Clasen committed
242
243
244
   * The `GIcon` displayed in the GtkImage.
   *
   * For themed icons, If the icon theme is changed, the image will be updated
245
246
   * automatically.
   */
247
248
249
250
251
252
  image_props[PROP_GICON] =
      g_param_spec_object ("gicon",
                           P_("Icon"),
                           P_("The GIcon being displayed"),
                           G_TYPE_ICON,
                           GTK_PARAM_READWRITE);
253
254

  /**
255
   * GtkImage:resource: (attributes org.gtk.Property.set=gtk_image_set_from_resource)
256
257
258
   *
   * A path to a resource file to display.
   */
259
260
261
262
263
264
265
  image_props[PROP_RESOURCE] =
      g_param_spec_string ("resource",
                           P_("Resource"),
                           P_("The resource path being displayed"),
                           NULL,
                           GTK_PARAM_READWRITE);

Matthias Clasen's avatar
Matthias Clasen committed
266
  /**
267
   * GtkImage:storage-type: (attributes org.gtk.Property.get=gtk_image_get_storage_type)
Matthias Clasen's avatar
Matthias Clasen committed
268
269
270
   *
   * The representation being used for image data.
   */
271
272
273
274
275
276
277
  image_props[PROP_STORAGE_TYPE] =
      g_param_spec_enum ("storage-type",
                         P_("Storage type"),
                         P_("The representation being used for image data"),
                         GTK_TYPE_IMAGE_TYPE,
                         GTK_IMAGE_EMPTY,
                         GTK_PARAM_READABLE);
278

279
280
281
  /**
   * GtkImage:use-fallback:
   *
Matthias Clasen's avatar
Matthias Clasen committed
282
283
284
285
286
   * Whether the icon displayed in the `GtkImage` will use
   * standard icon names fallback.
   *
   * The value of this property is only relevant for images of type
   * %GTK_IMAGE_ICON_NAME and %GTK_IMAGE_GICON.
287
   */
288
289
290
291
292
293
294
295
  image_props[PROP_USE_FALLBACK] =
      g_param_spec_boolean ("use-fallback",
                            P_("Use Fallback"),
                            P_("Whether to use icon names fallback"),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (gobject_class, NUM_PROPERTIES, image_props);
296

Matthias Clasen's avatar
Matthias Clasen committed
297
  gtk_widget_class_set_css_name (widget_class, I_("image"));
298
299

  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_IMG);
Elliot Lee's avatar
Elliot Lee committed
300
301
302
303
304
}

static void
gtk_image_init (GtkImage *image)
{
Matthias Clasen's avatar
Matthias Clasen committed
305
  GtkCssNode *widget_node;
306

307
308
  widget_node = gtk_widget_get_css_node (GTK_WIDGET (image));

309
  image->icon_helper = gtk_icon_helper_new (widget_node, GTK_WIDGET (image));
Elliot Lee's avatar
Elliot Lee committed
310
311
}

312
static void
313
gtk_image_finalize (GObject *object)
314
{
315
  GtkImage *image = GTK_IMAGE (object);
316

317
318
  gtk_image_clear (image);

319
  g_clear_object (&image->icon_helper);
Matthias Clasen's avatar
Matthias Clasen committed
320

321
322
  g_free (image->filename);
  g_free (image->resource_path);
Dan Vrátil's avatar
Dan Vrátil committed
323

324
325
  G_OBJECT_CLASS (gtk_image_parent_class)->finalize (object);
};
326

Matthias Clasen's avatar
Matthias Clasen committed
327
static void
Havoc Pennington's avatar
Havoc Pennington committed
328
329
330
331
332
gtk_image_set_property (GObject      *object,
			guint         prop_id,
			const GValue *value,
			GParamSpec   *pspec)
{
333
  GtkImage *image = GTK_IMAGE (object);
334

Havoc Pennington's avatar
Havoc Pennington committed
335
336
  switch (prop_id)
    {
337
338
339
    case PROP_PAINTABLE:
      gtk_image_set_from_paintable (image, g_value_get_object (value));
      break;
Havoc Pennington's avatar
Havoc Pennington committed
340
    case PROP_FILE:
341
      gtk_image_set_from_file (image, g_value_get_string (value));
Havoc Pennington's avatar
Havoc Pennington committed
342
343
      break;
    case PROP_ICON_SIZE:
Matthias Clasen's avatar
Matthias Clasen committed
344
      gtk_image_set_icon_size (image, g_value_get_enum (value));
Havoc Pennington's avatar
Havoc Pennington committed
345
      break;
346
    case PROP_PIXEL_SIZE:
347
      gtk_image_set_pixel_size (image, g_value_get_int (value));
348
349
      break;
    case PROP_ICON_NAME:
350
      gtk_image_set_from_icon_name (image, g_value_get_string (value));
351
      break;
352
    case PROP_GICON:
353
      gtk_image_set_from_gicon (image, g_value_get_object (value));
354
      break;
355
356
357
    case PROP_RESOURCE:
      gtk_image_set_from_resource (image, g_value_get_string (value));
      break;
358

359
    case PROP_USE_FALLBACK:
360
      if (_gtk_icon_helper_set_use_fallback (image->icon_helper, g_value_get_boolean (value)))
361
        g_object_notify_by_pspec (object, pspec);
362
363
      break;

Havoc Pennington's avatar
Havoc Pennington committed
364
365
366
367
368
369
370
371
372
373
374
375
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void 
gtk_image_get_property (GObject     *object,
			guint        prop_id,
			GValue      *value,
			GParamSpec  *pspec)
{
376
  GtkImage *image = GTK_IMAGE (object);
Havoc Pennington's avatar
Havoc Pennington committed
377
378
379

  switch (prop_id)
    {
380
    case PROP_PAINTABLE:
381
      g_value_set_object (value, _gtk_icon_helper_peek_paintable (image->icon_helper));
382
      break;
383
    case PROP_FILE:
384
      g_value_set_string (value, image->filename);
385
      break;
Havoc Pennington's avatar
Havoc Pennington committed
386
    case PROP_ICON_SIZE:
387
      g_value_set_enum (value, image->icon_size);
Havoc Pennington's avatar
Havoc Pennington committed
388
      break;
389
    case PROP_PIXEL_SIZE:
390
      g_value_set_int (value, _gtk_icon_helper_get_pixel_size (image->icon_helper));
391
392
      break;
    case PROP_ICON_NAME:
393
      g_value_set_string (value, _gtk_icon_helper_get_icon_name (image->icon_helper));
394
      break;
395
    case PROP_GICON:
396
      g_value_set_object (value, _gtk_icon_helper_peek_gicon (image->icon_helper));
Havoc Pennington's avatar
Havoc Pennington committed
397
      break;
398
    case PROP_RESOURCE:
399
      g_value_set_string (value, image->resource_path);
400
      break;
401
    case PROP_USE_FALLBACK:
402
      g_value_set_boolean (value, _gtk_icon_helper_get_use_fallback (image->icon_helper));
403
      break;
404
    case PROP_STORAGE_TYPE:
405
      g_value_set_enum (value, _gtk_icon_helper_get_storage_type (image->icon_helper));
406
      break;
Havoc Pennington's avatar
Havoc Pennington committed
407
408
409
410
411
412
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

413

414
415
/**
 * gtk_image_new_from_file:
416
 * @filename: (type filename): a filename
Matthias Clasen's avatar
Matthias Clasen committed
417
418
419
420
421
422
 *
 * Creates a new `GtkImage` displaying the file @filename.
 *
 * If the file isn’t found or can’t be loaded, the resulting `GtkImage`
 * will display a “broken image” icon. This function never returns %NULL,
 * it always returns a valid `GtkImage` widget.
Havoc Pennington's avatar
Havoc Pennington committed
423
424
 *
 * If you need to detect failures to load the file, use
Matthias Clasen's avatar
Matthias Clasen committed
425
426
427
428
429
430
431
432
433
 * [ctor@Gdk.Texture.new_from_file] to load the file yourself,
 * then create the `GtkImage` from the texture.
 *
 * The storage type (see [method@Gtk.Image.get_storage_type])
 * of the returned image is not defined, it will be whatever
 * is appropriate for displaying the file.
 *
 * Returns: a new `GtkImage`
 */
434
GtkWidget*
Benjamin Otte's avatar
Benjamin Otte committed
435
gtk_image_new_from_file   (const char *filename)
436
437
438
{
  GtkImage *image;

Manish Singh's avatar
Manish Singh committed
439
  image = g_object_new (GTK_TYPE_IMAGE, NULL);
440
441
442
443
444
445

  gtk_image_set_from_file (image, filename);

  return GTK_WIDGET (image);
}

446
447
448
449
/**
 * gtk_image_new_from_resource:
 * @resource_path: a resource path
 *
Matthias Clasen's avatar
Matthias Clasen committed
450
451
452
 * Creates a new `GtkImage` displaying the resource file @resource_path.
 *
 * If the file isn’t found or can’t be loaded, the resulting `GtkImage` will
William Jon McCann's avatar
William Jon McCann committed
453
 * display a “broken image” icon. This function never returns %NULL,
Matthias Clasen's avatar
Matthias Clasen committed
454
 * it always returns a valid `GtkImage` widget.
455
456
 *
 * If you need to detect failures to load the file, use
Matthias Clasen's avatar
Matthias Clasen committed
457
458
 * [ctor@GdkPixbuf.Pixbuf.new_from_file] to load the file yourself,
 * then create the `GtkImage` from the pixbuf.
459
 *
Matthias Clasen's avatar
Matthias Clasen committed
460
461
462
 * The storage type (see [method@Gtk.Image.get_storage_type]) of
 * the returned image is not defined, it will be whatever is
 * appropriate for displaying the file.
463
 *
Matthias Clasen's avatar
Matthias Clasen committed
464
465
 * Returns: a new `GtkImage`
 */
466
GtkWidget*
Benjamin Otte's avatar
Benjamin Otte committed
467
gtk_image_new_from_resource (const char *resource_path)
468
469
470
471
472
473
474
475
476
477
{
  GtkImage *image;

  image = g_object_new (GTK_TYPE_IMAGE, NULL);

  gtk_image_set_from_resource (image, resource_path);

  return GTK_WIDGET (image);
}

478
479
/**
 * gtk_image_new_from_pixbuf:
Matthias Clasen's avatar
Matthias Clasen committed
480
 * @pixbuf: (nullable): a `GdkPixbuf`
Matthias Clasen's avatar
Matthias Clasen committed
481
482
 *
 * Creates a new `GtkImage` displaying @pixbuf.
483
 *
Matthias Clasen's avatar
Matthias Clasen committed
484
485
486
 * The `GtkImage` does not assume a reference to the pixbuf; you still
 * need to unref it if you own references. `GtkImage` will add its own
 * reference rather than adopting yours.
487
 *
Matthias Clasen's avatar
Matthias Clasen committed
488
 * This is a helper for [ctor@Gtk.Image.new_from_paintable], and you can't
489
 * get back the exact pixbuf once this is called, only a texture.
490
 *
Matthias Clasen's avatar
Matthias Clasen committed
491
492
493
494
495
496
 * Note that this function just creates an `GtkImage` from the pixbuf.
 * The `GtkImage` created will not react to state changes. Should you
 * want that, you should use [ctor@Gtk.Image.new_from_icon_name].
 *
 * Returns: a new `GtkImage`
 */
497
498
499
500
501
GtkWidget*
gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
{
  GtkImage *image;

Manish Singh's avatar
Manish Singh committed
502
  image = g_object_new (GTK_TYPE_IMAGE, NULL);
503
504
505
506
507
508

  gtk_image_set_from_pixbuf (image, pixbuf);

  return GTK_WIDGET (image);  
}

509
510
/**
 * gtk_image_new_from_paintable:
Matthias Clasen's avatar
Matthias Clasen committed
511
 * @paintable: (nullable): a `GdkPaintable`
512
 *
Matthias Clasen's avatar
Matthias Clasen committed
513
 * Creates a new `GtkImage` displaying @paintable.
514
 *
Matthias Clasen's avatar
Matthias Clasen committed
515
516
517
518
519
 * The `GtkImage` does not assume a reference to the paintable; you still
 * need to unref it if you own references. `GtkImage` will add its own
 * reference rather than adopting yours.
 *
 * The `GtkImage` will track changes to the @paintable and update
520
521
 * its size and contents in response to it.
 *
Matthias Clasen's avatar
Matthias Clasen committed
522
523
 * Returns: a new `GtkImage`
 */
524
525
526
527
528
529
530
531
532
533
534
535
GtkWidget*
gtk_image_new_from_paintable (GdkPaintable *paintable)
{
  GtkImage *image;

  image = g_object_new (GTK_TYPE_IMAGE, NULL);

  gtk_image_set_from_paintable (image, paintable);

  return GTK_WIDGET (image);  
}

536
537
/**
 * gtk_image_new_from_icon_name:
Matthias Clasen's avatar
Matthias Clasen committed
538
 * @icon_name: (nullable): an icon name
Matthias Clasen's avatar
Matthias Clasen committed
539
540
541
 *
 * Creates a `GtkImage` displaying an icon from the current icon theme.
 *
542
 * If the icon name isn’t known, a “broken image” icon will be
Matthias Clasen's avatar
Matthias Clasen committed
543
 * displayed instead. If the current icon theme is changed, the icon
544
 * will be updated appropriately.
Matthias Clasen's avatar
Matthias Clasen committed
545
 *
Matthias Clasen's avatar
Matthias Clasen committed
546
547
 * Returns: a new `GtkImage` displaying the themed icon
 */
548
GtkWidget*
Benjamin Otte's avatar
Benjamin Otte committed
549
gtk_image_new_from_icon_name (const char *icon_name)
550
551
552
553
554
{
  GtkImage *image;

  image = g_object_new (GTK_TYPE_IMAGE, NULL);

555
  gtk_image_set_from_icon_name (image, icon_name);
556
557
558
559

  return GTK_WIDGET (image);
}

560
561
562
/**
 * gtk_image_new_from_gicon:
 * @icon: an icon
Matthias Clasen's avatar
Matthias Clasen committed
563
564
565
 *
 * Creates a `GtkImage` displaying an icon from the current icon theme.
 *
566
 * If the icon name isn’t known, a “broken image” icon will be
Matthias Clasen's avatar
Matthias Clasen committed
567
 * displayed instead. If the current icon theme is changed, the icon
568
 * will be updated appropriately.
Matthias Clasen's avatar
Matthias Clasen committed
569
 *
Matthias Clasen's avatar
Matthias Clasen committed
570
571
 * Returns: a new `GtkImage` displaying the themed icon
 */
572
GtkWidget*
573
gtk_image_new_from_gicon (GIcon *icon)
574
575
576
577
578
{
  GtkImage *image;

  image = g_object_new (GTK_TYPE_IMAGE, NULL);

579
  gtk_image_set_from_gicon (image, icon);
580
581
582
583

  return GTK_WIDGET (image);
}

584
/**
585
 * gtk_image_set_from_file: (attributes org.gtk.Method.set_property=file)
Matthias Clasen's avatar
Matthias Clasen committed
586
 * @image: a `GtkImage`
Matthias Clasen's avatar
Matthias Clasen committed
587
 * @filename: (type filename) (nullable): a filename
588
 *
Matthias Clasen's avatar
Matthias Clasen committed
589
590
591
592
 * Sets a `GtkImage` to show a file.
 *
 * See [ctor@Gtk.Image.new_from_file] for details.
 */
593
void
594
595
gtk_image_set_from_file (GtkImage    *image,
                         const char *filename)
596
{
Benjamin Otte's avatar
Benjamin Otte committed
597
  int scale_factor;
598
  GdkPaintable *paintable;
599

600
  g_return_if_fail (GTK_IS_IMAGE (image));
Havoc Pennington's avatar
Havoc Pennington committed
601
602

  g_object_freeze_notify (G_OBJECT (image));
603

604
  gtk_image_clear (image);
605
606

  if (filename == NULL)
Havoc Pennington's avatar
Havoc Pennington committed
607
    {
608
      image->filename = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
609
610
611
      g_object_thaw_notify (G_OBJECT (image));
      return;
    }
612

613
614
  scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (image));
  paintable = gdk_paintable_new_from_path_scaled (filename, scale_factor);
615

616
  if (paintable == NULL)
617
    {
618
      gtk_image_set_from_icon_name (image, "image-missing");
Havoc Pennington's avatar
Havoc Pennington committed
619
      g_object_thaw_notify (G_OBJECT (image));
620
621
      return;
    }
622

623
  gtk_image_set_from_paintable (image, paintable);
624

625
  g_object_unref (paintable);
Havoc Pennington's avatar
Havoc Pennington committed
626

627
  image->filename = g_strdup (filename);
628

Havoc Pennington's avatar
Havoc Pennington committed
629
  g_object_thaw_notify (G_OBJECT (image));
630
631
}

632
633
634
635
636
#ifndef GDK_PIXBUF_MAGIC_NUMBER
#define GDK_PIXBUF_MAGIC_NUMBER (0x47646b50)    /* 'GdkP' */
#endif

static gboolean
Benjamin Otte's avatar
Benjamin Otte committed
637
resource_is_pixdata (const char *resource_path)
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
{
  const guint8 *stream;
  guint32 magic;
  gsize data_size;
  GBytes *bytes;
  gboolean ret = FALSE;

  bytes = g_resources_lookup_data (resource_path, 0, NULL);
  if (bytes == NULL)
    return FALSE;

  stream = g_bytes_get_data (bytes, &data_size);
  if (data_size < sizeof(guint32))
    goto out;

  magic = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
  if (magic == GDK_PIXBUF_MAGIC_NUMBER)
    ret = TRUE;

out:
  g_bytes_unref (bytes);
  return ret;
}

662
/**
663
 * gtk_image_set_from_resource: (attributes org.gtk.Method.set_property=resource)
Matthias Clasen's avatar
Matthias Clasen committed
664
 * @image: a `GtkImage`
Matthias Clasen's avatar
Matthias Clasen committed
665
 * @resource_path: (nullable): a resource path
666
 *
Matthias Clasen's avatar
Matthias Clasen committed
667
668
669
670
 * Sets a `GtkImage` to show a resource.
 *
 * See [ctor@Gtk.Image.new_from_resource] for details.
 */
671
void
672
673
gtk_image_set_from_resource (GtkImage   *image,
                             const char *resource_path)
674
{
675
676
  int scale_factor;
  GdkPaintable *paintable;
677
678
679
680
681
682
683
684
685
686
687
688
689

  g_return_if_fail (GTK_IS_IMAGE (image));

  g_object_freeze_notify (G_OBJECT (image));

  gtk_image_clear (image);

  if (resource_path == NULL)
    {
      g_object_thaw_notify (G_OBJECT (image));
      return;
    }

690
691
692
  if (resource_is_pixdata (resource_path))
    {
      g_warning ("GdkPixdata format images are not supported, remove the \"to-pixdata\" option from your GResource files");
693
      paintable = NULL;
694
695
696
    }
  else
    {
697
698
      scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (image));
      paintable = gdk_paintable_new_from_resource_scaled (resource_path, scale_factor);
699
    }
700

701
  if (paintable == NULL)
702
    {
703
      gtk_image_set_from_icon_name (image, "image-missing");
704
705
706
707
      g_object_thaw_notify (G_OBJECT (image));
      return;
    }

708
  gtk_image_set_from_paintable (image, paintable);
709

710
  g_object_unref (paintable);
711

712
  image->resource_path = g_strdup (resource_path);
713

714
  g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_RESOURCE]);
715

716
717
718
719
  g_object_thaw_notify (G_OBJECT (image));
}


720
/**
721
 * gtk_image_set_from_pixbuf: (attributes org.gtk.Method.set_property=paintable)
Matthias Clasen's avatar
Matthias Clasen committed
722
 * @image: a `GtkImage`
723
 * @pixbuf: (nullable): a `GdkPixbuf` or `NULL`
724
 *
725
 * Sets a `GtkImage` to show a `GdkPixbuf`.
726
 *
Matthias Clasen's avatar
Matthias Clasen committed
727
728
729
730
731
732
 * See [ctor@Gtk.Image.new_from_pixbuf] for details.
 *
 * Note: This is a helper for [method@Gtk.Image.set_from_paintable],
 * and you can't get back the exact pixbuf once this is called,
 * only a paintable.
 */
733
734
735
736
void
gtk_image_set_from_pixbuf (GtkImage  *image,
                           GdkPixbuf *pixbuf)
{
737
  GdkTexture *texture;
738

739
  g_return_if_fail (GTK_IS_IMAGE (image));
740
  g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
741

742
  if (pixbuf)
743
744
745
    texture = gdk_texture_new_for_pixbuf (pixbuf);
  else
    texture = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
746

747
  gtk_image_set_from_paintable (image, GDK_PAINTABLE (texture));
748

749
750
  if (texture)
    g_object_unref (texture);
751
752
}

753
/**
754
 * gtk_image_set_from_icon_name: (attributes org.gtk.Method.set_property=icon-name)
Matthias Clasen's avatar
Matthias Clasen committed
755
 * @image: a `GtkImage`
Matthias Clasen's avatar
Matthias Clasen committed
756
 * @icon_name: (nullable): an icon name
757
 *
Matthias Clasen's avatar
Matthias Clasen committed
758
 * Sets a `GtkImage` to show a named icon.
759
 *
Matthias Clasen's avatar
Matthias Clasen committed
760
761
 * See [ctor@Gtk.Image.new_from_icon_name] for details.
 */
762
void
763
gtk_image_set_from_icon_name  (GtkImage    *image,
Benjamin Otte's avatar
Benjamin Otte committed
764
			       const char *icon_name)
765
766
767
768
769
{
  g_return_if_fail (GTK_IS_IMAGE (image));

  g_object_freeze_notify (G_OBJECT (image));

770
  gtk_image_clear (image);
771

772
  if (icon_name)
773
    _gtk_icon_helper_set_icon_name (image->icon_helper, icon_name);
774

775
  g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_ICON_NAME]);
776

777
778
779
  g_object_thaw_notify (G_OBJECT (image));
}

780
/**
781
 * gtk_image_set_from_gicon: (attributes org.gtk.Method.set_property=gicon)
Matthias Clasen's avatar
Matthias Clasen committed
782
 * @image: a `GtkImage`
783
784
 * @icon: an icon
 *
Matthias Clasen's avatar
Matthias Clasen committed
785
 * Sets a `GtkImage` to show a `GIcon`.
786
 *
Matthias Clasen's avatar
Matthias Clasen committed
787
788
 * See [ctor@Gtk.Image.new_from_gicon] for details.
 */
789
790
void
gtk_image_set_from_gicon  (GtkImage       *image,
791
			   GIcon          *icon)
792
793
794
795
796
797
798
{
  g_return_if_fail (GTK_IS_IMAGE (image));

  g_object_freeze_notify (G_OBJECT (image));

  if (icon)
    g_object_ref (icon);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
799

800
  gtk_image_clear (image);
801
802
803

  if (icon)
    {
804
      _gtk_icon_helper_set_gicon (image->icon_helper, icon);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
805
      g_object_unref (icon);
806
807
    }

808
  g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_GICON]);
809
  
810
811
812
  g_object_thaw_notify (G_OBJECT (image));
}

813
814
815
816
817
818
819
820
821
822
823
static void
gtk_image_paintable_invalidate_contents (GdkPaintable *paintable,
                                         GtkImage     *image)
{
  gtk_widget_queue_draw (GTK_WIDGET (image));
}

static void
gtk_image_paintable_invalidate_size (GdkPaintable *paintable,
                                     GtkImage     *image)
{
824
  gtk_icon_helper_invalidate (image->icon_helper);
825
826
827
}

/**
828
 * gtk_image_set_from_paintable: (attributes org.gtk.Method.set_property=paintable)
Matthias Clasen's avatar
Matthias Clasen committed
829
 * @image: a `GtkImage`
Matthias Clasen's avatar
Matthias Clasen committed
830
 * @paintable: (nullable): a `GdkPaintable`
831
 *
Matthias Clasen's avatar
Matthias Clasen committed
832
833
834
835
 * Sets a `GtkImage` to show a `GdkPaintable`.
 *
 * See [ctor@Gtk.Image.new_from_paintable] for details.
 */
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
void
gtk_image_set_from_paintable (GtkImage     *image,
			      GdkPaintable *paintable)
{
  g_return_if_fail (GTK_IS_IMAGE (image));
  g_return_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable));

  g_object_freeze_notify (G_OBJECT (image));

  if (paintable)
    g_object_ref (paintable);

  gtk_image_clear (image);

  if (paintable)
    {
852
853
      const guint flags = gdk_paintable_get_flags (paintable);

854
      _gtk_icon_helper_set_paintable (image->icon_helper, paintable);
855
856
857
858
859
860
861
862
863
864
865
866

      if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
        g_signal_connect (paintable,
                          "invalidate-contents",
                          G_CALLBACK (gtk_image_paintable_invalidate_contents),
                          image);

      if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0)
        g_signal_connect (paintable,
                          "invalidate-size",
                          G_CALLBACK (gtk_image_paintable_invalidate_size),
                          image);
867
868
869
870
871
872
873
874
      g_object_unref (paintable);
    }

  g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_PAINTABLE]);
  
  g_object_thaw_notify (G_OBJECT (image));
}

875
/**
876
 * gtk_image_get_storage_type: (attributes org.gtk.Method.get_property=storage-type)
Matthias Clasen's avatar
Matthias Clasen committed
877
878
879
880
881
882
883
884
 * @image: a `GtkImage`
 *
 * Gets the type of representation being used by the `GtkImage`
 * to store image data.
 *
 * If the `GtkImage` has no image data, the return value will
 * be %GTK_IMAGE_EMPTY.
 *
885
 * Returns: image representation being used
Matthias Clasen's avatar
Matthias Clasen committed
886
 */
887
888
889
890
891
GtkImageType
gtk_image_get_storage_type (GtkImage *image)
{
  g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);

892
  return _gtk_icon_helper_get_storage_type (image->icon_helper);
893
894
}

895
/**
896
 * gtk_image_get_paintable: (attributes org.gtk.Method.get_property=paintable)
Matthias Clasen's avatar
Matthias Clasen committed
897
898
899
 * @image: a `GtkImage`
 *
 * Gets the image `GdkPaintable` being displayed by the `GtkImage`.
900
901
 *
 * The storage type of the image must be %GTK_IMAGE_EMPTY or
Matthias Clasen's avatar
Matthias Clasen committed
902
 * %GTK_IMAGE_PAINTABLE (see [method@Gtk.Image.get_storage_type]).
903
904
 * The caller of this function does not own a reference to the
 * returned paintable.
Matthias Clasen's avatar
Matthias Clasen committed
905
 *
Matthias Clasen's avatar
Matthias Clasen committed
906
 * Returns: (nullable) (transfer none): the displayed paintable
Matthias Clasen's avatar
Matthias Clasen committed
907
 */
908
909
910
911
912
GdkPaintable *
gtk_image_get_paintable (GtkImage *image)
{
  g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);

913
  return _gtk_icon_helper_peek_paintable (image->icon_helper);
914
915
}

916
/**
917
 * gtk_image_get_icon_name: (attributes org.gtk.Method.get_property=icon-name)
Matthias Clasen's avatar
Matthias Clasen committed
918
919
920
 * @image: a `GtkImage`
 *
 * Gets the icon name and size being displayed by the `GtkImage`.
921
922
 *
 * The storage type of the image must be %GTK_IMAGE_EMPTY or
Matthias Clasen's avatar
Matthias Clasen committed
923
924
 * %GTK_IMAGE_ICON_NAME (see [method@Gtk.Image.get_storage_type]).
 * The returned string is owned by the `GtkImage` and should not
925
 * be freed.
Benjamin Otte's avatar
Benjamin Otte committed
926
 *
Matthias Clasen's avatar
Matthias Clasen committed
927
 * Returns: (transfer none) (nullable): the icon name
Matthias Clasen's avatar
Matthias Clasen committed
928
 */
Benjamin Otte's avatar
Benjamin Otte committed
929
const char *
Benjamin Otte's avatar
Benjamin Otte committed
930
gtk_image_get_icon_name (GtkImage *image)
931
{
Benjamin Otte's avatar
Benjamin Otte committed
932
  g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
933

934
  return _gtk_icon_helper_get_icon_name (image->icon_helper);
935
936
}

937
/**
938
 * gtk_image_get_gicon: (attributes org.gtk.Method.get_property=gicon)
Matthias Clasen's avatar
Matthias Clasen committed
939
940
941
 * @image: a `GtkImage`
 *
 * Gets the `GIcon` being displayed by the `GtkImage`.
942
943
 *
 * The storage type of the image must be %GTK_IMAGE_EMPTY or
Matthias Clasen's avatar
Matthias Clasen committed
944
 * %GTK_IMAGE_GICON (see [method@Gtk.Image.get_storage_type]).
945
 * The caller of this function does not own a reference to the
Matthias Clasen's avatar
Matthias Clasen committed
946
 * returned `GIcon`.
Matthias Clasen's avatar
Matthias Clasen committed
947
 *
Matthias Clasen's avatar
Matthias Clasen committed
948
 * Returns: (transfer none) (nullable): a `GIcon`
949
 **/
Benjamin Otte's avatar
Benjamin Otte committed
950
951
GIcon *
gtk_image_get_gicon (GtkImage *image)
952
{
Benjamin Otte's avatar
Benjamin Otte committed
953
  g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
954

955
  return _gtk_icon_helper_peek_gicon (image->icon_helper);
956
957
}

958
959
/**
 * gtk_image_new:
Matthias Clasen's avatar
Matthias Clasen committed
960
961
962
963
964
 *
 * Creates a new empty `GtkImage` widget.
 *
 * Returns: a newly created `GtkImage` widget.
 */
965
GtkWidget*
966
gtk_image_new (void)
967
{
968
  return g_object_new (GTK_TYPE_IMAGE, NULL);
969
970
}

971
972
973
static void
gtk_image_unrealize (GtkWidget *widget)
{
974
975
  GtkImage *image = GTK_IMAGE (widget);

976
  gtk_icon_helper_invalidate (image->icon_helper);
977

978
  GTK_WIDGET_CLASS (gtk_image_parent_class)->unrealize (widget);
979
980
}

981
982
983
984
985
static float
gtk_image_get_baseline_align (GtkImage *image)
{
  PangoContext *pango_context;
  PangoFontMetrics *metrics;
Timm Bäder's avatar
Timm Bäder committed
986

987
  if (image->baseline_align == 0.0)
988
989
    {
      pango_context = gtk_widget_get_pango_context (GTK_WIDGET (image));
Matthias Clasen's avatar
Matthias Clasen committed
990
      metrics = pango_context_get_metrics (pango_context, NULL, NULL);
991
      image->baseline_align =
Timm Bäder's avatar
Timm Bäder committed