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 <gtk/gtk.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
# include "../gf_config.h"
#endif
#include "gf_internal.h"
#include <blist.h>
#include <debug.h>
#include <gtkutils.h>
#include <plugin.h>
#include <request.h>
#include <version.h>
#include "gf_blist.h"
#include "gf_notification.h"
#include "gf_theme.h"
#include "gf_theme_info.h"
#include "gf_utils.h"
#define GF_NODE_SETTING "guifications-theme"
/******************************************************************************
* Structs
*****************************************************************************/
typedef struct _GfBlistDialog {
PurpleBlistNode *node;
PurpleRequestField *theme_field;
gpointer handle;
} GfBlistDialog;
/******************************************************************************
* Enums
*****************************************************************************/
typedef enum _GfBlistThemeType {
GF_BLIST_THEME_UNASSIGNED = 0,
GF_BLIST_THEME_RANDOM,
GF_BLIST_THEME_NONE,
GF_BLIST_THEME_SPECIFIC,
GF_BLIST_THEME_TYPES
} GfBlistThemeType;
/******************************************************************************
* Globals
*****************************************************************************/
static GList *dialogs = NULL;
/******************************************************************************
* Dialog Callbacks
*****************************************************************************/
static void
gf_blist_dialog_ok_cb(gpointer data, PurpleRequestFields *fields) {
GfBlistDialog *diag = (GfBlistDialog *)data;
GList *l;
const gchar *name = NULL;
gint value = 0;
value = purple_request_field_choice_get_value(diag->theme_field);
l = purple_request_field_choice_get_labels(diag->theme_field);
name = g_list_nth_data(l, value);
if(diag->node) {
switch(value) {
case GF_BLIST_THEME_UNASSIGNED:
purple_blist_node_remove_setting(diag->node, GF_NODE_SETTING);
break;
case GF_BLIST_THEME_RANDOM:
purple_blist_node_set_string(diag->node, GF_NODE_SETTING,
"(RANDOM)");
break;
case GF_BLIST_THEME_NONE:
purple_blist_node_set_string(diag->node, GF_NODE_SETTING,
"(NONE)");
break;
default:
purple_blist_node_set_string(diag->node, GF_NODE_SETTING, name);
}
}
dialogs = g_list_remove(dialogs, diag);
g_free(diag);
}
static void
gf_blist_dialog_cancel_cb(gpointer data, PurpleRequestFields *fields) {
GfBlistDialog *diag = (GfBlistDialog *)data;
dialogs = g_list_remove(dialogs, diag);
g_free(diag);
}
/******************************************************************************
* Dialog Stuff
*****************************************************************************/
static void
gf_blist_dialog_new(PurpleBlistNode *node) {
GfBlistDialog *dialog = NULL;
PurpleRequestFields *fields;
PurpleRequestFieldGroup *group;
PurpleAccount *account = NULL;
GList *l;
gchar *info;
const gchar *name = NULL, *format = NULL, *current = NULL;
gint history = 0, i = 0;
dialog = g_new0(GfBlistDialog, 1);
if(!dialog)
return;
dialog->node = node;
/* wow this should really be in blist.[ch] someone remind me to
* write a patch at some point.
*/
if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
PurpleBuddy *buddy = (PurpleBuddy *)node;
if(buddy->alias)
name = buddy->alias;
else
name = buddy->name;
account = purple_buddy_get_account(buddy);
format = N_("Please select a theme for the buddy %s");
} else if(PURPLE_BLIST_NODE_IS_CONTACT(node)) {
PurpleContact *contact = (PurpleContact *)node;
if(contact->alias)
name = contact->alias;
else {
if(contact->priority->alias)
name = contact->priority->alias;
else
name = contact->priority->name;
}
format = N_("Please select a theme for the contact %s");
} else if(PURPLE_BLIST_NODE_IS_GROUP(node)) {
PurpleGroup *group = (PurpleGroup *)node;
name = group->name;
format = N_("Please select a theme for the group %s");
}
current = purple_blist_node_get_string(node, GF_NODE_SETTING);
fields = purple_request_fields_new();
group = purple_request_field_group_new(NULL);
purple_request_fields_add_group(fields, group);
dialog->theme_field = purple_request_field_choice_new("theme",
_("_Theme"), 1);
purple_request_field_group_add_field(group, dialog->theme_field);
purple_request_field_choice_add(dialog->theme_field, _("Clear setting"));
purple_request_field_choice_add(dialog->theme_field, _("Random"));
if(!gf_utils_strcmp("(RANDOM)", current))
history = GF_BLIST_THEME_RANDOM;
purple_request_field_choice_add(dialog->theme_field, _("None"));
if(!gf_utils_strcmp("(NONE)", current))
history = GF_BLIST_THEME_NONE;
for(l = gf_themes_get_loaded(); l; l = l->next) {
GfTheme *theme = GF_THEME(l->data);
GfThemeInfo *info = gf_theme_get_theme_info(theme);
const gchar *theme_name;
theme_name = gf_theme_info_get_name(info);
purple_request_field_choice_add(dialog->theme_field, theme_name);
if(!gf_utils_strcmp(theme_name, current))
history = i + GF_BLIST_THEME_SPECIFIC;
i++;
}
purple_request_field_choice_set_default_value(dialog->theme_field, history);
purple_request_field_choice_set_value(dialog->theme_field, history);
info = g_strdup_printf(_(format), name);
dialog->handle =
purple_request_fields(NULL, _("Select Guifications theme"),
NULL, info, fields,
_("OK"), G_CALLBACK(gf_blist_dialog_ok_cb),
_("Cancel"), G_CALLBACK(gf_blist_dialog_cancel_cb),
account, NULL, NULL, dialog);
g_free(info);
dialogs = g_list_append(dialogs, dialog);
}
/******************************************************************************
* Menu Callbacks
*****************************************************************************/
static void
gf_blist_menu_cb(PurpleBlistNode *node, gpointer data) {
/* Fix this up when we actually have a way to know if a request window
* is still visible, ie: remind me to write a patch for that and to
* "show" that window for a future pidgin release...
*/
gf_blist_dialog_new(node);
}
static void
gf_blist_drawing_menu_cb(PurpleBlistNode *node, GList **menu) {
PurpleMenuAction *action;
/* there's no point offering to save a theme for a node that
* won't be saved */
if (purple_blist_node_get_flags(node) & PURPLE_BLIST_NODE_FLAG_NO_SAVE)
return;
/* theres no way to get the name of a chat yet so we don't support
* them yet.
*/
if(PURPLE_BLIST_NODE_IS_CHAT(node))
return;
/* add a separator */
(*menu) = g_list_append(*menu, NULL);
/* add our menu item */
action = purple_menu_action_new(_("Guifications Theme"), PURPLE_CALLBACK(gf_blist_menu_cb), NULL, NULL);
(*menu) = g_list_append(*menu, action);
}
/******************************************************************************
* Subsystem
*****************************************************************************/
void
gf_blist_init(PurplePlugin *plugin) {
purple_signal_connect(purple_blist_get_handle(),
"blist-node-extended-menu",
plugin,
PURPLE_CALLBACK(gf_blist_drawing_menu_cb),
NULL);
}
void
gf_blist_uninit() {
GfBlistDialog *diag;
GList *l, *ll;
for(l = dialogs; l; l = ll) {
ll = l->next;
diag = (GfBlistDialog *)l->data;
purple_request_close(PURPLE_REQUEST_FIELDS, diag->handle);
dialogs = g_list_remove(dialogs, diag);
g_free(diag);
}
dialogs = NULL;
}
/* The pointer to a GfTheme is only used if gf_blist_get_theme_type returns
* GF_BLIST_THEME_SPECIFIC. If it returns random we handle that in the
* calling function.
*/
static GfBlistThemeType
gf_blist_get_theme_type(PurpleBlistNode *node, GfTheme **theme) {
const gchar *node_theme = NULL;
g_return_val_if_fail(node, GF_BLIST_THEME_NONE);
g_return_val_if_fail(theme, GF_BLIST_THEME_NONE);
node_theme = purple_blist_node_get_string(node, GF_NODE_SETTING);
if(!node_theme)
return GF_BLIST_THEME_UNASSIGNED;
if(!gf_utils_strcmp(node_theme, "(RANDOM)")) {
return GF_BLIST_THEME_RANDOM;
} else if(!gf_utils_strcmp(node_theme, "(NONE)")) {
return GF_BLIST_THEME_NONE;
} else {
*theme = gf_theme_find_theme_by_name(node_theme);
/* if the specific theme is not loaded we fallback to a random theme
* and do not touch the setting in the event that the user reloads
* said specific theme. In our words, lets not muck everything up if
* the user unloads a theme they don't mean to :)
*/
if(!*theme)
return GF_BLIST_THEME_RANDOM;
return GF_BLIST_THEME_SPECIFIC;
}
}
GfNotification *
gf_blist_get_notification_for_buddy(PurpleBuddy *buddy, const gchar *n_type) {
PurpleBlistNode *node = NULL;
g_return_val_if_fail(buddy, NULL);
g_return_val_if_fail(n_type, NULL);
node = (PurpleBlistNode *)buddy;
g_return_val_if_fail(node, NULL);
/* i don't really like the way this is setup.. but I also don't liek the
* idea of typing this out three times...
*/
while(node) {
GfBlistThemeType theme_type;
GfTheme *theme = NULL;
/* grab the theme type right away */
theme_type = gf_blist_get_theme_type(node, &theme);
/* then update the parent so we avoid excessive checking */
node = node->parent;
/* no theme set, check the parent */
if(theme_type == GF_BLIST_THEME_UNASSIGNED)
continue;
if(theme_type == GF_BLIST_THEME_RANDOM)
return gf_notification_find_for_event(n_type);
if(theme_type == GF_BLIST_THEME_NONE)
return NULL;
if(theme_type == GF_BLIST_THEME_SPECIFIC)
return gf_notification_find_for_theme(theme, n_type);
}
return gf_notification_find_for_event(n_type);
}