grim/guifications1

This should fix the Mdk 9.1 RPM building bug reported on the forums a while ago
/*
Guifications - The notification plugin to end all notification plugins!
Copyright (C) 2003-2004 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 <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <pango/pango.h>
#ifdef HAVE_CONFIG_H
# include "../gf_config.h"
#endif
#include "internal.h"
#include "plugin.h"
#include "account.h"
#include "blist.h"
#include "conversation.h"
#include "debug.h"
#include "gaim.h"
#include "gtkblist.h"
#include "gtklog.h"
#include "gtkplugin.h"
#include "gtkpounce.h"
#include "gtkutils.h"
#include "multi.h"
#include "notify.h"
#include "prefs.h"
#include "server.h"
#include "stock.h"
#include "util.h"
#include "guifications.h"
#include "gf_types.h"
#include "gf_conf.h"
#include "gf_prefs.h"
#include "gf_utils.h"
#include "gf_pngs.h"
/**********************************************************************
Globals
***********************************************************************/
GSList *connecting;
GtkWidget *gf_window = NULL;
GtkWidget *gf_box = NULL;
/***********************************************************************
Static prototypes
***********************************************************************/
static gboolean gf_load(GaimPlugin *plugin);
static gboolean gf_unload(GaimPlugin *plugin);
static void init_plugin(GaimPlugin *plugin);
static void gf_account(GaimAccount *account, void *data);
static gint gf_rem_account(gpointer account);
static void gf_event_cb(GaimBuddy *buddy, gpointer data);
static gboolean gf_message_cb(GaimAccount *account, char *sender, char *message, int flags, void *data);
static void make_gf_window();
static gint rem_guification(gpointer pguification);
static void destroy_guification(GtkWidget *guification);
/* helpers */
static void gf_show_conv(GaimBuddy *buddy);
/* Call backs */
static void gf_clicked(GtkWidget *widget, GdkEventButton *event_button, gpointer data);
static void gf_menu_info_cb(GtkWidget *widget, GaimBuddy *buddy);
static void gf_menu_im_cb(GtkWidget *widget, GaimBuddy *buddy);
static void gf_menu_pounce_cb(GtkWidget *widget, GaimBuddy *buddy);
static void gf_menu_log_cb(GtkWidget *widget, GaimBuddy *buddy);
static void gf_menu_destroy(GtkWidget *widget, gpointer data);
static void gf_signed_on(GaimConnection *gc, void *data);
static void gf_release_check();
static void gf_release_check_cb(void *userdata, const char *data, size_t len);
/***********************************************************************
Plugin registration
***********************************************************************/
static void
init_plugin(GaimPlugin *plugin) {
gf_add_prefs();
}
static GaimGtkPluginUiInfo ui_info = { get_config_frame };
static GaimPluginInfo gf_info = {
GAIM_PLUGIN_API_VERSION, /* api version */
GAIM_PLUGIN_STANDARD, /* type */
GAIM_GTK_PLUGIN_TYPE, /* ui requirement */
0, /* flags */
NULL, /* dependencies */
GAIM_PRIORITY_DEFAULT, /* priority */
"Gtk-amc_grim-Guifications", /* id */
"Guifications", /* name */
GF_VERSION, /* version */
"The notification plugin to end all notification" /* summary */
"plugins!",
"Guifications: The Pimpin' Penguin Notification" /* description */
"Plugin thats good for the soul!",
"Gary Kramlich \
<amc_grim@users.sf.net>", /* author */
"http://guifications.sourceforge.net/Guifications/", /* homepage */
gf_load, /* load */
gf_unload, /* unload */
NULL, /* destroy */
&ui_info, /* ui info */
NULL, /* extra info */
NULL, /* prefs info */
NULL /* actions info */
};
GAIM_INIT_PLUGIN(my_name, init_plugin, gf_info)
/***********************************************************************
* Internal
**********************************************************************/
static gboolean
gf_load(GaimPlugin *plugin) {
void *blist = gaim_blist_get_handle();
void *conversation = gaim_conversations_get_handle();
gaim_signal_connect(gaim_accounts_get_handle(), "account-connecting", plugin, GAIM_CALLBACK(gf_account), NULL);
gaim_signal_connect(gaim_connections_get_handle(), "signed-on", plugin, GAIM_CALLBACK(gf_signed_on), NULL);
gaim_signal_connect(blist, "buddy-signed-on", plugin, GAIM_CALLBACK(gf_event_cb), (gpointer)gf_event_signon);
gaim_signal_connect(blist, "buddy-signed-off", plugin, GAIM_CALLBACK(gf_event_cb), (gpointer)gf_event_signoff);
gaim_signal_connect(blist, "buddy-away", plugin, GAIM_CALLBACK(gf_event_cb), (gpointer)gf_event_away);
gaim_signal_connect(blist, "buddy-back", plugin, GAIM_CALLBACK(gf_event_cb), (gpointer)gf_event_back);
gaim_signal_connect(blist, "buddy-idle", plugin, GAIM_CALLBACK(gf_event_cb), (gpointer)gf_event_idle);
gaim_signal_connect(blist, "buddy-unidle", plugin, GAIM_CALLBACK(gf_event_cb), (gpointer)gf_event_unidle);
gaim_signal_connect(conversation, "received-im-msg", plugin, GAIM_CALLBACK(gf_message_cb), (gpointer)gf_event_rcv_msg);
if (gaim_connections_get_all())
gf_release_check();
return TRUE;
}
static gboolean
gf_unload(GaimPlugin *plugin) {
g_slist_free(connecting);
return TRUE;
}
static void
gf_remove_old_notification(GaimBuddy *buddy) {
GaimBuddy *old_buddy;
GtkWidget *gf;
GList *l, *ll;
gint timeout_id;
for(l = gtk_container_get_children(GTK_CONTAINER(gf_box)); l; l = ll) {
ll = l->next;
gf = l->data;
old_buddy = g_object_get_data(G_OBJECT(gf), "buddy");
if(old_buddy == buddy) {
timeout_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gf), "timeout"));
g_source_remove(timeout_id);
gtk_widget_destroy(gf);
g_list_free(l);
return;
}
}
}
static gboolean
gf_message_cb(GaimAccount *account, char *sender, char *message, int flags,
void *data)
{
GaimBuddy *buddy;
buddy = gaim_find_buddy(account, sender);
if(buddy)
gf_event_cb(gaim_find_buddy(account,sender),data);
return FALSE;
}
static void
gf_event_cb(GaimBuddy *buddy, gpointer data) {
gf_event gf_new_event = (gf_event)data;
GtkWidget *new_guification, *new_guification_box;
GdkPixbuf *pb_guification, *scaled;
GdkPixmap *pm_guification;
gboolean vertical;
guint timeout_id = 0;
dimensions img_size, zoom;
if (g_slist_find(connecting, buddy->account) != NULL)
return;
/* snakez */
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOWAWAY))
if (buddy->account->gc->away_state != NULL)
return;
switch (gf_new_event) {
case gf_event_signon:
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_SIGN_ON))
return;
break;
case gf_event_signoff:
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_SIGN_OFF))
return;
break;
case gf_event_away:
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_AWAY))
return;
break;
case gf_event_back:
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_BACK))
return;
break;
case gf_event_idle:
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_IDLE))
return;
break;
case gf_event_unidle:
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_UNIDLE))
return;
break;
case gf_event_rcv_msg:
if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_RECEIVE_MESSAGES))
return;
break;
case gf_event_custom:
return;
}
if (gf_window == NULL)
make_gf_window();
/* kill old guifications.. like back when they've really signed off */
gf_remove_old_notification(buddy);
get_image_size(&img_size);
pm_guification = make_guification(buddy, gf_new_event);
get_zoom_size(img_size, &zoom);
pb_guification = gdk_pixbuf_get_from_drawable(NULL, pm_guification, NULL, 0, 0, 0, 0, -1, -1);
g_object_unref(pm_guification);
scaled = gdk_pixbuf_scale_simple(pb_guification, zoom.width, zoom.height, GDK_INTERP_BILINEAR);
g_object_unref(G_OBJECT(pb_guification));
new_guification = gtk_image_new_from_pixbuf(scaled);
g_object_unref(G_OBJECT(scaled));
gtk_widget_set_size_request(new_guification, zoom.width, zoom.height);
new_guification_box = gtk_event_box_new();
gtk_widget_set_events(new_guification_box, GDK_BUTTON_PRESS);
g_object_set_data(G_OBJECT(new_guification_box), "buddy", buddy);
gtk_container_add(GTK_CONTAINER(new_guification_box), new_guification);
vertical = gaim_prefs_get_bool(GF_PREF_BEHAVIOR_WINDOW_VERTICAL);
switch (gaim_prefs_get_int(GF_PREF_BEHAVIOR_WINDOW_POS)) {
case window_position_nw:
gtk_box_pack_start(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0);
break;
case window_position_ne:
if (vertical)
gtk_box_pack_start(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0);
else
gtk_box_pack_end(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0);
break;
case window_position_sw:
if (vertical)
gtk_box_pack_end(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0);
else
gtk_box_pack_start(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0);
break;
case window_position_se:
gtk_box_pack_end(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0);
break;
}
gtk_widget_show(new_guification);
gtk_widget_show(new_guification_box);
gf_resize(gf_window, gf_box);
g_signal_connect(G_OBJECT(new_guification_box), "button-press-event", G_CALLBACK(gf_clicked), new_guification_box);
timeout_id = gtk_timeout_add(gaim_prefs_get_int(GF_PREF_BEHAVIOR_TIMEOUT) * 1000, rem_guification, new_guification_box);
g_object_set_data(G_OBJECT(new_guification_box), "timeout", GUINT_TO_POINTER(timeout_id));
if (!GTK_WIDGET_VISIBLE(gf_window))
gtk_widget_show_all(gf_window);
}
static gint
rem_guification(gpointer pguification) {
GtkWidget *guification = (GtkWidget*)pguification;
if (guification != NULL)
destroy_guification(guification);
return FALSE;
}
static void
destroy_guification(GtkWidget *guification) {
GList *gf_list = NULL;
if (guification != NULL) {
gtk_widget_destroy(guification);
guification = NULL;
if (gf_box != NULL) {
gf_list = gtk_container_get_children(GTK_CONTAINER(gf_box));
if (gf_list == NULL) {
gtk_widget_destroy(gf_box);
gf_box = NULL;
gtk_widget_destroy(gf_window);
gf_window = NULL;
}
else {
gf_resize(gf_window, gf_box);
}
g_list_free(gf_list);
gf_list = NULL;
}
}
}
static void
make_gf_window() {
dimensions def_size;
gf_window = gtk_window_new(GTK_WINDOW_POPUP);
get_image_size(&def_size);
gtk_window_set_default_size(GTK_WINDOW(gf_window), def_size.width, def_size.height);
gtk_widget_realize(gf_window);
if (gaim_prefs_get_bool(GF_PREF_BEHAVIOR_WINDOW_VERTICAL))
gf_box = gtk_vbox_new(FALSE, 0);
else
gf_box = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(gf_window), gf_box);
gtk_widget_show(gf_box);
}
GdkPixmap *
make_guification(GaimBuddy *buddy, gf_event event) {
GdkPixbuf *background = NULL, *protocol = NULL, *protocol_scaled = NULL;
GdkPixmap *memmap = NULL;
PangoContext *context;
PangoFontDescription *font_desc = NULL;
PangoLayout *layout_name, *layout_status;
gchar *name = "", *message = "";
gint x, y;
gint px, py;
gint psize = get_icon_size();
if (gaim_prefs_get_bool(GF_PREF_APPEARANCE_IMAGE))
background = gdk_pixbuf_new_from_file(gaim_prefs_get_string(GF_PREF_APPEARANCE_IMAGE_FILE), NULL);
else
background = get_def_background_image();
gdk_pixbuf_render_pixmap_and_mask(background, &memmap, NULL, 100);
g_object_unref(G_OBJECT(background));
get_icon_pos(&px, &py);
protocol = create_prpl_icon(buddy->account);
protocol_scaled = gdk_pixbuf_scale_simple(protocol, psize, psize,
GDK_INTERP_BILINEAR);
g_object_unref(G_OBJECT(protocol));
gdk_draw_pixbuf(GDK_DRAWABLE(memmap),
gf_window->style->bg_gc[GTK_STATE_NORMAL], protocol_scaled,
0, 0, px, py, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0);
g_object_unref(G_OBJECT(protocol_scaled));
if (gaim_prefs_get_bool(GF_PREF_BEHAVIOR_ALIAS))
name = g_strdup(gaim_get_buddy_alias(buddy));
else
name = g_strdup(buddy->name);
/* get pango context and setup layouts */
context = gtk_widget_get_pango_context(gf_window);
layout_name = pango_layout_new(context);
pango_layout_set_width(layout_name, -1);
layout_status = pango_layout_new(context);
pango_layout_set_width(layout_status, -1);
if (gaim_prefs_get_bool(GF_PREF_APPEARANCE_FONT)) {
font_desc = pango_font_description_from_string(gaim_prefs_get_string(GF_PREF_APPEARANCE_FONT_FACE));
pango_layout_set_font_description(layout_name, font_desc);
pango_layout_set_font_description(layout_status, font_desc);
pango_font_description_free(font_desc);
}
switch (event) {
case gf_event_signon: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_SIGN_ON)); break;
case gf_event_signoff: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_SIGN_OFF)); break;
case gf_event_away: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_AWAY)); break;
case gf_event_back: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_BACK)); break;
case gf_event_idle: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_IDLE)); break;
case gf_event_unidle: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_UNIDLE)); break;
case gf_event_rcv_msg: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_RECEIVE)); break;
case gf_event_custom: return NULL; break; /* not yet implemented */
}
pango_layout_set_text(layout_name, name, -1);
pango_layout_set_text(layout_status, message, -1);
g_free(name);
g_free(message);
clip_layout(&layout_name, gaim_prefs_get_bool(GF_PREF_APPEARANCE_COLOR), GF_PREF_APPEARANCE_TEXT_X, GF_PREF_COLORS_FOREGROUND);
clip_layout(&layout_status, gaim_prefs_get_bool(GF_PREF_APPEARANCE_COLOR), GF_PREF_APPEARANCE_TEXT_X, GF_PREF_COLORS_FOREGROUND);
/* draw buddy name */
get_text_pos(&x, &y, TRUE, layout_name);
gdk_draw_layout(GDK_DRAWABLE(memmap), gf_window->style->bg_gc[GTK_STATE_NORMAL], x, y, layout_name);
g_object_unref(layout_name);
/* draw status */
get_text_pos(&x, &y, FALSE, layout_status);
gdk_draw_layout(GDK_DRAWABLE(memmap), gf_window->style->bg_gc[GTK_STATE_NORMAL], x, y, layout_status);
g_object_unref(layout_status);
return memmap;
}
static void
gf_account(GaimAccount *account, void *data) {
if (g_slist_find(connecting, account) == NULL) {
connecting = g_slist_append(connecting, account);
gtk_timeout_add(gaim_prefs_get_int(GF_PREF_ADVANCED_DELAY), gf_rem_account, account);
}
}
static gint
gf_rem_account(void *paccount) {
GaimAccount *account = (GaimAccount*) paccount;
if (account == NULL)
return FALSE;
if(account->gc == NULL) {
connecting = g_slist_remove(connecting, account);
return FALSE;
}
if (account->gc->state == GAIM_CONNECTING)
return TRUE;
connecting = g_slist_remove(connecting, account);
return FALSE;
}
static void
gf_clicked(GtkWidget *widget, GdkEventButton *event_button, gpointer data) {
GtkWidget *guification = (GtkWidget*)data, *menu;
guint timeout_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(guification), "timeout"));
GaimBuddy *buddy = g_object_get_data(G_OBJECT(guification), "buddy");
GaimConnection *gc;
gboolean destroy = FALSE;
GaimPluginProtocolInfo *prplinfo = NULL;
gf_window_mouse action;
switch (event_button->button) {
case 1: action = gaim_prefs_get_int(GF_PREF_BEHAVIOR_MOUSE1); break;
case 2: action = gaim_prefs_get_int(GF_PREF_BEHAVIOR_MOUSE2); break;
case 3: action = gaim_prefs_get_int(GF_PREF_BEHAVIOR_MOUSE3); break;
default: action = window_mouse_destroy; break;
}
switch (action) {
case window_mouse_destroy:
destroy = TRUE;
break;
case window_mouse_info:
serv_get_info(buddy->account->gc, buddy->name);
destroy = TRUE;
break;
case window_mouse_conversation:
gf_show_conv(buddy);
destroy = TRUE;
break;
case window_mouse_log:
gaim_gtk_log_show(buddy->name, buddy->account);
destroy = TRUE;
break;
case window_mouse_context:
prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(gaim_find_prpl(gaim_account_get_protocol_id(buddy->account)));
menu = gtk_menu_new();
if (prplinfo && prplinfo->get_info)
gaim_new_item_from_stock(menu, _("_Get Info"), GAIM_STOCK_INFO, G_CALLBACK(gf_menu_info_cb), buddy, 0, 0, NULL);
gaim_new_item_from_stock(menu, _("_IM"), GAIM_STOCK_IM, G_CALLBACK(gf_menu_im_cb), buddy, 0, 0, NULL);
gaim_new_item_from_stock(menu, _("Add Buddy _Pounce"), NULL, G_CALLBACK(gf_menu_pounce_cb), buddy, 0, 0, NULL);
gaim_new_item_from_stock(menu, _("View _Log"), NULL, G_CALLBACK(gf_menu_log_cb), buddy, 0, 0, NULL);
gc = gaim_account_get_connection(buddy->account);
gaim_gtk_append_blist_node_proto_menu (menu, gc, (GaimBlistNode*)buddy);
gaim_gtk_append_blist_node_extended_menu(menu, (GaimBlistNode*)buddy);
g_source_remove(timeout_id);
g_signal_connect(G_OBJECT(menu), "hide", G_CALLBACK(gf_menu_destroy), guification);
gtk_widget_show_all(menu);
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time);
destroy = FALSE;
break;
default:
destroy = TRUE;
break;
}
if (destroy)
if (g_source_remove(timeout_id)) /* destroy if timer was found, else let timer destroy */
destroy_guification(guification);
}
void
gf_destroy_all() {
GtkWidget *child = NULL;
GList *children = NULL;
guint timeout_id = 0;
if (gf_box != NULL) {
children = gtk_container_get_children(GTK_CONTAINER(gf_box));
while (children) {
child = children->data;
children = children->next;
timeout_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(child), "timeout"));
g_source_remove(timeout_id);
destroy_guification(child);
}
g_list_free(children);
}
}
static void
gf_show_conv(GaimBuddy *buddy) {
GaimConversation *conv;
GaimConvWindow *win;
conv = gaim_conversation_new(GAIM_CONV_IM, buddy->account, buddy->name);
win = gaim_conversation_get_window(conv);
gaim_conv_window_raise(win);
gaim_conv_window_switch_conversation(win, gaim_conversation_get_index(conv));
if (GAIM_IS_GTK_WINDOW(win))
gtk_window_present(GTK_WINDOW(GAIM_GTK_WINDOW(win)->window));
}
static void
gf_menu_info_cb(GtkWidget *widget, GaimBuddy *buddy) {
serv_get_info(buddy->account->gc, buddy->name);
}
static void
gf_menu_im_cb(GtkWidget *widget, GaimBuddy *buddy) {
gf_show_conv(buddy);
}
static void
gf_menu_pounce_cb(GtkWidget *widget, GaimBuddy *buddy) {
gaim_gtkpounce_dialog_show(buddy->account, buddy->name, NULL);
}
static void
gf_menu_log_cb(GtkWidget *widget, GaimBuddy *buddy) {
gaim_gtk_log_show(buddy->name, buddy->account);
}
static void
gf_menu_destroy(GtkWidget *widget, gpointer data) {
GtkWidget *guification = (GtkWidget*)data;
gint timeout = (gaim_prefs_get_int(GF_PREF_BEHAVIOR_TIMEOUT) * 1000) / 2;
guint timeout_id;
timeout_id = gtk_timeout_add(timeout, rem_guification, guification);
g_object_set_data(G_OBJECT(guification), "timeout", GUINT_TO_POINTER(timeout_id));
}
static void
gf_signed_on(GaimConnection *gc, void *data) {
gf_release_check();
}
static void
gf_release_check() {
int last_checked = gaim_prefs_get_int(GF_PREF_ADVANCED_RELEASE_CHECK);
gchar *url;
if (gaim_prefs_get_bool(GF_PREF_ADVANCED_RELEASE)) {
if (!last_checked || time(NULL) - last_checked > 86400 /* one day */) {
url = g_strdup_printf("http://guifications.sourceforge.net/version.php?version=%s", GF_VERSION);
gaim_url_fetch(url, TRUE, NULL, FALSE, gf_release_check_cb, NULL);
gaim_prefs_set_int(GF_PREF_ADVANCED_RELEASE_CHECK, time(NULL));
g_free(url);
}
}
}
static void
gf_release_check_cb(void *userdata, const char *data, size_t len) {
const gchar *changelog = data;
GString *notification;
gchar *cur_ver, *formatted;
gint i = 0;
/* I wasn't trying to rip Nathan's code.. but I couldn't find a
better way to do it... */
if (!changelog || !len)
return;
while (changelog[i] && changelog[i] != '\n')
i++;
cur_ver = g_strndup(changelog, i);
changelog += i;
while (*changelog == '\n')
changelog++;
notification = g_string_new("");
g_string_append_printf(notification, "There is a new version of Guifications (%s) available, you are running version %s.<hr>", cur_ver, GF_VERSION);
if (*changelog) {
formatted = gaim_strdup_withhtml(changelog);
g_string_append_printf(notification, "<b>ChangeLog</b><br>%s<br>", formatted);
g_free(formatted);
}
g_string_append_printf(notification, "You can download version %s from <a href=\"http://guifications.sourceforge.net/\">http://guifications.sourceforge.net</a>.", cur_ver);
gaim_notify_formatted(NULL, "New version of Guifications available", "New version of Guifications available", NULL, notification->str, NULL, NULL);
g_string_free(notification, TRUE);
g_free(cur_ver);
}