grim/guifications2

Doing this so I can fix our tarball
org.guifications.gf2 gf_2_13beta7
2007-05-01, John Bailey
d9f3834d8f71
Doing this so I can fix our tarball
/*
* Guifications - The end all, be all, toaster popup plugin
* Copyright (C) 2003-2005 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <glib.h>
#include <gdk/gdk.h>
#include <debug.h>
#ifdef HAVE_CONFIG_H
# include "../gf_config.h"
#endif
#include "gf_event_info.h"
#include "gf_internal.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;
}