From 0d4e81432f5ace47ac86991aa239e4a55686de00 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 8 Oct 2007 16:44:44 +0000 Subject: Implement EmpathyAvatarChooser and EmpathyAvatarImage and make use of them 2007-10-08 Xavier Claessens * libempathy-gtk/empathy-ui-utils.c: * libempathy-gtk/empathy-ui-utils.h: * libempathy-gtk/empathy-contact-widget.c: * libempathy-gtk/empathy-contact-widget.h: * libempathy-gtk/empathy-avatar-chooser.c: * libempathy-gtk/empathy-avatar-chooser.h: * libempathy-gtk/empathy-avatar-image.c: * libempathy-gtk/empathy-avatar-image.h: * libempathy-gtk/Makefile.am: * src/empathy.c: Implement EmpathyAvatarChooser and EmpathyAvatarImage and make use of them in contact information windows. That means we can now enlarge avatars when clicking on it and we can set our own avatar if we edit our own contact. svn path=/trunk/; revision=363 --- libempathy-gtk/empathy-avatar-image.c | 306 ++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 libempathy-gtk/empathy-avatar-image.c (limited to 'libempathy-gtk/empathy-avatar-image.c') diff --git a/libempathy-gtk/empathy-avatar-image.c b/libempathy-gtk/empathy-avatar-image.c new file mode 100644 index 000000000..cc4ecbf45 --- /dev/null +++ b/libempathy-gtk/empathy-avatar-image.c @@ -0,0 +1,306 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include + +#include "empathy-avatar-image.h" +#include "empathy-ui-utils.h" + +#define DEBUG_DOMAIN "AvatarImage" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImagePriv)) + +#define MAX_SMALL 48 +#define MAX_LARGE 400 + +typedef struct { + GtkWidget *image; + GtkWidget *popup; + GdkPixbuf *pixbuf; +} EmpathyAvatarImagePriv; + +static void avatar_image_finalize (GObject *object); +static void avatar_image_add_filter (EmpathyAvatarImage *avatar_image); +static void avatar_image_remove_filter (EmpathyAvatarImage *avatar_image); +static gboolean avatar_image_button_press_event (GtkWidget *widget, + GdkEventButton *event); +static gboolean avatar_image_button_release_event (GtkWidget *widget, + GdkEventButton *event); + +G_DEFINE_TYPE (EmpathyAvatarImage, empathy_avatar_image, GTK_TYPE_EVENT_BOX); + +static void +empathy_avatar_image_class_init (EmpathyAvatarImageClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = G_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = avatar_image_finalize; + + widget_class->button_press_event = avatar_image_button_press_event; + widget_class->button_release_event = avatar_image_button_release_event; + + g_type_class_add_private (object_class, sizeof (EmpathyAvatarImagePriv)); +} + +static void +empathy_avatar_image_init (EmpathyAvatarImage *avatar_image) +{ + EmpathyAvatarImagePriv *priv; + + priv = GET_PRIV (avatar_image); + + priv->image = gtk_image_new (); + gtk_container_add (GTK_CONTAINER (avatar_image), priv->image); + empathy_avatar_image_set (avatar_image, NULL); + gtk_widget_show (priv->image); + + avatar_image_add_filter (avatar_image); +} + +static void +avatar_image_finalize (GObject *object) +{ + EmpathyAvatarImagePriv *priv; + + priv = GET_PRIV (object); + + avatar_image_remove_filter (EMPATHY_AVATAR_IMAGE (object)); + + if (priv->popup) { + gtk_widget_destroy (priv->popup); + } + + if (priv->pixbuf) { + g_object_unref (priv->pixbuf); + } + + G_OBJECT_CLASS (empathy_avatar_image_parent_class)->finalize (object); +} + +static GdkFilterReturn +avatar_image_filter_func (GdkXEvent *gdkxevent, + GdkEvent *event, + gpointer data) +{ + XEvent *xevent = gdkxevent; + Atom atom; + EmpathyAvatarImagePriv *priv; + + priv = GET_PRIV (data); + + switch (xevent->type) { + case PropertyNotify: + atom = gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP"); + if (xevent->xproperty.atom == atom) { + if (priv->popup) { + gtk_widget_destroy (priv->popup); + priv->popup = NULL; + } + } + break; + } + + return GDK_FILTER_CONTINUE; +} + +static void +avatar_image_add_filter (EmpathyAvatarImage *avatar_image) +{ + Window window; + GdkWindow *gdkwindow; + gint mask; + + mask = PropertyChangeMask; + + window = GDK_ROOT_WINDOW (); + gdkwindow = gdk_xid_table_lookup (window); + + gdk_error_trap_push (); + if (gdkwindow) { + XWindowAttributes attrs; + XGetWindowAttributes (gdk_display, window, &attrs); + mask |= attrs.your_event_mask; + } + + XSelectInput (gdk_display, window, mask); + + gdk_error_trap_pop (); + + gdk_window_add_filter (NULL, avatar_image_filter_func, avatar_image); +} + +static void +avatar_image_remove_filter (EmpathyAvatarImage *avatar_image) +{ + gdk_window_remove_filter (NULL, avatar_image_filter_func, avatar_image); +} + +static gboolean +avatar_image_button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + EmpathyAvatarImagePriv *priv; + GtkWidget *popup; + GtkWidget *frame; + GtkWidget *image; + gint x, y; + gint popup_width, popup_height; + gint width, height; + GdkPixbuf *pixbuf; + + priv = GET_PRIV (widget); + + if (priv->popup) { + gtk_widget_destroy (priv->popup); + priv->popup = NULL; + } + + if (event->button != 1 || event->type != GDK_BUTTON_PRESS || !priv->pixbuf) { + return FALSE; + } + + popup_width = gdk_pixbuf_get_width (priv->pixbuf); + popup_height = gdk_pixbuf_get_height (priv->pixbuf); + + width = priv->image->allocation.width; + height = priv->image->allocation.height; + + /* Don't show a popup if the popup is smaller then the currently avatar + * image. + */ + if (popup_height <= height && popup_width <= width) { + return TRUE; + } + + pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_LARGE); + popup_width = gdk_pixbuf_get_width (pixbuf); + popup_height = gdk_pixbuf_get_height (pixbuf); + + popup = gtk_window_new (GTK_WINDOW_POPUP); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); + + gtk_container_add (GTK_CONTAINER (popup), frame); + + image = gtk_image_new (); + gtk_container_add (GTK_CONTAINER (frame), image); + + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + g_object_unref (pixbuf); + + gdk_window_get_origin (priv->image->window, &x, &y); + + x = x - (popup_width - width) / 2; + y = y - (popup_height - height) / 2; + + gtk_window_move (GTK_WINDOW (popup), x, y); + + priv->popup = popup; + + gtk_widget_show_all (popup); + + return TRUE; +} + +static gboolean +avatar_image_button_release_event (GtkWidget *widget, GdkEventButton *event) +{ + EmpathyAvatarImagePriv *priv; + + priv = GET_PRIV (widget); + + if (event->button != 1 || event->type != GDK_BUTTON_RELEASE) { + return FALSE; + } + + if (!priv->popup) { + return TRUE; + } + + gtk_widget_destroy (priv->popup); + priv->popup = NULL; + + return TRUE; +} + +GtkWidget * +empathy_avatar_image_new (void) +{ + EmpathyAvatarImage *avatar_image; + + avatar_image = g_object_new (EMPATHY_TYPE_AVATAR_IMAGE, NULL); + + return GTK_WIDGET (avatar_image); +} + +void +empathy_avatar_image_set (EmpathyAvatarImage *avatar_image, + EmpathyAvatar *avatar) +{ + EmpathyAvatarImagePriv *priv = GET_PRIV (avatar_image); + GdkPixbuf *scaled_pixbuf; + + g_return_if_fail (EMPATHY_IS_AVATAR_IMAGE (avatar_image)); + + if (priv->pixbuf) { + g_object_unref (priv->pixbuf); + priv->pixbuf = NULL; + } + + if (avatar) { + priv->pixbuf = empathy_pixbuf_from_data (avatar->data, avatar->len); + } + + if (!priv->pixbuf) { + gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), + "stock_person", + GTK_ICON_SIZE_DIALOG); + return; + } + + scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_SMALL); + gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled_pixbuf); + + if (scaled_pixbuf != priv->pixbuf) { + gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image), + _("Click to enlarge")); + } else { + gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image), + NULL); + } + + g_object_unref (scaled_pixbuf); +} + -- cgit v1.2.3