1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2006-2007 Imendio AB
4 * Copyright (C) 2007-2008 Collabora Ltd.
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.
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.
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
21 * Authors: Xavier Claessens <xclaesse@gmail.com>
26 #include <glib/gi18n-lib.h>
27 #include <gdk/gdkkeysyms.h>
32 #include <libempathy/empathy-utils.h>
33 #include "empathy-avatar-image.h"
34 #include "empathy-ui-utils.h"
37 * SECTION:empathy-avatar-image
38 * @title: EmpathyAvatarImage
39 * @short_description: A widget to display an avatar
40 * @include: libempathy-gtk/empathy-avatar-image.h
42 * #EmpathyAvatarImage is a widget which displays an avatar.
47 * @parent: parent object
49 * Widget which displays an avatar.
55 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarImage)
60 } EmpathyAvatarImagePriv
;
62 static void avatar_image_finalize (GObject
*object
);
63 static void avatar_image_add_filter (EmpathyAvatarImage
*avatar_image
);
64 static void avatar_image_remove_filter (EmpathyAvatarImage
*avatar_image
);
65 static gboolean
avatar_image_button_press_event (GtkWidget
*widget
,
66 GdkEventButton
*event
);
67 static gboolean
avatar_image_button_release_event (GtkWidget
*widget
,
68 GdkEventButton
*event
);
70 G_DEFINE_TYPE (EmpathyAvatarImage
, empathy_avatar_image
, GTK_TYPE_EVENT_BOX
);
73 empathy_avatar_image_class_init (EmpathyAvatarImageClass
*klass
)
75 GObjectClass
*object_class
;
76 GtkWidgetClass
*widget_class
;
78 object_class
= G_OBJECT_CLASS (klass
);
79 widget_class
= GTK_WIDGET_CLASS (klass
);
81 object_class
->finalize
= avatar_image_finalize
;
83 widget_class
->button_press_event
= avatar_image_button_press_event
;
84 widget_class
->button_release_event
= avatar_image_button_release_event
;
86 g_type_class_add_private (object_class
, sizeof (EmpathyAvatarImagePriv
));
90 empathy_avatar_image_init (EmpathyAvatarImage
*avatar_image
)
92 EmpathyAvatarImagePriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (avatar_image
,
93 EMPATHY_TYPE_AVATAR_IMAGE
, EmpathyAvatarImagePriv
);
95 avatar_image
->priv
= priv
;
96 priv
->image
= gtk_image_new ();
97 gtk_container_add (GTK_CONTAINER (avatar_image
), priv
->image
);
98 empathy_avatar_image_set (avatar_image
, NULL
);
99 gtk_widget_show (priv
->image
);
101 avatar_image_add_filter (avatar_image
);
105 avatar_image_finalize (GObject
*object
)
107 EmpathyAvatarImagePriv
*priv
;
109 priv
= GET_PRIV (object
);
111 avatar_image_remove_filter (EMPATHY_AVATAR_IMAGE (object
));
114 gtk_widget_destroy (priv
->popup
);
118 g_object_unref (priv
->pixbuf
);
121 G_OBJECT_CLASS (empathy_avatar_image_parent_class
)->finalize (object
);
124 static GdkFilterReturn
125 avatar_image_filter_func (GdkXEvent
*gdkxevent
,
129 XEvent
*xevent
= gdkxevent
;
131 EmpathyAvatarImagePriv
*priv
;
133 priv
= GET_PRIV (data
);
135 if (xevent
->type
== PropertyNotify
) {
136 atom
= gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP");
137 if (xevent
->xproperty
.atom
== atom
) {
139 gtk_widget_destroy (priv
->popup
);
145 return GDK_FILTER_CONTINUE
;
149 avatar_image_add_filter (EmpathyAvatarImage
*avatar_image
)
152 GdkWindow
*gdkwindow
;
155 mask
= PropertyChangeMask
;
157 window
= GDK_ROOT_WINDOW ();
158 gdkwindow
= gdk_xid_table_lookup (window
);
160 gdk_error_trap_push ();
162 XWindowAttributes attrs
;
163 XGetWindowAttributes (gdk_display
, window
, &attrs
);
164 mask
|= attrs
.your_event_mask
;
167 XSelectInput (gdk_display
, window
, mask
);
169 gdk_error_trap_pop ();
171 gdk_window_add_filter (NULL
, avatar_image_filter_func
, avatar_image
);
175 avatar_image_remove_filter (EmpathyAvatarImage
*avatar_image
)
177 gdk_window_remove_filter (NULL
, avatar_image_filter_func
, avatar_image
);
181 avatar_image_button_press_event (GtkWidget
*widget
, GdkEventButton
*event
)
183 EmpathyAvatarImagePriv
*priv
;
188 gint popup_width
, popup_height
;
191 GtkAllocation allocation
;
193 priv
= GET_PRIV (widget
);
196 gtk_widget_destroy (priv
->popup
);
200 if (event
->button
!= 1 || event
->type
!= GDK_BUTTON_PRESS
|| !priv
->pixbuf
) {
204 popup_width
= gdk_pixbuf_get_width (priv
->pixbuf
);
205 popup_height
= gdk_pixbuf_get_height (priv
->pixbuf
);
207 gtk_widget_get_allocation (priv
->image
, &allocation
);
208 width
= allocation
.width
;
209 height
= allocation
.height
;
211 /* Don't show a popup if the popup is smaller then the currently avatar
214 if (popup_height
<= height
&& popup_width
<= width
) {
218 pixbuf
= empathy_pixbuf_scale_down_if_necessary (priv
->pixbuf
, MAX_LARGE
);
219 popup_width
= gdk_pixbuf_get_width (pixbuf
);
220 popup_height
= gdk_pixbuf_get_height (pixbuf
);
222 popup
= gtk_window_new (GTK_WINDOW_POPUP
);
224 frame
= gtk_frame_new (NULL
);
225 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_OUT
);
227 gtk_container_add (GTK_CONTAINER (popup
), frame
);
229 image
= gtk_image_new ();
230 gtk_container_add (GTK_CONTAINER (frame
), image
);
232 gtk_image_set_from_pixbuf (GTK_IMAGE (image
), pixbuf
);
233 g_object_unref (pixbuf
);
235 gdk_window_get_origin (gtk_widget_get_window (priv
->image
), &x
, &y
);
237 x
= x
- (popup_width
- width
) / 2;
238 y
= y
- (popup_height
- height
) / 2;
240 gtk_window_move (GTK_WINDOW (popup
), x
, y
);
244 gtk_widget_show_all (popup
);
250 avatar_image_button_release_event (GtkWidget
*widget
, GdkEventButton
*event
)
252 EmpathyAvatarImagePriv
*priv
;
254 priv
= GET_PRIV (widget
);
256 if (event
->button
!= 1 || event
->type
!= GDK_BUTTON_RELEASE
) {
264 gtk_widget_destroy (priv
->popup
);
271 * empathy_avatar_image_new:
273 * Creates a new #EmpathyAvatarImage.
275 * Return value: a new #EmpathyAvatarImage
278 empathy_avatar_image_new (void)
280 EmpathyAvatarImage
*avatar_image
;
282 avatar_image
= g_object_new (EMPATHY_TYPE_AVATAR_IMAGE
, NULL
);
284 return GTK_WIDGET (avatar_image
);
288 * empathy_avatar_image_set:
289 * @avatar_image: an #EmpathyAvatarImage
290 * @avatar: the #EmpathyAvatar to set @avatar_image to
292 * Sets @avatar_image to display the avatar indicated by @avatar.
295 empathy_avatar_image_set (EmpathyAvatarImage
*avatar_image
,
296 EmpathyAvatar
*avatar
)
298 EmpathyAvatarImagePriv
*priv
= GET_PRIV (avatar_image
);
299 GdkPixbuf
*scaled_pixbuf
;
301 g_return_if_fail (EMPATHY_IS_AVATAR_IMAGE (avatar_image
));
304 g_object_unref (priv
->pixbuf
);
309 priv
->pixbuf
= empathy_pixbuf_from_data ((gchar
*) avatar
->data
,
314 gtk_image_clear (GTK_IMAGE (priv
->image
));
318 scaled_pixbuf
= empathy_pixbuf_scale_down_if_necessary (priv
->pixbuf
, MAX_SMALL
);
319 gtk_image_set_from_pixbuf (GTK_IMAGE (priv
->image
), scaled_pixbuf
);
321 if (scaled_pixbuf
!= priv
->pixbuf
) {
322 gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image
),
323 _("Click to enlarge"));
325 gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image
),
329 g_object_unref (scaled_pixbuf
);