]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-avatar-image.c
GNOME Goal: Update icon names
[empathy.git] / libempathy-gtk / empathy-avatar-image.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2006-2007 Imendio AB
4  * Copyright (C) 2007-2008 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301  USA
20  *
21  * Authors: Xavier Claessens <xclaesse@gmail.com>
22  */
23
24 #include "config.h"
25 #include "empathy-avatar-image.h"
26
27 #include <glib/gi18n-lib.h>
28 #include <gdk/gdkx.h>
29
30 #include "empathy-ui-utils.h"
31 #include "empathy-utils.h"
32
33 /**
34  * SECTION:empathy-avatar-image
35  * @title: EmpathyAvatarImage
36  * @short_description: A widget to display an avatar
37  * @include: libempathy-gtk/empathy-avatar-image.h
38  *
39  * #EmpathyAvatarImage is a widget which displays an avatar.
40  */
41
42 /**
43  * EmpathyAvatarImage:
44  * @parent: parent object
45  *
46  * Widget which displays an avatar.
47  */
48
49 #define MAX_SMALL 64
50 #define MAX_LARGE 400
51
52 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarImage)
53 typedef struct {
54         GtkWidget   *image;
55         GtkWidget   *popup;
56         GdkPixbuf   *pixbuf;
57 } EmpathyAvatarImagePriv;
58
59 static void     avatar_image_finalize                (GObject           *object);
60 static void     avatar_image_add_filter              (EmpathyAvatarImage *avatar_image);
61 static void     avatar_image_remove_filter           (EmpathyAvatarImage *avatar_image);
62 static gboolean avatar_image_button_press_event      (GtkWidget         *widget,
63                                                       GdkEventButton    *event);
64 static gboolean avatar_image_button_release_event    (GtkWidget         *widget,
65                                                       GdkEventButton    *event);
66
67 G_DEFINE_TYPE (EmpathyAvatarImage, empathy_avatar_image, GTK_TYPE_EVENT_BOX);
68
69 static void
70 empathy_avatar_image_class_init (EmpathyAvatarImageClass *klass)
71 {
72         GObjectClass   *object_class;
73         GtkWidgetClass *widget_class;
74
75         object_class = G_OBJECT_CLASS (klass);
76         widget_class = GTK_WIDGET_CLASS (klass);
77
78         object_class->finalize = avatar_image_finalize;
79
80         widget_class->button_press_event   = avatar_image_button_press_event;
81         widget_class->button_release_event = avatar_image_button_release_event;
82
83         g_type_class_add_private (object_class, sizeof (EmpathyAvatarImagePriv));
84 }
85
86 static void
87 empathy_avatar_image_init (EmpathyAvatarImage *avatar_image)
88 {
89         EmpathyAvatarImagePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (avatar_image,
90                 EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImagePriv);
91
92         avatar_image->priv = priv;
93         priv->image = gtk_image_new ();
94         gtk_container_add (GTK_CONTAINER (avatar_image), priv->image);
95         empathy_avatar_image_set (avatar_image, NULL);
96         gtk_widget_show (priv->image);
97
98         avatar_image_add_filter (avatar_image);
99 }
100
101 static void
102 avatar_image_finalize (GObject *object)
103 {
104         EmpathyAvatarImagePriv *priv;
105
106         priv = GET_PRIV (object);
107
108         avatar_image_remove_filter (EMPATHY_AVATAR_IMAGE (object));
109
110         if (priv->popup) {
111                 gtk_widget_destroy (priv->popup);
112         }
113
114         if (priv->pixbuf) {
115                 g_object_unref (priv->pixbuf);
116         }
117
118         G_OBJECT_CLASS (empathy_avatar_image_parent_class)->finalize (object);
119 }
120
121 static GdkFilterReturn
122 avatar_image_filter_func (GdkXEvent  *gdkxevent,
123                           GdkEvent   *event,
124                           gpointer    data)
125 {
126         XEvent                *xevent = gdkxevent;
127         Atom                   atom;
128         EmpathyAvatarImagePriv *priv;
129
130         priv = GET_PRIV (data);
131
132         if (xevent->type == PropertyNotify) {
133                 atom = gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP");
134                 if (xevent->xproperty.atom == atom) {
135                         if (priv->popup) {
136                                 gtk_widget_destroy (priv->popup);
137                                 priv->popup = NULL;
138                         }
139                 }
140         }
141
142         return GDK_FILTER_CONTINUE;
143 }
144
145 static void
146 avatar_image_add_filter (EmpathyAvatarImage *avatar_image)
147 {
148         Display    *display;
149         Window     window;
150         gint       mask;
151         XWindowAttributes attrs;
152
153         mask = PropertyChangeMask;
154
155         window = gdk_x11_get_default_root_xwindow ();
156         display = gdk_x11_get_default_xdisplay ();
157
158         gdk_error_trap_push ();
159
160         XGetWindowAttributes (display, window, &attrs);
161         mask |= attrs.your_event_mask;
162
163         XSelectInput (display, window, mask);
164
165         gdk_error_trap_pop_ignored ();
166
167         gdk_window_add_filter (NULL, avatar_image_filter_func, avatar_image);
168 }
169
170 static void
171 avatar_image_remove_filter (EmpathyAvatarImage *avatar_image)
172 {
173         gdk_window_remove_filter (NULL, avatar_image_filter_func, avatar_image);
174 }
175
176 static gboolean
177 avatar_image_button_press_event (GtkWidget *widget, GdkEventButton *event)
178 {
179         EmpathyAvatarImagePriv *priv;
180         GtkWidget             *popup;
181         GtkWidget             *frame;
182         GtkWidget             *image;
183         gint                   x, y;
184         gint                   popup_width, popup_height;
185         gint                   width, height;
186         GdkPixbuf             *pixbuf;
187         GtkAllocation          allocation;
188
189         priv = GET_PRIV (widget);
190
191         if (priv->popup) {
192                 gtk_widget_destroy (priv->popup);
193                 priv->popup = NULL;
194         }
195
196         if (event->button != 1 || event->type != GDK_BUTTON_PRESS || !priv->pixbuf) {
197                 return FALSE;
198         }
199
200         popup_width = gdk_pixbuf_get_width (priv->pixbuf);
201         popup_height = gdk_pixbuf_get_height (priv->pixbuf);
202
203         gtk_widget_get_allocation (priv->image, &allocation);
204         width = allocation.width;
205         height = allocation.height;
206
207         /* Don't show a popup if the popup is smaller then the currently avatar
208          * image.
209          */
210         if (popup_height <= height && popup_width <= width) {
211                 return TRUE;
212         }
213
214         pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_LARGE);
215         popup_width = gdk_pixbuf_get_width (pixbuf);
216         popup_height = gdk_pixbuf_get_height (pixbuf);
217
218         popup = gtk_window_new (GTK_WINDOW_POPUP);
219
220         frame = gtk_frame_new (NULL);
221         gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
222
223         gtk_container_add (GTK_CONTAINER (popup), frame);
224
225         image = gtk_image_new ();
226         gtk_container_add (GTK_CONTAINER (frame), image);
227
228         gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
229         g_object_unref (pixbuf);
230
231         gdk_window_get_origin (gtk_widget_get_window (priv->image), &x, &y);
232
233         x = x - (popup_width - width) / 2;
234         y = y - (popup_height - height) / 2;
235
236         gtk_window_move (GTK_WINDOW (popup), x, y);
237
238         priv->popup = popup;
239
240         gtk_widget_show_all (popup);
241
242         return TRUE;
243 }
244
245 static gboolean
246 avatar_image_button_release_event (GtkWidget *widget, GdkEventButton *event)
247 {
248         EmpathyAvatarImagePriv *priv;
249
250         priv = GET_PRIV (widget);
251
252         if (event->button != 1 || event->type != GDK_BUTTON_RELEASE) {
253                 return FALSE;
254         }
255
256         if (!priv->popup) {
257                 return TRUE;
258         }
259
260         gtk_widget_destroy (priv->popup);
261         priv->popup = NULL;
262
263         return TRUE;
264 }
265
266 /**
267  * empathy_avatar_image_new:
268  *
269  * Creates a new #EmpathyAvatarImage.
270  *
271  * Return value: a new #EmpathyAvatarImage
272  */
273 GtkWidget *
274 empathy_avatar_image_new (void)
275 {
276         EmpathyAvatarImage *avatar_image;
277
278         avatar_image = g_object_new (EMPATHY_TYPE_AVATAR_IMAGE, NULL);
279
280         return GTK_WIDGET (avatar_image);
281 }
282
283 /**
284  * empathy_avatar_image_set:
285  * @avatar_image: an #EmpathyAvatarImage
286  * @avatar: the #EmpathyAvatar to set @avatar_image to
287  *
288  * Sets @avatar_image to display the avatar indicated by @avatar.
289  */
290 void
291 empathy_avatar_image_set (EmpathyAvatarImage *avatar_image,
292                           EmpathyAvatar      *avatar)
293 {
294         EmpathyAvatarImagePriv *priv = GET_PRIV (avatar_image);
295         GdkPixbuf              *scaled_pixbuf;
296
297         g_return_if_fail (EMPATHY_IS_AVATAR_IMAGE (avatar_image));
298
299         if (priv->pixbuf) {
300                 g_object_unref (priv->pixbuf);
301                 priv->pixbuf = NULL;
302         }
303
304         if (avatar) {
305                 priv->pixbuf = empathy_pixbuf_from_data ((gchar *) avatar->data,
306                                 avatar->len);
307         }
308
309         if (!priv->pixbuf) {
310                 gtk_image_clear (GTK_IMAGE (priv->image));
311                 return;
312         }
313
314         scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_SMALL);
315         gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled_pixbuf);
316
317         if (scaled_pixbuf != priv->pixbuf) {
318                 gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image),
319                                              _("Click to enlarge"));
320         } else {
321                 gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image),
322                                              NULL);
323         }
324
325         g_object_unref (scaled_pixbuf);
326 }
327