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 <stdlib.h>
#include <glib.h>
#include <gdk/gdk.h>
#ifdef HAVE_CONFIG_H
# include "../gf_config.h"
#endif
#include "gf_internal.h"
#include <debug.h>
#include <xmlnode.h>
#include "gf_event_info.h"
#include "gf_gtk_utils.h"
#include "gf_item.h"
#include "gf_notification.h"
#include "gf_preferences.h"
#include "gf_theme.h"
#include "gf_theme_ops.h"
#include "gf_utils.h"
struct _GfNotification {
GfTheme *theme;
gchar *n_type;
gchar *alias;
gboolean use_gtk;
gchar *background;
gint width;
gint height;
GList *items;
};
/*******************************************************************************
* API
******************************************************************************/
GfNotification *
gf_notification_new(GfTheme *theme) {
GfNotification *notification;
g_return_val_if_fail(theme, NULL);
notification = g_new0(GfNotification, 1);
notification->theme = theme;
notification->use_gtk = TRUE;
notification->height = 140;
notification->width = 120;
return notification;
}
GfNotification *
gf_notification_new_from_xmlnode(GfTheme *theme, xmlnode *node) {
GfNotification *notification;
GfItem *item;
xmlnode *child;
const gchar *data;
g_return_val_if_fail(theme, NULL);
g_return_val_if_fail(node, NULL);
notification = gf_notification_new(theme);
notification->n_type = g_strdup(xmlnode_get_attrib(node, "type"));
if(!notification->n_type) {
purple_debug_info("Guifications", "** Error: Notification type unknown\n");
gf_notification_destroy(notification);
return NULL;
}
if(!g_utf8_collate(notification->n_type, GF_NOTIFICATION_MASTER))
gf_theme_set_master(theme, notification);
data = xmlnode_get_attrib(node, "use_gtk");
if(data)
notification->use_gtk = atoi(data);
data = xmlnode_get_attrib(node, "background");
if(data)
notification->background = g_strdup(data);
data = xmlnode_get_attrib(node, "width");
if(data)
notification->width = atoi(data);
data = xmlnode_get_attrib(node, "height");
if(data)
notification->height = atoi(data);
data = xmlnode_get_attrib(node, "alias");
if(data)
notification->alias = g_strdup(data);
if(notification->use_gtk) {
if(notification->width < GF_NOTIFICATION_MIN ||
notification->height < GF_NOTIFICATION_MIN)
{
purple_debug_info("Guifications", "** Error: notification '%s' is using the "
"gtk background but %dx%d is less than the %dx%d minimum\n",
notification->n_type,
notification->width, notification->height,
GF_NOTIFICATION_MIN, GF_NOTIFICATION_MIN);
gf_notification_destroy(notification);
return NULL;
}
} else if(!notification->background) {
purple_debug_info("Guifications", "** Error: notification '%s' is not using the "
"gtk background and does not have a background image\n",
notification->n_type);
gf_notification_destroy(notification);
return NULL;
}
child = xmlnode_get_child(node, "item");
while(child) {
item = gf_item_new_from_xmlnode(notification, child);
if(item)
gf_notification_add_item(notification, item);
child = xmlnode_get_next_twin(child);
}
return notification;
}
GfNotification *
gf_notification_copy(GfNotification *notification) {
GfNotification *new_notification;
GList *l;
g_return_val_if_fail(notification, NULL);
new_notification = gf_notification_new(notification->theme);
if(notification->n_type)
new_notification->n_type = g_strdup(notification->n_type);
if(notification->background)
new_notification->background = g_strdup(notification->background);
if(notification->alias)
new_notification->alias = g_strdup(notification->alias);
new_notification->use_gtk = notification->use_gtk;
new_notification->width = notification->width;
new_notification->height = notification->height;
for(l = notification->items; l; l = l->next) {
GfItem *item;
item = gf_item_copy(GF_ITEM(l->data));
new_notification->items = g_list_append(new_notification->items, item);
}
return new_notification;
}
xmlnode *
gf_notification_to_xmlnode(GfNotification *notification) {
GList *l;
xmlnode *parent, *child;
gchar *data;
parent = xmlnode_new("notification");
xmlnode_set_attrib(parent, "type", notification->n_type);
xmlnode_set_attrib(parent, "use_gtk", (notification->use_gtk) ? "1" : "0");
if(notification->background)
xmlnode_set_attrib(parent, "background", notification->background);
if(notification->alias)
xmlnode_set_attrib(parent, "alias", notification->alias);
data = g_strdup_printf("%d", notification->width);
xmlnode_set_attrib(parent, "width", data);
g_free(data);
data = g_strdup_printf("%d", notification->height);
xmlnode_set_attrib(parent, "height", data);
g_free(data);
for(l = notification->items; l; l = l->next) {
if((child = gf_item_to_xmlnode(GF_ITEM(l->data))))
xmlnode_insert_child(parent, child);
}
return parent;
}
void
gf_notification_destroy(GfNotification *notification) {
GfItem *item;
GList *l;
g_return_if_fail(notification);
if(notification->n_type) {
g_free(notification->n_type);
notification->n_type = NULL;
}
if(notification->background) {
g_free(notification->background);
notification->background = NULL;
}
if(notification->alias) {
g_free(notification->alias);
notification->alias = NULL;
}
if(notification->items) {
for(l = notification->items; l; l = l->next) {
item = GF_ITEM(l->data);
gf_item_destroy(item);
}
g_list_free(notification->items);
notification->items = NULL;
}
g_free(notification);
}
void
gf_notification_set_type(GfNotification *notification, const gchar *n_type) {
g_return_if_fail(notification);
g_return_if_fail(n_type);
if(notification->n_type)
g_free(notification->n_type);
notification->n_type = g_strdup(n_type);
}
const gchar *
gf_notification_get_type(GfNotification *notification) {
g_return_val_if_fail(notification, NULL);
return notification->n_type;
}
void
gf_notification_set_use_gtk(GfNotification *notification, gboolean value) {
g_return_if_fail(notification);
notification->use_gtk = value;
}
gboolean
gf_notification_get_use_gtk(GfNotification *notification) {
g_return_val_if_fail(notification, FALSE);
return notification->use_gtk;
}
void
gf_notification_set_background(GfNotification *notification,
const gchar *background)
{
g_return_if_fail(notification);
if(notification->background)
g_free(notification->background);
notification->background = g_strdup(background);
}
const gchar *
gf_notification_get_background(GfNotification *notification) {
g_return_val_if_fail(notification, NULL);
return notification->background;
}
void
gf_notification_set_width(GfNotification *notification, gint width) {
g_return_if_fail(notification);
notification->width = width;
}
gint
gf_notification_get_width(GfNotification *notification) {
g_return_val_if_fail(notification, -1);
return notification->width;
}
void
gf_notification_set_height(GfNotification *notification, gint height) {
g_return_if_fail(notification);
notification->height = height;
}
gint
gf_notification_get_height(GfNotification *notification) {
g_return_val_if_fail(notification, -1);
return notification->height;
}
void
gf_notification_add_item(GfNotification *notification, GfItem *item) {
g_return_if_fail(notification);
g_return_if_fail(item);
notification->items = g_list_append(notification->items, item);
}
void
gf_notification_remove_item(GfNotification *notification, GfItem *item) {
g_return_if_fail(notification);
g_return_if_fail(item);
notification->items = g_list_remove(notification->items, item);
}
GList *
gf_notification_get_items(GfNotification *notification) {
g_return_val_if_fail(notification, NULL);
return notification->items;
}
const gchar *
gf_notification_get_alias(const GfNotification *notification) {
g_return_val_if_fail(notification, NULL);
return notification->alias;
}
void
gf_notification_set_alias(GfNotification *notification, const gchar *alias) {
g_return_if_fail(notification);
if(notification->alias)
g_free(notification->alias);
notification->alias = (alias) ? g_strdup(alias) : NULL;
}
/*******************************************************************************
* Finding, rendering, all that fun stuff...
******************************************************************************/
void
gf_notifications_swap(GfNotification *notification1, GfNotification *notification2) {
GfNotification *notification = NULL;
GList *l = NULL, *l1 = NULL, *l2 = NULL;
g_return_if_fail(notification1);
g_return_if_fail(notification2);
if(notification1->theme != notification2->theme)
return;
for(l = gf_theme_get_notifications(notification1->theme); l; l = l->next) {
if(l->data == notification1)
l1 = l;
if(l->data == notification2)
l2 = l;
}
g_return_if_fail(l1);
g_return_if_fail(l2);
/* swap 'em */
notification = l1->data;
l1->data = l2->data;
l2->data = notification;
}
GList *
gf_notifications_for_event(const gchar *n_type) {
GfTheme *theme;
GfNotification *notification;
GList *l = NULL, *t, *n;
g_return_val_if_fail(n_type, NULL);
for(t = gf_themes_get_loaded(); t; t = t->next) {
theme = GF_THEME(t->data);
for(n = gf_theme_get_notifications(theme); n; n = n->next) {
notification = GF_NOTIFICATION(n->data);
if(!g_ascii_strcasecmp(notification->n_type, n_type))
l = g_list_append(l, notification);
}
}
return l;
}
GfNotification *
gf_notification_find_for_event(const gchar *n_type) {
GfNotification *notification = NULL;
GList *n = NULL;
gint c;
g_return_val_if_fail(n_type, NULL);
n = gf_notifications_for_event(n_type);
if(!n)
return NULL;
c = rand() % g_list_length(n);
notification = GF_NOTIFICATION(g_list_nth_data(n, c));
g_list_free(n);
return notification;
}
GfNotification *
gf_notification_find_for_theme(GfTheme *theme, const gchar *n_type) {
GfNotification *notification = NULL;
GList *n = NULL, *t = NULL;
gint len;
g_return_val_if_fail(theme, NULL);
g_return_val_if_fail(n_type, NULL);
/* Get the list of notifications for a theme */
for(t = gf_theme_get_notifications(theme); t; t = t->next) {
notification = GF_NOTIFICATION(t->data);
if(notification == NULL)
continue;
if(!gf_utils_strcmp(notification->n_type, n_type))
n = g_list_append(n, notification);
}
len = g_list_length(n);
if(len == 0) {
notification = NULL;
} else if(len == 1) {
if(n != NULL)
notification = GF_NOTIFICATION(n->data);
else
notification = NULL;
} else {
gint c;
time_t t;
t = time(NULL);
srand(t);
c = rand() % len;
notification = GF_NOTIFICATION(g_list_nth_data(n, c));
}
g_list_free(n);
return notification;
}
GdkPixbuf *
gf_notification_render(GfNotification *notification, GfEventInfo *info) {
GfItem *item = NULL;
GdkPixbuf *pixbuf = NULL;
GList *l = NULL;
gchar *filename;
const gchar *path;
g_return_val_if_fail(notification, NULL);
g_return_val_if_fail(info, NULL);
if(notification->background) {
/* create the pixbuf, return if it failed */
path = gf_theme_get_path(notification->theme);
filename = g_build_filename(path, notification->background, NULL);
pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
g_free(filename);
if(!pixbuf) {
purple_debug_info("Guifications", "Couldn't not load notification background\n");
return NULL;
}
} else {
GdkPixmap *pixmap = NULL;
pixmap = gf_gtk_theme_get_bg_pixmap();
if(pixmap) {
GdkPixbuf *tile = NULL;
gint width, height;
gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &width, &height);
tile = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(pixmap), NULL,
0, 0, 0, 0, width, height);
if(!tile) {
purple_debug_info("Guifications", "Failed to get the gtk theme "
"background image\n");
return NULL;
}
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
notification->width, notification->height);
gf_gtk_pixbuf_tile(pixbuf, tile);
g_object_unref(G_OBJECT(tile));
} else {
GdkColor color;
guint32 pixel;
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
notification->width, notification->height);
if(!pixbuf) {
purple_debug_info("Guifications", "Failed to create notification background\n");
return NULL;
}
gf_gtk_theme_get_bg_color(&color);
pixel = gf_gtk_color_pixel_from_gdk(&color);
gdk_pixbuf_fill(pixbuf, pixel);
}
}
/* render the items */
for(l = notification->items; l; l = l->next) {
item = GF_ITEM(l->data);
gf_item_render(item, pixbuf, info);
}
/* display it already!! */
return pixbuf;
}
GfTheme *
gf_notification_get_theme(GfNotification *notification) {
g_return_val_if_fail(notification, NULL);
return notification->theme;
}