--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/guifications.c Sat Dec 27 14:14:38 2003 +0000
@@ -0,0 +1,626 @@
+ Guifications - The notification plugin to end all notification plugins! + Copyright (C) 2003 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 <gdk-pixbuf/gdk-pixbuf.h> +#include <pango/pango.h> +#include "conversation.h" +#include "guifications.h" +/********************************************************************** +***********************************************************************/ +GtkWidget *gf_window = NULL; +GtkWidget *gf_box = NULL; +/*********************************************************************** +***********************************************************************/ +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(GaimBuddy *buddy, gpointer data); +static void make_gf_window(); +static gint rem_guification(gpointer pguification); +static void destroy_guification(GtkWidget *guification); +static void gf_show_conv(GaimBuddy *buddy); +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_proto_menu_cb(GtkMenuItem *item, 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); +/*********************************************************************** +***********************************************************************/ +init_plugin(GaimPlugin *plugin) { +/**********************************************************************/ +static GaimGtkPluginUiInfo ui_info = { get_config_frame }; +/**********************************************************************/ +static GaimPluginInfo gf_info = { + GAIM_PLUGIN_STANDARD, /* type */ + GAIM_GTK_PLUGIN_TYPE, /* ui requirement */ + NULL, /* dependencies */ + GAIM_PRIORITY_DEFAULT, /* priority */ + my_version, /* version */ + my_summary, /* summary */ + my_description, /* description */ + my_authors, /* author */ + my_homepage, /* homepage */ + gf_unload, /* unload */ + &ui_info, /* ui info */ +/**********************************************************************/ +GAIM_INIT_PLUGIN(my_name, init_plugin, gf_info) +/**********************************************************************/ +gf_load(GaimPlugin *plugin) { + void *blist = gaim_blist_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), (gpointer)event_signon); + gaim_signal_connect(blist, "buddy-signed-off", plugin, GAIM_CALLBACK(gf_event), (gpointer)event_signoff); + gaim_signal_connect(blist, "buddy-away", plugin, GAIM_CALLBACK(gf_event), (gpointer)event_away); + gaim_signal_connect(blist, "buddy-back", plugin, GAIM_CALLBACK(gf_event), (gpointer)event_back); + gaim_signal_connect(blist, "buddy-idle", plugin, GAIM_CALLBACK(gf_event), (gpointer)event_idle); + gaim_signal_connect(blist, "buddy-unidle", plugin, GAIM_CALLBACK(gf_event), (gpointer)event_unidle); + if (gaim_connections_get_all()) +/**********************************************************************/ +gf_unload(GaimPlugin *plugin) { + g_slist_free(connecting); +/**********************************************************************/ +gf_event(GaimBuddy *buddy, gpointer data) { + gf_guification_event gf_new_event = (gf_guification_event)data; + GtkWidget *new_guification, *new_guification_box; + GdkPixbuf *pb_guification; + GdkPixmap *pm_guification; + dimensions img_size, zoom; + if (g_slist_find(connecting, buddy->account) != NULL) + if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOWAWAY)) + if (buddy->account->gc->away_state != NULL) + switch (gf_new_event) { + if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_SIGN_ON)) + if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_SIGN_OFF)) + if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_AWAY)) + if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_BACK)) + if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_IDLE)) + if (!gaim_prefs_get_bool(GF_PREF_BEHAVIOR_SHOW_UNIDLE)) + 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); + if (zoom.width != img_size.width || zoom.height != img_size.height) + pb_guification = gdk_pixbuf_scale_simple(pb_guification, zoom.width, zoom.height, GDK_INTERP_BILINEAR); + new_guification = gtk_image_new_from_pixbuf(pb_guification); + g_object_unref(pb_guification); + 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)) { + gtk_box_pack_start(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(gf_box), new_guification_box, FALSE, FALSE, 0); + 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); +/**********************************************************************/ +rem_guification(gpointer pguification) { + GtkWidget *guification = (GtkWidget*)pguification; + if (guification != NULL) + destroy_guification(guification); +/**********************************************************************/ +destroy_guification(GtkWidget *guification) { + if (guification != NULL) { + gtk_widget_destroy(guification); + gf_list = gtk_container_get_children(GTK_CONTAINER(gf_box)); + gtk_widget_destroy(gf_box); + gtk_widget_destroy(gf_window); + gf_resize(gf_window, gf_box); +/**********************************************************************/ + 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); + gf_box = gtk_hbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(gf_window), gf_box); + gtk_widget_show(gf_box); +/**********************************************************************/ +make_guification(GaimBuddy *buddy, gf_guification_event event) { + GdkPixbuf *background = NULL, *protocol = NULL; + PangoFontDescription *font_desc = NULL; + PangoLayout *layout_name, *layout_status; + gchar *name = "", *message = ""; + 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); + background = get_def_background_image(); + gdk_pixbuf_render_pixmap_and_mask(background, &memmap, NULL, 100); + g_object_unref(background); + if (gaim_prefs_get_int(GF_PREF_APPEARANCE_PROT_POS) != ipos_none) { + get_icon_pos(&px, &py); + protocol = get_proto_icon(buddy); + gdk_draw_pixbuf(GDK_DRAWABLE(memmap), gf_window->style->bg_gc[GTK_STATE_NORMAL], protocol, 0, 0, px, py, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0); + g_object_unref(protocol); + if (gaim_prefs_get_bool(GF_PREF_BEHAVIOR_ALIAS)) + name = g_strdup(gaim_get_buddy_alias(buddy)); + 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); + case event_signon: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_SIGN_ON)); break; + case event_signoff: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_SIGN_OFF)); break; + case event_away: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_AWAY)); break; + case event_back: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_BACK)); break; + case event_idle: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_IDLE)); break; + case event_unidle: message = g_strdup(gaim_prefs_get_string(GF_PREF_MESSAGES_UNIDLE)); break; + pango_layout_set_text(layout_name, name, -1); + pango_layout_set_text(layout_status, message, -1); + 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); + 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); + 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); +/**********************************************************************/ +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); +/**********************************************************************/ +gf_rem_account(void *paccount) { + GaimAccount *account = (GaimAccount*) paccount; + if (account == NULL || account->gc == NULL) { + connecting = g_slist_remove(connecting, account); + if (account->gc->state == GAIM_CONNECTING) + connecting = g_slist_remove(connecting, account); +/**********************************************************************/ +gf_clicked(GtkWidget *widget, GdkEventButton *event_button, gpointer data) { + GtkWidget *guification = (GtkWidget*)data, *menu, *item; + guint timeout_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(guification), "timeout")); + GaimBuddy *buddy = g_object_get_data(G_OBJECT(guification), "buddy"); + gboolean destroy = FALSE; + GaimPluginProtocolInfo *prplinfo = NULL; + 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 = mouse_destroy; break; + serv_get_info(buddy->account->gc, buddy->name); + case mouse_conversation: + gaim_gtk_log_show(buddy->name, buddy->account); + prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(gaim_find_prpl(gaim_account_get_protocol(buddy->account))); + 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); + if (prplinfo && prplinfo->buddy_menu) { + list = prplinfo->buddy_menu(buddy->account->gc, buddy->name); + struct proto_buddy_menu *pbm = list->data; + item = gtk_menu_item_new_with_mnemonic(pbm->label); + g_object_set_data(G_OBJECT(item), "gaimcallback", pbm); + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gf_proto_menu_cb), buddy); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + 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); + if (g_source_remove(timeout_id)) /* destroy if timer was found, else let timer destroy */ + destroy_guification(guification); +/**********************************************************************/ + GtkWidget *child = NULL; + GList *children = NULL; + children = gtk_container_get_children(GTK_CONTAINER(gf_box)); + 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); +/**********************************************************************/ +gf_show_conv(GaimBuddy *buddy) { + GaimConversation *conv; + 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(gaim_conversation_get_window(conv), gaim_conversation_get_index(conv)); + if (GAIM_IS_GTK_WINDOW(win)) + gtk_window_present(GTK_WINDOW(GAIM_GTK_WINDOW(win)->window)); +/**********************************************************************/ +gf_menu_info_cb(GtkWidget *widget, GaimBuddy *buddy) { + serv_get_info(buddy->account->gc, buddy->name); +/**********************************************************************/ +gf_menu_im_cb(GtkWidget *widget, GaimBuddy *buddy) { +/**********************************************************************/ +gf_menu_pounce_cb(GtkWidget *widget, GaimBuddy *buddy) { + gaim_gtkpounce_dialog_show(buddy->account, buddy->name, NULL); +/**********************************************************************/ +gf_menu_log_cb(GtkWidget *widget, GaimBuddy *buddy) { + gaim_gtk_log_show(buddy->name, buddy->account); +/**********************************************************************/ +gf_proto_menu_cb(GtkMenuItem *item, GaimBuddy *buddy) { + struct proto_buddy_menu *pbm = g_object_get_data(G_OBJECT(item), "gaimcallback"); + pbm->callback(pbm->gc, buddy->name); +/**********************************************************************/ +gf_menu_destroy(GtkWidget *widget, gpointer data) { + GtkWidget *guification = (GtkWidget*)data; + gint timeout = (gaim_prefs_get_int(GF_PREF_BEHAVIOR_TIMEOUT) * 1000) / 2; + timeout_id = gtk_timeout_add(timeout, rem_guification, guification); + g_object_set_data(G_OBJECT(guification), "timeout", GUINT_TO_POINTER(timeout_id)); +/**********************************************************************/ +gf_signed_on(GaimConnection *gc, void *data) { +/**********************************************************************/ + int last_checked = gaim_prefs_get_int(GF_PREF_ADVANCED_RELEASE_CHECK); + 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", my_version); + gaim_url_fetch(url, TRUE, NULL, FALSE, gf_release_check_cb, NULL); + gaim_prefs_set_int(GF_PREF_ADVANCED_RELEASE_CHECK, time(NULL)); +/**********************************************************************/ +gf_release_check_cb(void *userdata, const char *data, size_t len) { + const gchar *changelog = data; + gchar *cur_ver, *formatted; + /* I wasn't trying to rip Nathan's code.. but I couldn't find a + better way to do it... */ + if (!changelog || !len) + while (changelog[i] && changelog[i] != '\n') + cur_ver = g_strndup(changelog, i); + while (*changelog == '\n') + 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, my_version); + formatted = gaim_strdup_withhtml(changelog); + g_string_append_printf(notification, "<b>ChangeLog</b><br>%s<br>", 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); +/**********************************************************************/