1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* Copyright (C) 2004 Novell, Inc.
4
* Author: Chris Toshok <toshok@ximian.com>
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of version 2 of the GNU General Public
8
* License as published by the Free Software Foundation.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
15
* You should have received a copy of the GNU General Public
16
* License along with this library; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
25
#include <glib-object.h>
26
#include <glib/gi18n.h>
30
#include "e-image-chooser.h"
32
struct _EImageChooserPrivate {
35
GtkWidget *browse_button;
51
static gint image_chooser_signals [LAST_SIGNAL] = { 0 };
53
static void e_image_chooser_init (EImageChooser *chooser);
54
static void e_image_chooser_class_init (EImageChooserClass *klass);
55
static void e_image_chooser_dispose (GObject *object);
57
static gboolean image_drag_motion_cb (GtkWidget *widget,
58
GdkDragContext *context,
59
gint x, gint y, guint time, EImageChooser *chooser);
60
static gboolean image_drag_drop_cb (GtkWidget *widget,
61
GdkDragContext *context,
62
gint x, gint y, guint time, EImageChooser *chooser);
63
static void image_drag_data_received_cb (GtkWidget *widget,
64
GdkDragContext *context,
66
GtkSelectionData *selection_data,
67
guint info, guint time, EImageChooser *chooser);
69
static GtkObjectClass *parent_class = NULL;
70
#define PARENT_TYPE GTK_TYPE_VBOX
73
DND_TARGET_TYPE_URI_LIST
75
#define URI_LIST_TYPE "text/uri-list"
77
static GtkTargetEntry image_drag_types[] = {
78
{ URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
80
static const int num_image_drag_types = sizeof (image_drag_types) / sizeof (image_drag_types[0]);
83
e_image_chooser_new (void)
85
return g_object_new (E_TYPE_IMAGE_CHOOSER, NULL);
89
e_image_chooser_get_type (void)
91
static GType eic_type = 0;
94
static const GTypeInfo eic_info = {
95
sizeof (EImageChooserClass),
97
NULL, /* base_finalize */
98
(GClassInitFunc) e_image_chooser_class_init,
99
NULL, /* class_finalize */
100
NULL, /* class_data */
101
sizeof (EImageChooser),
103
(GInstanceInitFunc) e_image_chooser_init,
106
eic_type = g_type_register_static (PARENT_TYPE, "EImageChooser", &eic_info, 0);
114
e_image_chooser_class_init (EImageChooserClass *klass)
116
GObjectClass *object_class = G_OBJECT_CLASS (klass);
118
parent_class = g_type_class_ref (PARENT_TYPE);
120
image_chooser_signals [CHANGED] =
121
g_signal_new ("changed",
122
G_OBJECT_CLASS_TYPE (object_class),
124
G_STRUCT_OFFSET (EImageChooserClass, changed),
126
g_cclosure_marshal_VOID__VOID,
129
object_class->dispose = e_image_chooser_dispose;
133
e_image_chooser_init (EImageChooser *chooser)
135
EImageChooserPrivate *priv;
137
priv = chooser->priv = g_new0 (EImageChooserPrivate, 1);
139
priv->image = gtk_image_new ();
141
gtk_box_set_homogeneous (GTK_BOX (chooser), FALSE);
142
gtk_box_pack_start (GTK_BOX (chooser), priv->image, TRUE, TRUE, 0);
144
gtk_drag_dest_set (priv->image, 0, image_drag_types, num_image_drag_types, GDK_ACTION_COPY);
145
g_signal_connect (priv->image,
146
"drag_motion", G_CALLBACK (image_drag_motion_cb), chooser);
147
g_signal_connect (priv->image,
148
"drag_drop", G_CALLBACK (image_drag_drop_cb), chooser);
149
g_signal_connect (priv->image,
150
"drag_data_received", G_CALLBACK (image_drag_data_received_cb), chooser);
152
gtk_widget_show_all (priv->image);
154
/* we default to being editable */
155
priv->editable = TRUE;
159
e_image_chooser_dispose (GObject *object)
161
EImageChooser *eic = E_IMAGE_CHOOSER (object);
164
EImageChooserPrivate *priv = eic->priv;
166
if (priv->image_buf) {
167
g_free (priv->image_buf);
168
priv->image_buf = NULL;
175
if (G_OBJECT_CLASS (parent_class)->dispose)
176
(* G_OBJECT_CLASS (parent_class)->dispose) (object);
181
set_image_from_data (EImageChooser *chooser,
182
char *data, int length)
185
GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
188
gdk_pixbuf_loader_write (loader, data, length, NULL);
189
gdk_pixbuf_loader_close (loader, NULL);
191
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
193
g_object_ref (pixbuf);
194
g_object_unref (loader);
198
GtkRequisition chooser_size;
201
int new_height, new_width;
203
gtk_widget_size_request (gtk_widget_get_parent (GTK_WIDGET (chooser)),
205
chooser_size.width -= 5;
206
chooser_size.height -= 5;
208
new_height = gdk_pixbuf_get_height (pixbuf);
209
new_width = gdk_pixbuf_get_width (pixbuf);
211
if (chooser->priv->image_height == 0
212
&& chooser->priv->image_width == 0) {
215
else if (chooser->priv->image_height < new_height
216
|| chooser->priv->image_width < new_width) {
217
/* we need to scale down */
218
if (new_height > new_width)
219
scale = (float)chooser_size.height / new_height;
221
scale = (float)chooser_size.width / new_width;
224
/* we need to scale up */
225
if (new_height > new_width)
226
scale = (float)new_height / chooser_size.height;
228
scale = (float)new_width / chooser_size.width;
232
gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image), pixbuf);
234
chooser->priv->image_width = new_width;
235
chooser->priv->image_height = new_height;
240
new_width = MIN (new_width, chooser_size.width);
241
new_height = MIN (new_height, chooser_size.height);
243
scaled = gdk_pixbuf_scale_simple (pixbuf,
244
new_width, new_height,
245
GDK_INTERP_BILINEAR);
247
gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image), scaled);
248
g_object_unref (scaled);
251
g_object_unref (pixbuf);
253
g_free (chooser->priv->image_buf);
254
chooser->priv->image_buf = data;
255
chooser->priv->image_buf_size = length;
257
g_signal_emit (chooser,
258
image_chooser_signals [CHANGED], 0);
267
image_drag_motion_cb (GtkWidget *widget,
268
GdkDragContext *context,
269
gint x, gint y, guint time, EImageChooser *chooser)
273
if (!chooser->priv->editable)
276
for (p = context->targets; p != NULL; p = p->next) {
279
possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
280
if (!strcmp (possible_type, URI_LIST_TYPE)) {
281
g_free (possible_type);
282
gdk_drag_status (context, GDK_ACTION_COPY, time);
286
g_free (possible_type);
293
image_drag_drop_cb (GtkWidget *widget,
294
GdkDragContext *context,
295
gint x, gint y, guint time, EImageChooser *chooser)
299
if (!chooser->priv->editable)
302
if (context->targets == NULL) {
306
for (p = context->targets; p != NULL; p = p->next) {
309
possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
310
if (!strcmp (possible_type, URI_LIST_TYPE)) {
311
g_free (possible_type);
312
gtk_drag_get_data (widget, context,
313
GDK_POINTER_TO_ATOM (p->data),
318
g_free (possible_type);
325
image_drag_data_received_cb (GtkWidget *widget,
326
GdkDragContext *context,
328
GtkSelectionData *selection_data,
329
guint info, guint time, EImageChooser *chooser)
332
gboolean handled = FALSE;
334
target_type = gdk_atom_name (gtk_selection_data_get_target (selection_data));
336
if (!strcmp (target_type, URI_LIST_TYPE)) {
337
const char *data = gtk_selection_data_get_data (selection_data);
340
GInputStream *istream;
341
char *nl = strstr (data, "\r\n");
344
uri = g_strndup (data, nl - (char *) data);
346
uri = g_strdup (data);
348
file = g_file_new_for_uri (uri);
349
istream = G_INPUT_STREAM (g_file_read (file, NULL, NULL));
351
if (istream != NULL) {
354
info = g_file_query_info (file,
355
G_FILE_ATTRIBUTE_STANDARD_SIZE,
356
G_FILE_QUERY_INFO_NONE,
364
size = g_file_info_get_size (info);
365
g_object_unref (info);
367
buf = g_malloc (size);
369
success = g_input_stream_read_all (istream,
375
g_input_stream_close (istream, NULL, NULL);
378
set_image_from_data (chooser, buf, size))
384
g_object_unref (istream);
387
g_object_unref (file);
391
gtk_drag_finish (context, handled, FALSE, time);
395
e_image_chooser_set_from_file (EImageChooser *chooser, const char *filename)
400
g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE);
401
g_return_val_if_fail (filename, FALSE);
403
if (!g_file_get_contents (filename, &data, &data_length, NULL)) {
407
if (!set_image_from_data (chooser, data, data_length))
414
e_image_chooser_set_editable (EImageChooser *chooser, gboolean editable)
416
g_return_if_fail (E_IS_IMAGE_CHOOSER (chooser));
418
chooser->priv->editable = editable;
420
gtk_widget_set_sensitive (chooser->priv->browse_button, editable);
424
e_image_chooser_get_image_data (EImageChooser *chooser, char **data, gsize *data_length)
426
g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE);
427
g_return_val_if_fail (data != NULL, FALSE);
428
g_return_val_if_fail (data_length != NULL, FALSE);
430
*data_length = chooser->priv->image_buf_size;
431
*data = g_malloc (*data_length);
432
memcpy (*data, chooser->priv->image_buf, *data_length);
438
e_image_chooser_set_image_data (EImageChooser *chooser, char *data, gsize data_length)
442
g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE);
443
g_return_val_if_fail (data != NULL, FALSE);
445
/* yuck, a copy... */
446
buf = g_malloc (data_length);
447
memcpy (buf, data, data_length);
449
if (!set_image_from_data (chooser, buf, data_length)) {