grim/guifications2

This was compatibility code for Pidgin 1.x.y; because it was written as a check
for "not 2.0.0" this code would be compiled in for 3.0.0. It looks like the
supporting code elsewhere was removed, causing this to leave an unresolved
symbol in guifications.so, thus causing Pidgin to refuse to load. Now we load
in Pidgin 3.0.0. Whether it works or not, I have no clue.
/*
* 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)
{
GfEvent *event;
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);
event = gf_event_info_get_event(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));
}