grim/guifications2

flow: Merged 'autotools_mingw_cleanup' to ('develop').
/*
* Guifications - The end all, be all, toaster popup plugin
* Copyright (C) 2003-2008 Gary Kramlich
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
*/
#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#ifdef HAVE_CONFIG_H
# include "../gf_config.h"
#endif
#include "gf_internal.h"
#include <account.h>
#include <buddyicon.h>
#include <debug.h>
#include <xmlnode.h>
#include <gtkblist.h>
#include <gtkutils.h>
#include <version.h>
#include "gf_gtk_utils.h"
#include "gf_item.h"
#include "gf_item_icon.h"
struct _GfItemIcon {
GfItem *item;
GfItemIconType type;
GfItemIconSize size;
};
static GfItemIconType
item_icon_type_from_string(const gchar *string) {
g_return_val_if_fail(string, GF_ITEM_ICON_TYPE_UNKNOWN);
if(!g_ascii_strcasecmp(string, "protocol"))
return GF_ITEM_ICON_TYPE_PROTOCOL;
else if(!g_ascii_strcasecmp(string, "buddy"))
return GF_ITEM_ICON_TYPE_BUDDY;
else if(!g_ascii_strcasecmp(string, "status"))
return GF_ITEM_ICON_TYPE_STATUS;
else
return GF_ITEM_ICON_TYPE_UNKNOWN;
}
static const gchar *
item_icon_type_to_string(GfItemIconType type) {
g_return_val_if_fail(type != GF_ITEM_ICON_TYPE_UNKNOWN, NULL);
switch(type) {
case GF_ITEM_ICON_TYPE_BUDDY: return "buddy"; break;
case GF_ITEM_ICON_TYPE_PROTOCOL: return "protocol"; break;
case GF_ITEM_ICON_TYPE_STATUS: return "status"; break;
case GF_ITEM_ICON_TYPE_UNKNOWN:
default: return NULL; break;
}
}
static GfItemIconSize
item_icon_size_from_string(const gchar *string) {
g_return_val_if_fail(string, GF_ITEM_ICON_SIZE_UNKNOWN);
if(!g_ascii_strcasecmp(string, "tiny"))
return GF_ITEM_ICON_SIZE_TINY;
else if(!g_ascii_strcasecmp(string, "small"))
return GF_ITEM_ICON_SIZE_SMALL;
else if(!g_ascii_strcasecmp(string, "little"))
return GF_ITEM_ICON_SIZE_LITTLE;
else if(!g_ascii_strcasecmp(string, "normal"))
return GF_ITEM_ICON_SIZE_NORMAL;
else if(!g_ascii_strcasecmp(string, "big"))
return GF_ITEM_ICON_SIZE_BIG;
else if(!g_ascii_strcasecmp(string, "large"))
return GF_ITEM_ICON_SIZE_LARGE;
else if(!g_ascii_strcasecmp(string, "huge"))
return GF_ITEM_ICON_SIZE_HUGE;
else
return GF_ITEM_ICON_SIZE_UNKNOWN;
}
static const gchar *
item_icon_size_to_string(GfItemIconSize size) {
g_return_val_if_fail(size != GF_ITEM_ICON_SIZE_UNKNOWN, NULL);
switch(size) {
case GF_ITEM_ICON_SIZE_HUGE: return "huge"; break;
case GF_ITEM_ICON_SIZE_LARGE: return "large"; break;
case GF_ITEM_ICON_SIZE_BIG: return "big"; break;
case GF_ITEM_ICON_SIZE_NORMAL: return "normal"; break;
case GF_ITEM_ICON_SIZE_LITTLE: return "little"; break;
case GF_ITEM_ICON_SIZE_SMALL: return "small"; break;
case GF_ITEM_ICON_SIZE_TINY: return "tiny"; break;
case GF_ITEM_ICON_SIZE_UNKNOWN:
default: return NULL; break;
}
}
void
gf_item_icon_destroy(GfItemIcon *item_icon) {
g_return_if_fail(item_icon);
item_icon->item = NULL;
item_icon->type = GF_ITEM_ICON_TYPE_UNKNOWN;
item_icon->size = GF_ITEM_ICON_SIZE_UNKNOWN;
g_free(item_icon);
item_icon = NULL;
}
GfItemIcon *
gf_item_icon_new(GfItem *item) {
GfItemIcon *item_icon;
g_return_val_if_fail(item, NULL);
item_icon = g_new0(GfItemIcon, 1);
item_icon->item = item;
return item_icon;
}
GfItemIcon *
gf_item_icon_new_from_xmlnode(GfItem *item, xmlnode *node) {
GfItemIcon *item_icon;
g_return_val_if_fail(item, NULL);
g_return_val_if_fail(node, NULL);
item_icon = gf_item_icon_new(item);
item_icon->type = item_icon_type_from_string(xmlnode_get_attrib(node, "type"));
if(item_icon->type == GF_ITEM_ICON_TYPE_UNKNOWN) {
purple_debug_info("Guifications", "** Error loading icon item: 'Unknown icon type'\n");
gf_item_icon_destroy(item_icon);
return NULL;
}
item_icon->size = item_icon_size_from_string(xmlnode_get_attrib(node, "size"));
if(item_icon->size == GF_ITEM_ICON_SIZE_UNKNOWN) {
purple_debug_info("Guifications", "** Error loading icon item: 'Unknown icon size'\n");
gf_item_icon_destroy(item_icon);
return NULL;
}
return item_icon;
}
GfItemIcon *
gf_item_icon_copy(GfItemIcon *icon) {
GfItemIcon *new_icon;
g_return_val_if_fail(icon, NULL);
new_icon = gf_item_icon_new(icon->item);
new_icon->type = icon->type;
new_icon->size = icon->size;
return new_icon;
}
xmlnode *
gf_item_icon_to_xmlnode(GfItemIcon *icon) {
xmlnode *parent;
parent = xmlnode_new("icon");
xmlnode_set_attrib(parent, "type", item_icon_type_to_string(icon->type));
xmlnode_set_attrib(parent, "size", item_icon_size_to_string(icon->size));
return parent;
}
void
gf_item_icon_set_type(GfItemIcon *icon, GfItemIconType type) {
g_return_if_fail(icon);
g_return_if_fail(type != GF_ITEM_ICON_TYPE_UNKNOWN);
icon->type = type;
}
GfItemIconType
gf_item_icon_get_type(GfItemIcon *icon) {
g_return_val_if_fail(icon, GF_ITEM_ICON_TYPE_UNKNOWN);
return icon->type;
}
void
gf_item_icon_set_size(GfItemIcon *icon, GfItemIconSize size) {
g_return_if_fail(icon);
g_return_if_fail(size != GF_ITEM_ICON_SIZE_UNKNOWN);
icon->size = size;
}
GfItemIconSize
gf_item_icon_get_size(GfItemIcon *icon) {
g_return_val_if_fail(icon, GF_ITEM_ICON_SIZE_UNKNOWN);
return icon->size;
}
void
gf_item_icon_set_item(GfItemIcon *icon, GfItem *item) {
g_return_if_fail(icon);
g_return_if_fail(item);
icon->item = item;
}
GfItem *
gf_item_icon_get_item(GfItemIcon *icon) {
g_return_val_if_fail(icon, NULL);
return icon->item;
}
static void
get_icon_dimensions(gint *width, gint *height, GfItemIconSize size) {
switch(size) {
case GF_ITEM_ICON_SIZE_TINY:
*width = *height = 16; break;
case GF_ITEM_ICON_SIZE_SMALL:
*width = *height = 24; break;
case GF_ITEM_ICON_SIZE_LITTLE:
*width = *height = 32; break;
case GF_ITEM_ICON_SIZE_BIG:
*width = *height = 64; break;
case GF_ITEM_ICON_SIZE_LARGE:
*width = *height = 96; break;
case GF_ITEM_ICON_SIZE_HUGE:
*width = *height = 144; break;
case GF_ITEM_ICON_SIZE_NORMAL:
default:
*width = *height = 48; break;
}
}
static void
get_icon_position(gint *x, gint *y,
gint img_width, gint img_height,
GfItemIcon *item_icon)
{
gint width = 0, height = 0;
g_return_if_fail(item_icon);
get_icon_dimensions(&width, &height, item_icon->size);
gf_item_get_render_position(x, y, width, height, img_width, img_height,
item_icon->item);
}
static GdkPixbuf *
gf_item_icon_get_buddy_icon(GfEventInfo *info) {
PurpleBuddyIcon *icon = NULL;
GdkPixbuf *ret = NULL;
icon = purple_buddy_icons_find(gf_event_info_get_account(info),
gf_event_info_get_target(info));
if(icon) {
GdkPixbufLoader *loader = NULL;
gconstpointer data = NULL;
size_t len = 0;
loader = gdk_pixbuf_loader_new();
data = purple_buddy_icon_get_data(icon, &len);
gdk_pixbuf_loader_write(loader, data, len, NULL);
if((ret = gdk_pixbuf_loader_get_pixbuf(loader)))
g_object_ref(G_OBJECT(ret));
gdk_pixbuf_loader_close(loader, NULL);
g_object_unref(G_OBJECT(loader));
}
return ret;
}
static inline GdkPixbuf *
gf_item_icon_stored_image_to_pixbuf(PurpleStoredImage *image) {
GdkPixbuf *ret = NULL;
GdkPixbufLoader *loader = NULL;
gconstpointer data = NULL;
size_t len = 0;
data = purple_imgstore_get_data(image);
if(!data)
return NULL;
len = purple_imgstore_get_size(image);
loader = gdk_pixbuf_loader_new();
gdk_pixbuf_loader_write(loader, data, len, NULL);
if((ret = gdk_pixbuf_loader_get_pixbuf(loader)))
g_object_ref(G_OBJECT(ret));
gdk_pixbuf_loader_close(loader, NULL);
g_object_unref(G_OBJECT(loader));
return ret;
}
static GdkPixbuf *
gf_item_icon_get_custom_buddy_icon(GfEventInfo *info) {
GdkPixbuf *ret = NULL;
PurpleBuddy *buddy = NULL;
buddy = gf_event_info_get_buddy(info);
if(!buddy)
return NULL;
if(purple_buddy_icons_node_has_custom_icon(PURPLE_BLIST_NODE(buddy))) {
PurpleStoredImage *image = NULL;
image =
purple_buddy_icons_node_find_custom_icon(PURPLE_BLIST_NODE(buddy));
if(image) {
ret = gf_item_icon_stored_image_to_pixbuf(image);
purple_imgstore_unref(image);
}
}
return ret;
}
void
gf_item_icon_render(GfItemIcon *item_icon, GdkPixbuf *pixbuf, GfEventInfo *info)
{
GdkPixbuf *original = NULL, *scaled = NULL;
gint x, y;
gint width, height;
gboolean is_contact;
g_return_if_fail(item_icon);
g_return_if_fail(pixbuf);
g_return_if_fail(info);
is_contact = gf_event_info_get_is_contact(info);
if(item_icon->type == GF_ITEM_ICON_TYPE_PROTOCOL) {
if(is_contact) {
gchar *filename;
filename = g_build_filename(DATADIR, "pixmaps", "pidgin.png",
NULL);
original = gdk_pixbuf_new_from_file(filename, NULL);
g_free(filename);
} else {
PurpleAccount *account = gf_event_info_get_account(info);
original = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_LARGE);
}
} else if(item_icon->type == GF_ITEM_ICON_TYPE_BUDDY) {
original = gf_item_icon_get_custom_buddy_icon(info);
if(!original)
original = gf_item_icon_get_buddy_icon(info);
} else if(item_icon->type == GF_ITEM_ICON_TYPE_STATUS) {
PurpleBuddy *buddy = NULL;
if((buddy = gf_event_info_get_buddy(info))) {
original = pidgin_blist_get_status_icon((PurpleBlistNode *)buddy,
PIDGIN_STATUS_ICON_LARGE);
}
}
/* if the original doesn't work for whatever reason we fallback to the
* protocol or the Pidgin guy(?) if it is a contact notification, this will
* be optional when we "enhance" the theme format. If it fails we return
* like we used to.
*/
if(!original) {
PurpleAccount *account = gf_event_info_get_account(info);
original = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_LARGE);
if(!original)
return;
}
get_icon_position(&x, &y,
gdk_pixbuf_get_width(pixbuf),
gdk_pixbuf_get_height(pixbuf),
item_icon);
get_icon_dimensions(&width, &height, item_icon->size);
scaled = gdk_pixbuf_scale_simple(original, width, height, GDK_INTERP_BILINEAR);
g_object_unref(G_OBJECT(original));
gf_gtk_pixbuf_clip_composite(scaled, x, y, pixbuf);
g_object_unref(G_OBJECT(scaled));
}