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>
25 #include "empathy-avatar-image.h"
27 #include <glib/gi18n-lib.h>
29 #include <tp-account-widgets/tpaw-pixbuf-utils.h>
31 #include "empathy-ui-utils.h"
32 #include "empathy-utils.h"
35 * SECTION:empathy-avatar-image
36 * @title: EmpathyAvatarImage
37 * @short_description: A widget to display an avatar
38 * @include: libempathy-gtk/empathy-avatar-image.h
40 * #EmpathyAvatarImage is a widget which displays an avatar.
45 * @parent: parent object
47 * Widget which displays an avatar.
53 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarImage)
58 } EmpathyAvatarImagePriv
;
60 static void avatar_image_finalize (GObject
*object
);
61 static void avatar_image_add_filter (EmpathyAvatarImage
*avatar_image
);
62 static void avatar_image_remove_filter (EmpathyAvatarImage
*avatar_image
);
63 static gboolean
avatar_image_button_press_event (GtkWidget
*widget
,
64 GdkEventButton
*event
);
65 static gboolean
avatar_image_button_release_event (GtkWidget
*widget
,
66 GdkEventButton
*event
);
68 G_DEFINE_TYPE (EmpathyAvatarImage
, empathy_avatar_image
, GTK_TYPE_EVENT_BOX
);
71 empathy_avatar_image_class_init (EmpathyAvatarImageClass
*klass
)
73 GObjectClass
*object_class
;
74 GtkWidgetClass
*widget_class
;
76 object_class
= G_OBJECT_CLASS (klass
);
77 widget_class
= GTK_WIDGET_CLASS (klass
);
79 object_class
->finalize
= avatar_image_finalize
;
81 widget_class
->button_press_event
= avatar_image_button_press_event
;
82 widget_class
->button_release_event
= avatar_image_button_release_event
;
84 g_type_class_add_private (object_class
, sizeof (EmpathyAvatarImagePriv
));
88 empathy_avatar_image_init (EmpathyAvatarImage
*avatar_image
)
90 EmpathyAvatarImagePriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (avatar_image
,
91 EMPATHY_TYPE_AVATAR_IMAGE
, EmpathyAvatarImagePriv
);
93 avatar_image
->priv
= priv
;
94 priv
->image
= gtk_image_new ();
95 gtk_container_add (GTK_CONTAINER (avatar_image
), priv
->image
);
96 empathy_avatar_image_set (avatar_image
, NULL
);
97 gtk_widget_show (priv
->image
);
99 avatar_image_add_filter (avatar_image
);
103 avatar_image_finalize (GObject
*object
)
105 EmpathyAvatarImagePriv
*priv
;
107 priv
= GET_PRIV (object
);
109 avatar_image_remove_filter (EMPATHY_AVATAR_IMAGE (object
));
112 gtk_widget_destroy (priv
->popup
);
116 g_object_unref (priv
->pixbuf
);
119 G_OBJECT_CLASS (empathy_avatar_image_parent_class
)->finalize (object
);
122 #ifdef GDK_WINDOWING_X11
124 running_in_x11 (void)
128 display
= gdk_display_get_default ();
132 return GDK_IS_X11_DISPLAY (display
);
135 static GdkFilterReturn
136 avatar_image_filter_func (GdkXEvent
*gdkxevent
,
140 XEvent
*xevent
= gdkxevent
;
142 EmpathyAvatarImagePriv
*priv
;
144 if (!running_in_x11 ())
145 return GDK_FILTER_CONTINUE
;
147 priv
= GET_PRIV (data
);
149 if (xevent
->type
== PropertyNotify
) {
150 atom
= gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP");
151 if (xevent
->xproperty
.atom
== atom
) {
153 gtk_widget_destroy (priv
->popup
);
159 return GDK_FILTER_CONTINUE
;
163 avatar_image_add_filter (EmpathyAvatarImage
*avatar_image
)
168 XWindowAttributes attrs
;
170 if (!running_in_x11 ())
173 mask
= PropertyChangeMask
;
175 window
= gdk_x11_get_default_root_xwindow ();
176 display
= gdk_x11_get_default_xdisplay ();
178 gdk_error_trap_push ();
180 XGetWindowAttributes (display
, window
, &attrs
);
181 mask
|= attrs
.your_event_mask
;
183 XSelectInput (display
, window
, mask
);
185 gdk_error_trap_pop_ignored ();
187 gdk_window_add_filter (NULL
, avatar_image_filter_func
, avatar_image
);
190 static GdkFilterReturn
191 avatar_image_filter_func (GdkXEvent
*gdkxevent
,
195 return GDK_FILTER_CONTINUE
;
199 avatar_image_add_filter (EmpathyAvatarImage
*avatar_image
)
205 avatar_image_remove_filter (EmpathyAvatarImage
*avatar_image
)
207 gdk_window_remove_filter (NULL
, avatar_image_filter_func
, avatar_image
);
211 avatar_image_button_press_event (GtkWidget
*widget
, GdkEventButton
*event
)
213 EmpathyAvatarImagePriv
*priv
;
218 gint popup_width
, popup_height
;
221 GtkAllocation allocation
;
223 priv
= GET_PRIV (widget
);
226 gtk_widget_destroy (priv
->popup
);
230 if (event
->button
!= 1 || event
->type
!= GDK_BUTTON_PRESS
|| !priv
->pixbuf
) {
234 popup_width
= gdk_pixbuf_get_width (priv
->pixbuf
);
235 popup_height
= gdk_pixbuf_get_height (priv
->pixbuf
);
237 gtk_widget_get_allocation (priv
->image
, &allocation
);
238 width
= allocation
.width
;
239 height
= allocation
.height
;
241 /* Don't show a popup if the popup is smaller then the currently avatar
244 if (popup_height
<= height
&& popup_width
<= width
) {
248 pixbuf
= tpaw_pixbuf_scale_down_if_necessary (priv
->pixbuf
, MAX_LARGE
);
249 popup_width
= gdk_pixbuf_get_width (pixbuf
);
250 popup_height
= gdk_pixbuf_get_height (pixbuf
);
252 popup
= gtk_window_new (GTK_WINDOW_POPUP
);
254 frame
= gtk_frame_new (NULL
);
255 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_OUT
);
257 gtk_container_add (GTK_CONTAINER (popup
), frame
);
259 image
= gtk_image_new ();
260 gtk_container_add (GTK_CONTAINER (frame
), image
);
262 gtk_image_set_from_pixbuf (GTK_IMAGE (image
), pixbuf
);
263 g_object_unref (pixbuf
);
265 gdk_window_get_origin (gtk_widget_get_window (priv
->image
), &x
, &y
);
267 x
= x
- (popup_width
- width
) / 2;
268 y
= y
- (popup_height
- height
) / 2;
270 gtk_window_move (GTK_WINDOW (popup
), x
, y
);
274 gtk_widget_show_all (popup
);
280 avatar_image_button_release_event (GtkWidget
*widget
, GdkEventButton
*event
)
282 EmpathyAvatarImagePriv
*priv
;
284 priv
= GET_PRIV (widget
);
286 if (event
->button
!= 1 || event
->type
!= GDK_BUTTON_RELEASE
) {
294 gtk_widget_destroy (priv
->popup
);
301 * empathy_avatar_image_new:
303 * Creates a new #EmpathyAvatarImage.
305 * Return value: a new #EmpathyAvatarImage
308 empathy_avatar_image_new (void)
310 EmpathyAvatarImage
*avatar_image
;
312 avatar_image
= g_object_new (EMPATHY_TYPE_AVATAR_IMAGE
, NULL
);
314 return GTK_WIDGET (avatar_image
);
318 * empathy_avatar_image_set:
319 * @avatar_image: an #EmpathyAvatarImage
320 * @avatar: the #EmpathyAvatar to set @avatar_image to
322 * Sets @avatar_image to display the avatar indicated by @avatar.
325 empathy_avatar_image_set (EmpathyAvatarImage
*avatar_image
,
326 EmpathyAvatar
*avatar
)
328 EmpathyAvatarImagePriv
*priv
= GET_PRIV (avatar_image
);
329 GdkPixbuf
*scaled_pixbuf
;
331 g_return_if_fail (EMPATHY_IS_AVATAR_IMAGE (avatar_image
));
334 g_object_unref (priv
->pixbuf
);
339 priv
->pixbuf
= tpaw_pixbuf_from_data ((gchar
*) avatar
->data
,
344 gtk_image_clear (GTK_IMAGE (priv
->image
));
348 scaled_pixbuf
= tpaw_pixbuf_scale_down_if_necessary (priv
->pixbuf
, MAX_SMALL
);
349 gtk_image_set_from_pixbuf (GTK_IMAGE (priv
->image
), scaled_pixbuf
);
351 if (scaled_pixbuf
!= priv
->pixbuf
) {
352 gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image
),
353 _("Click to enlarge"));
355 gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image
),
359 g_object_unref (scaled_pixbuf
);