1#include "demoimage.h"
2#include <glib/gi18n.h>
3
4struct _DemoImage {
5 GtkWidget parent_instance;
6
7 GtkWidget *image;
8 GtkWidget *popover;
9};
10
11enum {
12 PROP_ICON_NAME = 1
13};
14
15G_DEFINE_TYPE(DemoImage, demo_image, GTK_TYPE_WIDGET)
16
17static GdkPaintable *
18get_image_paintable (GtkImage *image)
19{
20 const char *icon_name;
21 GtkIconTheme *icon_theme;
22 GtkIconPaintable *icon;
23
24 switch (gtk_image_get_storage_type (image))
25 {
26 case GTK_IMAGE_PAINTABLE:
27 return g_object_ref (gtk_image_get_paintable (image));
28 case GTK_IMAGE_ICON_NAME:
29 icon_name = gtk_image_get_icon_name (image);
30 icon_theme = gtk_icon_theme_get_for_display (display: gtk_widget_get_display (GTK_WIDGET (image)));
31 icon = gtk_icon_theme_lookup_icon (self: icon_theme,
32 icon_name,
33 NULL,
34 size: 48, scale: 1,
35 direction: gtk_widget_get_direction (GTK_WIDGET (image)),
36 flags: 0);
37 if (icon == NULL)
38 return NULL;
39 return GDK_PAINTABLE (ptr: icon);
40
41 case GTK_IMAGE_EMPTY:
42 case GTK_IMAGE_GICON:
43 default:
44 g_warning ("Image storage type %d not handled",
45 gtk_image_get_storage_type (image));
46 return NULL;
47 }
48}
49
50static void
51update_drag_icon (DemoImage *demo,
52 GtkDragIcon *icon)
53{
54 const char *icon_name;
55 GdkPaintable *paintable;
56 GtkWidget *image;
57
58 switch (gtk_image_get_storage_type (GTK_IMAGE (demo->image)))
59 {
60 case GTK_IMAGE_PAINTABLE:
61 paintable = gtk_image_get_paintable (GTK_IMAGE (demo->image));
62 image = gtk_image_new_from_paintable (paintable);
63 break;
64 case GTK_IMAGE_ICON_NAME:
65 icon_name = gtk_image_get_icon_name (GTK_IMAGE (demo->image));
66 image = gtk_image_new_from_icon_name (icon_name);
67 break;
68 case GTK_IMAGE_EMPTY:
69 case GTK_IMAGE_GICON:
70 default:
71 g_warning ("Image storage type %d not handled",
72 gtk_image_get_storage_type (GTK_IMAGE (demo->image)));
73 return;
74 }
75
76 gtk_image_set_pixel_size (GTK_IMAGE (image),
77 pixel_size: gtk_image_get_pixel_size (GTK_IMAGE (demo->image)));
78
79 gtk_drag_icon_set_child (self: icon, child: image);
80}
81
82static void
83drag_begin (GtkDragSource *source,
84 GdkDrag *drag,
85 gpointer data)
86{
87 GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
88 DemoImage *demo = DEMO_IMAGE (ptr: widget);
89
90 update_drag_icon (demo, icon: GTK_DRAG_ICON (ptr: gtk_drag_icon_get_for_drag (drag)));
91}
92
93static GdkContentProvider *
94prepare_drag (GtkDragSource *source,
95 double x,
96 double y,
97 gpointer data)
98{
99 GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
100 DemoImage *demo = DEMO_IMAGE (ptr: widget);
101 GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
102
103 /* Textures can be serialized, paintables can't, so special case the textures */
104 if (GDK_IS_TEXTURE (paintable))
105 return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
106 else
107 return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
108}
109
110static gboolean
111drag_drop (GtkDropTarget *dest,
112 const GValue *value,
113 double x,
114 double y,
115 gpointer data)
116{
117 GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
118 DemoImage *demo = DEMO_IMAGE (ptr: widget);
119 GdkPaintable *paintable = g_value_get_object (value);
120
121 gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
122
123 return TRUE;
124}
125
126static void
127copy_image (GtkWidget *widget,
128 const char *action_name,
129 GVariant *parameter)
130{
131 GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
132 DemoImage *demo = DEMO_IMAGE (ptr: widget);
133 GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
134 GValue value = G_VALUE_INIT;
135
136 /* Textures can be serialized, paintables can't, so special case the textures */
137 if (GDK_IS_TEXTURE (paintable))
138 g_value_init (value: &value, GDK_TYPE_TEXTURE);
139 else
140 g_value_init (value: &value, GDK_TYPE_PAINTABLE);
141 g_value_set_object (value: &value, v_object: paintable);
142 gdk_clipboard_set_value (clipboard, value: &value);
143 g_value_unset (value: &value);
144
145 if (paintable)
146 g_object_unref (object: paintable);
147}
148
149static void
150paste_image_cb (GObject *source,
151 GAsyncResult *result,
152 gpointer data)
153{
154 GdkClipboard *clipboard = GDK_CLIPBOARD (source);
155 DemoImage *demo = DEMO_IMAGE (ptr: data);
156 const GValue *value;
157
158 value = gdk_clipboard_read_value_finish (clipboard, result, NULL);
159 if (value == NULL)
160 {
161 gtk_widget_error_bell (GTK_WIDGET (demo));
162 g_object_unref (object: demo);
163 return;
164 }
165
166 gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable: g_value_get_object (value));
167 g_object_unref (object: demo);
168}
169
170static void
171paste_image (GtkWidget *widget,
172 const char *action_name,
173 GVariant *parameter)
174{
175 GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
176 GType type;
177
178 if (gdk_content_formats_contain_gtype (formats: gdk_clipboard_get_formats (clipboard), GDK_TYPE_TEXTURE))
179 type = GDK_TYPE_TEXTURE;
180 else
181 type = GDK_TYPE_PAINTABLE;
182
183 gdk_clipboard_read_value_async (clipboard,
184 type,
185 G_PRIORITY_DEFAULT,
186 NULL,
187 callback: paste_image_cb,
188 g_object_ref (widget));
189}
190
191static void
192pressed_cb (GtkGesture *gesture,
193 int n_press,
194 double x,
195 double y,
196 gpointer data)
197{
198 DemoImage *demo = DEMO_IMAGE (ptr: gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
199
200 gtk_popover_popup (GTK_POPOVER (demo->popover));
201}
202
203static void
204demo_image_init (DemoImage *demo)
205{
206 GMenu *menu;
207 GMenuItem *item;
208 GtkDragSource *source;
209 GtkDropTarget *dest;
210 GtkGesture *gesture;
211
212 demo->image = gtk_image_new ();
213 gtk_image_set_pixel_size (GTK_IMAGE (demo->image), pixel_size: 48);
214 gtk_widget_set_parent (widget: demo->image, GTK_WIDGET (demo));
215
216 menu = g_menu_new ();
217 item = g_menu_item_new (_("_Copy"), detailed_action: "clipboard.copy");
218 g_menu_append_item (menu, item);
219
220 item = g_menu_item_new (_("_Paste"), detailed_action: "clipboard.paste");
221 g_menu_append_item (menu, item);
222
223 demo->popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
224 gtk_widget_set_parent (widget: demo->popover, GTK_WIDGET (demo));
225
226 source = gtk_drag_source_new ();
227 g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
228 g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
229 gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (source));
230
231 dest = gtk_drop_target_new (GDK_TYPE_PAINTABLE, actions: GDK_ACTION_COPY);
232 g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
233 gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (dest));
234
235 gesture = gtk_gesture_click_new ();
236 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
237 g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL);
238 gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (gesture));
239}
240
241static void
242demo_image_dispose (GObject *object)
243{
244 DemoImage *demo = DEMO_IMAGE (ptr: object);
245
246 g_clear_pointer (&demo->image, gtk_widget_unparent);
247 g_clear_pointer (&demo->popover, gtk_widget_unparent);
248
249 G_OBJECT_CLASS (demo_image_parent_class)->dispose (object);
250}
251
252static void
253demo_image_get_property (GObject *object,
254 guint prop_id,
255 GValue *value,
256 GParamSpec *pspec)
257{
258 DemoImage *demo = DEMO_IMAGE (ptr: object);
259
260 switch (prop_id)
261 {
262 case PROP_ICON_NAME:
263 g_value_set_string (value, v_string: gtk_image_get_icon_name (GTK_IMAGE (demo->image)));
264 break;
265 default:
266 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267 break;
268 }
269}
270
271static void
272demo_image_set_property (GObject *object,
273 guint prop_id,
274 const GValue *value,
275 GParamSpec *pspec)
276{
277 DemoImage *demo = DEMO_IMAGE (ptr: object);
278
279 switch (prop_id)
280 {
281 case PROP_ICON_NAME:
282 gtk_image_set_from_icon_name (GTK_IMAGE (demo->image),
283 icon_name: g_value_get_string (value));
284 break;
285 default:
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
287 break;
288 }
289}
290
291static void
292demo_image_class_init (DemoImageClass *class)
293{
294 GObjectClass *object_class = G_OBJECT_CLASS (class);
295 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
296
297 object_class->dispose = demo_image_dispose;
298 object_class->get_property = demo_image_get_property;
299 object_class->set_property = demo_image_set_property;
300
301 g_object_class_install_property (oclass: object_class, property_id: PROP_ICON_NAME,
302 pspec: g_param_spec_string (name: "icon-name", nick: "Icon name", blurb: "Icon name",
303 NULL, flags: G_PARAM_READWRITE));
304
305 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
306
307 gtk_widget_class_install_action (widget_class, action_name: "clipboard.copy", NULL, activate: copy_image);
308 gtk_widget_class_install_action (widget_class, action_name: "clipboard.paste", NULL, activate: paste_image);
309}
310
311GtkWidget *
312demo_image_new (const char *icon_name)
313{
314 return g_object_new (DEMO_TYPE_IMAGE, first_property_name: "icon-name", icon_name, NULL);
315}
316

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