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 <gdk/gdk.h>
#include <debug.h>
#ifdef HAVE_CONFIG_H
# include "../gf_config.h"
#endif
#include "gf_internal.h"
#include "gf_event_info.h"
#include "gf_item.h"
#include "gf_item_icon.h"
#include "gf_item_image.h"
#include "gf_item_offset.h"
#include "gf_item_text.h"
#include "gf_notification.h"
#include "gf_preferences.h"
#include "gf_theme.h"
/* This setup sucks, but meh.. it works... be sure to update both the translated
* and the English versions if you add or remove anything. The english is used
* only for the files, so they're case insentive. The i18n are used in the
* theme editor.
*
* I'd fix this.. But whats translated doesn't match what is in the themes, and
* while we could use the text that's used in the theme's as display text, why
* mess with it while this, as ugly as it is, does work.
*/
const gchar *items_norm[] = { "icon", "image", "text", NULL };
const gchar *items_i18n[] = { N_("Icon"), N_("Image"), N_("Text"), NULL };
const gchar *positions_norm[] = { "north-west", "north", "north-east",
"west", "center", "east",
"south-west", "south", "south-east",
NULL };
const gchar *positions_i18n[] = { N_("North West"), N_("North"),
N_("North East"), N_("West"), N_("Center"),
N_("East"), N_("South West"), N_("South"),
N_("South East"), NULL };
struct _GfItem {
GfNotification *notification;
GfItemType type;
GfItemPosition position;
GfItemOffset *h_offset;
GfItemOffset *v_offset;
union {
GfItemIcon *icon;
GfItemText *text;
GfItemImage *image;
} u;
};
void
gf_item_get_render_position(gint *x, gint *y, gint width, gint height,
gint img_width, gint img_height, GfItem *item)
{
gint north, east, south, west, lat, lon;
gint item_h_w, item_h_h;
gint img_h_w, img_h_h;
gint h_offset, v_offset;
g_return_if_fail(item);
item_h_w = width / 2;
item_h_h = height / 2;
img_h_w = img_width / 2;
img_h_h = img_height / 2;
if(item->h_offset) {
if(gf_item_offset_get_is_percentage(item->h_offset))
h_offset = (img_width * gf_item_offset_get_value(item->h_offset)) / 100;
else
h_offset = gf_item_offset_get_value(item->h_offset);
} else {
h_offset = 0;
}
if(item->v_offset) {
if(gf_item_offset_get_is_percentage(item->v_offset))
v_offset = (img_height * gf_item_offset_get_value(item->v_offset)) / 100;
else
v_offset = gf_item_offset_get_value(item->v_offset);
} else {
v_offset = 0;
}
north = v_offset;
east = img_width - width + h_offset;
south = img_height - height + v_offset;
west = h_offset;
lon = img_h_w - item_h_w + h_offset;
lat = img_h_h - item_h_h + v_offset;
switch(item->position) {
case GF_ITEM_POSITION_NW: *x = west; *y = north; break;
case GF_ITEM_POSITION_N: *x = lon; *y = north; break;
case GF_ITEM_POSITION_NE: *x = east; *y = north; break;
case GF_ITEM_POSITION_W: *x = west; *y = lat; break;
case GF_ITEM_POSITION_C: *x = lon; *y = lat; break;
case GF_ITEM_POSITION_E: *x = east; *y = lat; break;
case GF_ITEM_POSITION_SW: *x = west; *y = south; break;
case GF_ITEM_POSITION_S: *x = lon; *y = south; break;
case GF_ITEM_POSITION_SE: *x = east; *y = south; break;
default: *x = 0; *y = 0; break;
}
}
const gchar *
gf_item_type_to_string(GfItemType type, gboolean i18n) {
g_return_val_if_fail(type < GF_ITEM_TYPE_UNKNOWN, NULL);
g_return_val_if_fail(type >= 0, NULL);
if(i18n)
return _(items_i18n[type]);
else
return items_norm[type];
}
GfItemType
gf_item_type_from_string(const gchar *string, gboolean i18n) {
gint i;
const gchar *val;
g_return_val_if_fail(string, GF_ITEM_TYPE_UNKNOWN);
for(i = 0; i < GF_ITEM_TYPE_UNKNOWN; i++) {
if(i18n)
val = _(items_i18n[i]);
else
val = items_norm[i];
if(!val)
return GF_ITEM_TYPE_UNKNOWN;
if(!g_ascii_strcasecmp(string, val))
return i;
}
return GF_ITEM_TYPE_UNKNOWN;
}
const gchar *
gf_item_position_to_string(GfItemPosition position, gboolean i18n) {
g_return_val_if_fail(position < GF_ITEM_POSITION_UNKNOWN, NULL);
g_return_val_if_fail(position >= 0, NULL);
if(i18n)
return _(positions_i18n[position]);
else
return positions_norm[position];
}
GfItemPosition
gf_item_position_from_string(const gchar *position, gboolean i18n) {
gint i;
const gchar *val;
g_return_val_if_fail(position, GF_ITEM_POSITION_UNKNOWN);
for(i = 0; i < GF_ITEM_POSITION_UNKNOWN; i++) {
if(i18n)
val = _(positions_i18n[i]);
else
val = positions_norm[i];
if(!val)
return GF_ITEM_POSITION_UNKNOWN;
if(!g_ascii_strcasecmp(val, position))
return i;
}
return GF_ITEM_POSITION_UNKNOWN;
}
GfItem *
gf_item_new(GfNotification *notification) {
GfItem *item;
g_return_val_if_fail(notification, NULL);
item = g_new0(GfItem, 1);
item->notification = notification;
return item;
}
GfItem *
gf_item_new_from_xmlnode(GfNotification *notification, xmlnode *node) {
GfItem *item;
xmlnode *child;
g_return_val_if_fail(node, NULL);
g_return_val_if_fail(notification, NULL);
item = gf_item_new(notification);
if(!item)
return NULL;
item->type = gf_item_type_from_string(xmlnode_get_attrib(node, "type"), FALSE);
if(item->type == GF_ITEM_TYPE_UNKNOWN) {
purple_debug_info("Guifications", "** Error: unknown item type\n");
gf_item_destroy(item);
return NULL;
}
if((child = xmlnode_get_child(node, "position"))) {
item->position = gf_item_position_from_string(xmlnode_get_attrib(child, "value"), FALSE);
if(item->position == GF_ITEM_POSITION_UNKNOWN) {
purple_debug_info("Guifications", "** Error: invalid position\n");
gf_item_destroy(item);
return NULL;
}
} else { /* if we don't have a position we drop the item */
purple_debug_info("Guifications", "** Error: no positioning found for item\n");
gf_item_destroy(item);
return NULL;
}
/* if we don't have an offset node, we create it anyways so it can be
* changed in the theme editor.
*/
if((child = xmlnode_get_child(node, "h_offset")))
item->h_offset = gf_item_offset_new_from_xmlnode(item, child);
if(!item->h_offset)
item->h_offset = gf_item_offset_new(item);
if((child = xmlnode_get_child(node, "v_offset")))
item->v_offset = gf_item_offset_new_from_xmlnode(item, child);
if(!item->v_offset)
item->v_offset = gf_item_offset_new(item);
switch(item->type) {
case GF_ITEM_TYPE_ICON:
if((child = xmlnode_get_child(node, "icon"))) {
item->u.icon = gf_item_icon_new_from_xmlnode(item, child);
if(!item->u.icon) {
gf_item_destroy(item);
return NULL;
}
} else {
purple_debug_info("Guifications", "** Error loading icon item: 'No icon element found'\n");
gf_item_destroy(item);
return NULL;
}
break;
case GF_ITEM_TYPE_IMAGE:
if((child = xmlnode_get_child(node, "image"))) {
item->u.image = gf_item_image_new_from_xmlnode(item, child);
if(!item->u.image) {
gf_item_destroy(item);
return NULL;
}
} else {
purple_debug_info("Guifications", "** Error loading image item: 'No image element found'\n");
gf_item_destroy(item);
return NULL;
}
break;
case GF_ITEM_TYPE_TEXT:
if((child = xmlnode_get_child(node, "text"))) {
item->u.text = gf_item_text_new_from_xmlnode(item, child);
if(!item->u.text) {
gf_item_destroy(item);
return NULL;
}
} else {
purple_debug_info("Guifications", "** Error loading text item: 'No text element found'\n");
gf_item_destroy(item);
return NULL;
}
break;
case GF_ITEM_TYPE_UNKNOWN:
default:
purple_debug_info("Guifications", "** Error loading item: 'Unknown item type'\n");
gf_item_destroy(item);
return NULL;
break;
}
return item;
}
GfItem *
gf_item_copy(GfItem *item) {
GfItem *new_item;
g_return_val_if_fail(item, NULL);
new_item = gf_item_new(item->notification);
new_item->type = item->type;
new_item->position = item->position;
new_item->h_offset = gf_item_offset_copy(item->h_offset);
new_item->v_offset = gf_item_offset_copy(item->v_offset);
if(item->type == GF_ITEM_TYPE_ICON)
new_item->u.icon = gf_item_icon_copy(item->u.icon);
else if(item->type == GF_ITEM_TYPE_ICON)
new_item->u.image = gf_item_image_copy(item->u.image);
else if(item->type == GF_ITEM_TYPE_TEXT)
new_item->u.text = gf_item_text_copy(item->u.text);
else {
gf_item_destroy(new_item);
new_item = NULL;
}
return new_item;
}
xmlnode *
gf_item_to_xmlnode(GfItem *item) {
gchar *offset;
xmlnode *parent, *child;
parent = xmlnode_new("item");
xmlnode_set_attrib(parent, "type", gf_item_type_to_string(item->type, FALSE));
child = xmlnode_new_child(parent, "position");
xmlnode_set_attrib(child, "value", gf_item_position_to_string(item->position, FALSE));
child = xmlnode_new_child(parent, "h_offset");
offset = g_strdup_printf("%d%s", gf_item_offset_get_value(item->h_offset),
gf_item_offset_get_is_percentage(item->h_offset) ? "%" : "");
xmlnode_set_attrib(child, "value", offset);
g_free(offset);
child = xmlnode_new_child(parent, "v_offset");
offset = g_strdup_printf("%d%s", gf_item_offset_get_value(item->v_offset),
gf_item_offset_get_is_percentage(item->v_offset) ? "%" : "");
xmlnode_set_attrib(child, "value", offset);
g_free(offset);
switch(item->type) {
case GF_ITEM_TYPE_ICON:
child = gf_item_icon_to_xmlnode(item->u.icon);
break;
case GF_ITEM_TYPE_IMAGE:
child = gf_item_image_to_xmlnode(item->u.image);
break;
case GF_ITEM_TYPE_TEXT:
child = gf_item_text_to_xmlnode(item->u.text);
break;
case GF_ITEM_TYPE_UNKNOWN:
default:
child = NULL;
}
if(child)
xmlnode_insert_child(parent, child);
return parent;
}
void
gf_item_destroy(GfItem *item) {
g_return_if_fail(item);
if(item->h_offset) {
gf_item_offset_destroy(item->h_offset);
item->h_offset = NULL;
}
if(item->v_offset) {
gf_item_offset_destroy(item->v_offset);
item->v_offset = NULL;
}
if(item->type == GF_ITEM_TYPE_ICON && item->u.icon) {
gf_item_icon_destroy(item->u.icon);
item->u.icon = NULL;
}
if(item->type == GF_ITEM_TYPE_IMAGE && item->u.image) {
gf_item_image_destroy(item->u.image);
item->u.image = NULL;
}
if(item->type == GF_ITEM_TYPE_TEXT && item->u.text) {
gf_item_text_destroy(item->u.text);
item->u.text = NULL;
}
g_free(item);
item = NULL;
}
void
gf_item_set_type(GfItem *item, GfItemType type) {
g_return_if_fail(item);
g_return_if_fail(type != GF_ITEM_TYPE_UNKNOWN);
item->type = type;
}
GfItemType
gf_item_get_type(GfItem *item) {
g_return_val_if_fail(item, GF_ITEM_TYPE_UNKNOWN);
return item->type;
}
void
gf_item_set_notification(GfItem *item, GfNotification *notification) {
g_return_if_fail(item);
g_return_if_fail(notification);
item->notification = notification;
}
GfNotification *
gf_item_get_notification(GfItem *item) {
g_return_val_if_fail(item, NULL);
return item->notification;
}
void
gf_item_set_horz_offset(GfItem *item, GfItemOffset *offset) {
g_return_if_fail(item);
g_return_if_fail(offset);
item->h_offset = offset;
}
GfItemOffset *
gf_item_get_horz_offset(GfItem *item) {
g_return_val_if_fail(item, NULL);
return item->h_offset;
}
void
gf_item_set_vert_offset(GfItem *item, GfItemOffset *offset) {
g_return_if_fail(item);
g_return_if_fail(offset);
item->v_offset = offset;
}
GfItemOffset *
gf_item_get_vert_offset(GfItem *item) {
g_return_val_if_fail(item, NULL);
return item->v_offset;
}
void
gf_item_set_position(GfItem *item, GfItemPosition position) {
g_return_if_fail(item);
g_return_if_fail(position != GF_ITEM_POSITION_UNKNOWN);
item->position = position;
}
GfItemPosition
gf_item_get_position(GfItem *item) {
g_return_val_if_fail(item, GF_ITEM_POSITION_UNKNOWN);
return item->position;
}
static void
gf_item_free_old_subtype(GfItem *item) {
if(item->type == GF_ITEM_TYPE_ICON && item->u.icon)
gf_item_icon_destroy(item->u.icon);
else if(item->type == GF_ITEM_TYPE_IMAGE && item->u.image)
gf_item_image_destroy(item->u.image);
else if(item->type == GF_ITEM_TYPE_TEXT && item->u.text)
gf_item_text_destroy(item->u.text);
}
void
gf_item_set_item_icon(GfItem *item, GfItemIcon *icon) {
g_return_if_fail(item);
g_return_if_fail(icon);
gf_item_free_old_subtype(item);
item->u.icon = icon;
}
GfItemIcon *
gf_item_get_item_icon(GfItem *item) {
g_return_val_if_fail(item->type == GF_ITEM_TYPE_ICON, NULL);
return item->u.icon;
}
void
gf_item_set_item_image(GfItem *item, GfItemImage *image) {
g_return_if_fail(item);
g_return_if_fail(image);
gf_item_free_old_subtype(item);
item->u.image = image;
}
GfItemImage *
gf_item_get_item_image(GfItem *item) {
g_return_val_if_fail(item->type == GF_ITEM_TYPE_IMAGE, NULL);
return item->u.image;
}
void
gf_item_set_item_text(GfItem *item, GfItemText *text) {
g_return_if_fail(item);
g_return_if_fail(text);
gf_item_free_old_subtype(item);
item->u.text = text;
}
GfItemText *
gf_item_get_item_text(GfItem *item) {
g_return_val_if_fail(item->type == GF_ITEM_TYPE_TEXT, NULL);
return item->u.text;
}
void
gf_item_render(GfItem *item, GdkPixbuf *pixbuf, GfEventInfo *info) {
g_return_if_fail(item);
g_return_if_fail(pixbuf);
g_return_if_fail(info);
switch(item->type) {
case GF_ITEM_TYPE_ICON:
gf_item_icon_render(item->u.icon, pixbuf, info);
break;
case GF_ITEM_TYPE_TEXT:
gf_item_text_render(item->u.text, pixbuf, info);
break;
case GF_ITEM_TYPE_IMAGE:
gf_item_image_render(item->u.image, pixbuf, info);
break;
default:
break;
}
};
void
gf_items_swap(GfItem *item1, GfItem *item2) {
GfItem *item = NULL;
GList *l = NULL, *l1 = NULL, *l2 = NULL;
g_return_if_fail(item1);
g_return_if_fail(item2);
g_return_if_fail(item1->notification == item2->notification);
for(l = gf_notification_get_items(item1->notification); l; l = l->next) {
if(l->data == item1)
l1 = l;
if(l->data == item2)
l2 = l;
}
g_return_if_fail(l1);
g_return_if_fail(l2);
item = l1->data;
l1->data = l2->data;
l2->data = item;
}