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 <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);
}