1/* Paintable/Simple Paintable
2 *
3 * GdkPaintable is an interface used by GTK for drawings of any sort
4 * that do not require layouting or positioning.
5 *
6 * This demo code gives a simple example on how a paintable can
7 * be created.
8 *
9 * Paintables can be used in many places inside GTK widgets, but the
10 * most common usage is inside GtkImage and that's what we're going
11 * to do here.
12 */
13
14#include <gtk/gtk.h>
15
16#include "paintable.h"
17
18static GtkWidget *window = NULL;
19
20/* First, add the boilerplate for the object itself.
21 * This part would normally go in the header.
22 */
23#define GTK_TYPE_NUCLEAR_ICON (gtk_nuclear_icon_get_type ())
24G_DECLARE_FINAL_TYPE (GtkNuclearIcon, gtk_nuclear_icon, GTK, NUCLEAR_ICON, GObject)
25
26/* Declare the struct. */
27struct _GtkNuclearIcon
28{
29 GObject parent_instance;
30
31 /* We store this rotation value here.
32 * We are not doing with it here, but it will come in
33 * very useful in the followup demos.
34 */
35 double rotation;
36};
37
38struct _GtkNuclearIconClass
39{
40 GObjectClass parent_class;
41};
42
43/* This is the function that draws the actual icon.
44 * We make it a custom function and define it in the paintable.h header
45 * so that it can be called from all the other demos, too.
46 */
47void
48gtk_nuclear_snapshot (GtkSnapshot *snapshot,
49 const GdkRGBA *foreground,
50 const GdkRGBA *background,
51 double width,
52 double height,
53 double rotation)
54{
55#define RADIUS 0.3
56 cairo_t *cr;
57 double size;
58
59 gtk_snapshot_append_color (snapshot,
60 color: background,
61 bounds: &GRAPHENE_RECT_INIT (0, 0, width, height));
62
63 size = MIN (width, height);
64 cr = gtk_snapshot_append_cairo (snapshot,
65 bounds: &GRAPHENE_RECT_INIT ((width - size) / 2.0,
66 (height - size) / 2.0,
67 size, size));
68 gdk_cairo_set_source_rgba (cr, rgba: foreground);
69 cairo_translate (cr, tx: width / 2.0, ty: height / 2.0);
70 cairo_scale (cr, sx: size, sy: size);
71 cairo_rotate (cr, angle: rotation);
72
73 cairo_arc (cr, xc: 0, yc: 0, radius: 0.1, angle1: - G_PI, G_PI);
74 cairo_fill (cr);
75
76 cairo_set_line_width (cr, RADIUS);
77 cairo_set_dash (cr, dashes: (double[1]) { RADIUS * G_PI / 3 }, num_dashes: 1, offset: 0.0);
78 cairo_arc (cr, xc: 0, yc: 0, RADIUS, angle1: - G_PI, G_PI);
79 cairo_stroke (cr);
80
81 cairo_destroy (cr);
82}
83
84/* Here, we implement the functionality required by the GdkPaintable interface */
85static void
86gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
87 GdkSnapshot *snapshot,
88 double width,
89 double height)
90{
91 GtkNuclearIcon *nuclear = GTK_NUCLEAR_ICON (ptr: paintable);
92
93 /* The snapshot function is the only function we need to implement.
94 * It does the actual drawing of the paintable.
95 */
96
97 gtk_nuclear_snapshot (snapshot,
98 foreground: &(GdkRGBA) { 0, 0, 0, 1 }, /* black */
99 background: &(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 }, /* yellow */
100 width, height,
101 rotation: nuclear->rotation);
102}
103
104static GdkPaintableFlags
105gtk_nuclear_icon_get_flags (GdkPaintable *paintable)
106{
107 /* The flags are very useful to let GTK know that this image
108 * is never going to change.
109 * This allows many optimizations and should therefore always
110 * be set.
111 */
112 return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
113}
114
115static void
116gtk_nuclear_icon_paintable_init (GdkPaintableInterface *iface)
117{
118 iface->snapshot = gtk_nuclear_icon_snapshot;
119 iface->get_flags = gtk_nuclear_icon_get_flags;
120}
121
122/* When defining the GType, we need to implement the GdkPaintable interface */
123G_DEFINE_TYPE_WITH_CODE (GtkNuclearIcon, gtk_nuclear_icon, G_TYPE_OBJECT,
124 G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
125 gtk_nuclear_icon_paintable_init))
126
127/* Here's the boilerplate for the GObject declaration.
128 * We don't need to do anything special here, because we keep no
129 * data of our own.
130 */
131static void
132gtk_nuclear_icon_class_init (GtkNuclearIconClass *klass)
133{
134}
135
136static void
137gtk_nuclear_icon_init (GtkNuclearIcon *nuclear)
138{
139}
140
141/* And finally, we add a simple constructor.
142 * It is declared in the header so that the other examples
143 * can use it.
144 */
145GdkPaintable *
146gtk_nuclear_icon_new (double rotation)
147{
148 GtkNuclearIcon *nuclear;
149
150 nuclear = g_object_new (GTK_TYPE_NUCLEAR_ICON, NULL);
151 nuclear->rotation = rotation;
152
153 return GDK_PAINTABLE (ptr: nuclear);
154}
155
156GtkWidget *
157do_paintable (GtkWidget *do_widget)
158{
159 GdkPaintable *nuclear;
160 GtkWidget *image;
161
162 if (!window)
163 {
164 window = gtk_window_new ();
165 gtk_window_set_display (GTK_WINDOW (window),
166 display: gtk_widget_get_display (widget: do_widget));
167 gtk_window_set_title (GTK_WINDOW (window), title: "Nuclear Icon");
168 gtk_window_set_default_size (GTK_WINDOW (window), width: 300, height: 200);
169 g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window);
170
171 nuclear = gtk_nuclear_icon_new (rotation: 0.0);
172 image = gtk_image_new_from_paintable (paintable: nuclear);
173 gtk_window_set_child (GTK_WINDOW (window), child: image);
174 g_object_unref (object: nuclear);
175 }
176
177 if (!gtk_widget_get_visible (widget: window))
178 gtk_widget_show (widget: window);
179 else
180 gtk_window_destroy (GTK_WINDOW (window));
181
182 return window;
183}
184

source code of gtk/demos/gtk-demo/paintable.c