pidgin/plugins/convcolors.c

Tue, 07 May 2013 05:04:46 -0400

author
Elliott Sales de Andrade <qulogic@pidgin.im>
date
Tue, 07 May 2013 05:04:46 -0400
changeset 33923
0fcc5635daba
parent 33683
bf243e3394a7
child 34477
86f6c431da7b
child 34660
68c776e3436e
permissions
-rw-r--r--

Rewrite debug window filter in JS.

Note, this does cause a couple regressions, but they are probably not
that big a deal. First, the JS regular expression syntax is slightly
different. Second, the JS regex API lacks a way to reliably determine
the location of matched groups, so we can't highlight just the groups
and must highlight the entire expression.

I suspect that none of our users ever had to use any fancy regex in the
debug window, and that most of our developers didn't even know it could
be done. So I doubt these regressions will cause much pain.

/*
 * Conversation Colors
 * Copyright (C) 2006
 *
 * 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 "internal.h"

#define PLUGIN_ID			"gtk-plugin_pack-convcolors"
#define PLUGIN_NAME			N_("Conversation Colors")
#define PLUGIN_STATIC_NAME	ConversationColors
#define PLUGIN_SUMMARY		N_("Customize colors in the conversation window")
#define PLUGIN_DESCRIPTION	N_("Customize colors in the conversation window")
#define PLUGIN_AUTHOR		"Sadrul H Chowdhury <sadrul@users.sourceforge.net>"

/* System headers */
#include <gdk/gdk.h>
#include <glib.h>
#include <gtk/gtk.h>

/* Purple headers */
#include <gtkplugin.h>
#include <version.h>

#include <conversation.h>
#include <gtkconv.h>
#include <gtkprefs.h>
#include <gtkutils.h>

#define	PREF_PREFIX	"/plugins/gtk/" PLUGIN_ID
#define PREF_IGNORE	PREF_PREFIX "/ignore_incoming"
#define PREF_CHATS	PREF_PREFIX "/chats"
#define PREF_IMS	PREF_PREFIX "/ims"

#define	PREF_SEND	PREF_PREFIX "/send"
#define	PREF_SEND_C	PREF_SEND "/color"
#define	PREF_SEND_F	PREF_SEND "/format"
#define	PREF_SEND_E	PREF_SEND "/enabled"

#define PREF_RECV	PREF_PREFIX "/recv"
#define	PREF_RECV_C	PREF_RECV "/color"
#define	PREF_RECV_F	PREF_RECV "/format"
#define	PREF_RECV_E	PREF_RECV "/enabled"

#define PREF_SYSTEM	PREF_PREFIX "/system"
#define	PREF_SYSTEM_C	PREF_SYSTEM "/color"
#define	PREF_SYSTEM_F	PREF_SYSTEM "/format"
#define	PREF_SYSTEM_E	PREF_SYSTEM "/enabled"

#define PREF_ERROR	PREF_PREFIX "/error"
#define	PREF_ERROR_C	PREF_ERROR "/color"
#define	PREF_ERROR_F	PREF_ERROR "/format"
#define	PREF_ERROR_E	PREF_ERROR "/enabled"

#define PREF_NICK	PREF_PREFIX "/nick"
#define	PREF_NICK_C	PREF_NICK "/color"
#define	PREF_NICK_F	PREF_NICK "/format"
#define	PREF_NICK_E	PREF_NICK "/enabled"

enum
{
	FONT_BOLD		= 1 << 0,
	FONT_ITALIC		= 1 << 1,
	FONT_UNDERLINE	= 1 << 2
};

static struct
{
	PurpleMessageFlags flag;
	char *prefix;
	const char *text;
} formats[] =
{
	{PURPLE_MESSAGE_ERROR, PREF_ERROR, N_("Error Messages")},
	{PURPLE_MESSAGE_NICK, PREF_NICK, N_("Highlighted Messages")},
	{PURPLE_MESSAGE_SYSTEM, PREF_SYSTEM, N_("System Messages")},
	{PURPLE_MESSAGE_SEND, PREF_SEND, N_("Sent Messages")},
	{PURPLE_MESSAGE_RECV, PREF_RECV, N_("Received Messages")},
	{0, NULL, NULL}
};

static gboolean
displaying_msg(PurpleAccount *account, const char *who, char **displaying,
				PurpleConversation *conv, PurpleMessageFlags flags)
{
	int i;
	char tmp[128], *t;
	gboolean bold, italic, underline;
	int f;
	const char *color;
	gboolean rtl = FALSE;

	for (i = 0; formats[i].prefix; i++)
		if (flags & formats[i].flag)
			break;

	if (!formats[i].prefix)
		return FALSE;

	g_snprintf(tmp, sizeof(tmp), "%s/enabled", formats[i].prefix);

	if (!purple_prefs_get_bool(tmp) ||
			(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM &&
			!purple_prefs_get_bool(PREF_IMS)) ||
			(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT &&
			!purple_prefs_get_bool(PREF_CHATS)))
		return FALSE;

	g_snprintf(tmp, sizeof(tmp), "%s/color", formats[i].prefix);
	color = purple_prefs_get_string(tmp);

	g_snprintf(tmp, sizeof(tmp), "%s/format", formats[i].prefix);
	f = purple_prefs_get_int(tmp);
	bold = (f & FONT_BOLD);
	italic = (f & FONT_ITALIC);
	underline = (f & FONT_UNDERLINE);
	rtl = purple_markup_is_rtl(*displaying);

	if (purple_prefs_get_bool(PREF_IGNORE))
	{
		/* This seems to be necessary, especially for received messages. */
		t = *displaying;
		*displaying = purple_strreplace(t, "\n", "<br>");
		g_free(t);

		t = *displaying;
		*displaying = purple_markup_strip_html(t);
		g_free(t);

		t = *displaying;
		*displaying = g_markup_escape_text(t, -1);
		g_free(t);

		/* Restore the links */
		t = *displaying;
		*displaying = purple_markup_linkify(t);
		g_free(t);
	}

	if (color && *color)
	{
		t = *displaying;
		*displaying = g_strdup_printf("<FONT COLOR=\"%s\">%s</FONT>", color, t);
		g_free(t);
	}

	t = *displaying;
	*displaying = g_strdup_printf("%s%s%s%s%s%s%s%s%s",
						bold ? "<B>" : "</B>",
						italic ? "<I>" : "</I>",
						underline ? "<U>" : "</U>",
						rtl ? "<SPAN style=\"direction:rtl;text-align:right;\">" : "",
						t,
						rtl ? "</SPAN>" : "",
						bold ? "</B>" : "<B>",
						italic ? "</I>" : "<I>",
						underline ? "</U>" : "<U>"
			);
	g_free(t);

	return FALSE;
}

static gboolean
plugin_load(PurplePlugin *plugin)
{
	purple_signal_connect(pidgin_conversations_get_handle(),
					"displaying-im-msg", plugin,
					PURPLE_CALLBACK(displaying_msg), NULL);
	purple_signal_connect(pidgin_conversations_get_handle(),
					"displaying-chat-msg", plugin,
					PURPLE_CALLBACK(displaying_msg), NULL);
	return TRUE;
}

static gboolean
plugin_unload(PurplePlugin *plugin)
{
	return TRUE;
}

/* Ripped from PurpleRC */
static void
color_response(GtkDialog *color_dialog, gint response, const char *data)
{
	if (response == GTK_RESPONSE_OK)
	{
		GtkWidget *colorsel =
			gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(color_dialog));
		GdkColor color;
		char colorstr[8];
		char tmp[128];

		gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(colorsel), &color);

		g_snprintf(colorstr, sizeof(colorstr), "#%02X%02X%02X",
		           color.red/256, color.green/256, color.blue/256);

		g_snprintf(tmp, sizeof(tmp), "%s/color", data);

		purple_prefs_set_string(tmp, colorstr);
	}

	gtk_widget_destroy(GTK_WIDGET(color_dialog));
}

static void
set_color(GtkWidget *widget, const char *data)
{
	GtkWidget *color_dialog = NULL;
	GdkColor color;
	char title[128];
	char tmp[128];

	g_snprintf(title, sizeof(title), _("Select Color for %s"), _(data));
	color_dialog = gtk_color_selection_dialog_new(title);
	g_signal_connect(G_OBJECT(color_dialog), "response",
	                 G_CALLBACK(color_response), (gpointer)data);

	g_snprintf(tmp, sizeof(tmp), "%s/color", data);
	if (gdk_color_parse(purple_prefs_get_string(tmp), &color))
	{
		gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(
			gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(color_dialog))),
			&color);
	}

	gtk_window_present(GTK_WINDOW(color_dialog));
}

static void
toggle_enabled(GtkWidget *widget, gpointer data)
{
	const char *prefix = (char *)data;
	gboolean e;
	char tmp[128];

	g_snprintf(tmp, sizeof(tmp), "%s/enabled", prefix);
	e = purple_prefs_get_bool(tmp);
	purple_prefs_set_bool(tmp, !e);
}

static void
toggle_something(const char *prefix, int format)
{
	int f;
	char tmp[128];

	g_snprintf(tmp, sizeof(tmp), "%s/format", prefix);
	f = purple_prefs_get_int(tmp);
	f ^= format;
	purple_prefs_set_int(tmp, f);
}

static void
toggle_bold(GtkWidget *widget, gpointer data)
{
	toggle_something(data, FONT_BOLD);
}

static void
toggle_italic(GtkWidget *widget, gpointer data)
{
	toggle_something(data, FONT_ITALIC);
}

static void
toggle_underline(GtkWidget *widget, gpointer data)
{
	toggle_something(data, FONT_UNDERLINE);
}

static void
enable_toggled(const char *name, PurplePrefType type, gconstpointer val, gpointer data)
{
	GtkWidget *widget = (GtkWidget *)data;

	gtk_widget_set_sensitive(widget, GPOINTER_TO_INT(val));
}

static void
disconnect_prefs_callbacks(GtkAdjustment *object, gpointer data)
{
	PurplePlugin *plugin = (PurplePlugin *)data;

	purple_prefs_disconnect_by_handle(plugin);
}

static GtkWidget *
get_config_frame(PurplePlugin *plugin)
{
	GtkWidget *ret;
	GtkWidget *frame;
	int i;

	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
	gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER);

	for (i = 0; formats[i].prefix; i++)
	{
		char tmp[128];
		char tmp2[128];
		int f;
		gboolean e;
		GtkWidget *vbox, *hbox, *button;

		g_snprintf(tmp2, sizeof(tmp2), "%s/enabled", formats[i].prefix);
		e = purple_prefs_get_bool(tmp2);

		g_snprintf(tmp, sizeof(tmp), "%s/format", formats[i].prefix);
		f = purple_prefs_get_int(tmp);

		frame = pidgin_make_frame(ret, _(formats[i].text));
		vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
		gtk_box_pack_start(GTK_BOX(frame), vbox, FALSE, FALSE, 0);

		hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

		button = gtk_check_button_new_with_label(_("Enabled"));
		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
		if (e)
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(toggle_enabled),
				formats[i].prefix);

		button = pidgin_pixbuf_button_from_stock(" Color", GTK_STOCK_SELECT_COLOR,
				PIDGIN_BUTTON_HORIZONTAL);
		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(set_color),
				formats[i].prefix);
		gtk_widget_set_sensitive(button, e);
		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);

		button = gtk_check_button_new_with_label(_("Bold"));
		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
		if (f & FONT_BOLD)
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(toggle_bold),
				formats[i].prefix);
		gtk_widget_set_sensitive(button, e);
		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);

		button = gtk_check_button_new_with_label(_("Italic"));
		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
		if (f & FONT_ITALIC)
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(toggle_italic),
				formats[i].prefix);
		gtk_widget_set_sensitive(button, e);
		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);

		button = gtk_check_button_new_with_label(_("Underline"));
		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
		if (f & FONT_UNDERLINE)
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
		g_signal_connect(G_OBJECT(button), "clicked",
				G_CALLBACK(toggle_underline), formats[i].prefix);
		gtk_widget_set_sensitive(button, e);
		purple_prefs_connect_callback(plugin, tmp2, enable_toggled, button);
	}

	g_signal_connect(G_OBJECT(ret), "destroy", G_CALLBACK(disconnect_prefs_callbacks), plugin);
	frame = pidgin_make_frame(ret, _("General"));
	pidgin_prefs_checkbox(_("Ignore incoming format"), PREF_IGNORE, frame);
	pidgin_prefs_checkbox(_("Apply in Chats"), PREF_CHATS, frame);
	pidgin_prefs_checkbox(_("Apply in IMs"), PREF_IMS, frame);

	gtk_widget_show_all(ret);
	return ret;
}

static PidginPluginUiInfo ui_info =
{
	get_config_frame,
	0,

	/* padding */
	NULL,
	NULL,
	NULL,
	NULL
};

static PurplePluginInfo info =
{
	PURPLE_PLUGIN_MAGIC,            /* Magic              */
	PURPLE_MAJOR_VERSION,           /* Purple Major Version */
	PURPLE_MINOR_VERSION,           /* Purple Minor Version */
	PURPLE_PLUGIN_STANDARD,         /* plugin type        */
	PIDGIN_PLUGIN_TYPE,         /* ui requirement     */
	0,                            /* flags              */
	NULL,                         /* dependencies       */
	PURPLE_PRIORITY_DEFAULT,        /* priority           */

	PLUGIN_ID,                    /* plugin id          */
	PLUGIN_NAME,                  /* name               */
	DISPLAY_VERSION,              /* version            */
	PLUGIN_SUMMARY,               /* summary            */
	PLUGIN_DESCRIPTION,           /* description        */
	PLUGIN_AUTHOR,                /* author             */
	PURPLE_WEBSITE,                 /* website            */

	plugin_load,                  /* load               */
	plugin_unload,                /* unload             */
	NULL,                         /* destroy            */

	&ui_info,                     /* ui_info            */
	NULL,                         /* extra_info         */
	NULL,                         /* prefs_info         */
	NULL,                         /* actions            */

	/* padding */
	NULL,
	NULL,
	NULL,
	NULL
};

static void
init_plugin(PurplePlugin *plugin)
{
	purple_prefs_add_none(PREF_PREFIX);

	purple_prefs_add_bool(PREF_IGNORE, TRUE);
	purple_prefs_add_bool(PREF_CHATS, TRUE);
	purple_prefs_add_bool(PREF_IMS, TRUE);

	purple_prefs_add_none(PREF_SEND);
	purple_prefs_add_none(PREF_RECV);
	purple_prefs_add_none(PREF_SYSTEM);
	purple_prefs_add_none(PREF_ERROR);
	purple_prefs_add_none(PREF_NICK);

	purple_prefs_add_string(PREF_SEND_C, "#909090");
	purple_prefs_add_string(PREF_RECV_C, "#000000");
	purple_prefs_add_string(PREF_SYSTEM_C, "#50a050");
	purple_prefs_add_string(PREF_ERROR_C, "#ff0000");
	purple_prefs_add_string(PREF_NICK_C, "#0000dd");

	purple_prefs_add_int(PREF_SEND_F, 0);
	purple_prefs_add_int(PREF_RECV_F, 0);
	purple_prefs_add_int(PREF_SYSTEM_F, FONT_ITALIC);
	purple_prefs_add_int(PREF_ERROR_F, FONT_BOLD | FONT_UNDERLINE);
	purple_prefs_add_int(PREF_NICK_F, FONT_BOLD);

	purple_prefs_add_bool(PREF_SEND_E, TRUE);
	purple_prefs_add_bool(PREF_RECV_E, TRUE);
	purple_prefs_add_bool(PREF_SYSTEM_E, TRUE);
	purple_prefs_add_bool(PREF_ERROR_E, TRUE);
	purple_prefs_add_bool(PREF_NICK_E, TRUE);
}

PURPLE_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)

mercurial