pidgin/pidgin

Remove the deprecated keyring API.

2021-04-21, Gary Kramlich
32c1f097d4e8
Remove the deprecated keyring API.

I've disable the building of the internal keyring for now but left it so it
can be referenced when it is ported to the CredentialProvider API.

Testing Done:
Ran Pidgin and verified the preferences window worked.

Bugs closed: PIDGIN-17486

Reviewed at https://reviews.imfreedom.org/r/624/
/* pidgin
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <purple.h>
#include "gtkdialogs.h"
#include "gtkutils.h"
#include "pidgincore.h"
#include "pidgindebug.h"
#include "pidginstock.h"
#include <gdk/gdkkeysyms.h>
#include "pidginresources.h"
struct _PidginDebugWindow {
GtkWindow parent;
GtkWidget *toolbar;
GtkWidget *textview;
GtkTextBuffer *buffer;
GtkTextMark *start_mark;
GtkTextMark *end_mark;
struct {
GtkTextTag *level[PURPLE_DEBUG_FATAL + 1];
GtkTextTag *category;
GtkTextTag *filtered_invisible;
GtkTextTag *filtered_visible;
GtkTextTag *match;
GtkTextTag *paused;
} tags;
GtkWidget *filter;
GtkWidget *expression;
GtkWidget *filterlevel;
gboolean paused;
GtkWidget *popover;
GtkWidget *popover_invert;
GtkWidget *popover_highlight;
gboolean invert;
gboolean highlight;
GRegex *regex;
};
static PidginDebugWindow *debug_win = NULL;
struct _PidginDebugUi
{
GObject parent;
/* Other members, including private data. */
guint debug_enabled_timer;
};
static void pidgin_debug_ui_finalize(GObject *gobject);
static void pidgin_debug_ui_interface_init(PurpleDebugUiInterface *iface);
G_DEFINE_TYPE_WITH_CODE(PidginDebugUi, pidgin_debug_ui, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(PURPLE_TYPE_DEBUG_UI,
pidgin_debug_ui_interface_init));
G_DEFINE_TYPE(PidginDebugWindow, pidgin_debug_window, GTK_TYPE_WINDOW);
static gint
debug_window_destroy(GtkWidget *w, GdkEvent *event, void *unused)
{
purple_prefs_disconnect_by_handle(pidgin_debug_get_handle());
if (debug_win->regex != NULL)
g_regex_unref(debug_win->regex);
/* If the "Save Log" dialog is open then close it */
purple_request_close_with_handle(debug_win);
debug_win = NULL;
purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/enabled", FALSE);
return FALSE;
}
static gboolean
configure_cb(GtkWidget *w, GdkEventConfigure *event, void *unused)
{
if (gtk_widget_get_visible(w)) {
purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/width", event->width);
purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/height", event->height);
}
return FALSE;
}
static gboolean
view_near_bottom(PidginDebugWindow *win)
{
GtkAdjustment *adj = gtk_scrollable_get_vadjustment(
GTK_SCROLLABLE(win->textview));
return (gtk_adjustment_get_value(adj) >=
(gtk_adjustment_get_upper(adj) -
gtk_adjustment_get_page_size(adj) * 1.5));
}
static void
save_writefile_cb(void *user_data, const char *filename)
{
PidginDebugWindow *win = (PidginDebugWindow *)user_data;
FILE *fp;
GtkTextIter start, end;
char *tmp;
if ((fp = g_fopen(filename, "w+")) == NULL) {
purple_notify_error(win, NULL, _("Unable to open file."), NULL, NULL);
return;
}
gtk_text_buffer_get_bounds(win->buffer, &start, &end);
tmp = gtk_text_buffer_get_text(win->buffer, &start, &end, TRUE);
fprintf(fp, "Pidgin Debug Log : %s\n", purple_date_format_full(NULL));
fprintf(fp, "%s", tmp);
g_free(tmp);
fclose(fp);
}
static void
save_cb(GtkWidget *w, PidginDebugWindow *win)
{
purple_request_file(win, _("Save Debug Log"), "purple-debug.log", TRUE,
G_CALLBACK(save_writefile_cb), NULL, NULL, win);
}
static void
clear_cb(GtkWidget *w, PidginDebugWindow *win)
{
gtk_text_buffer_set_text(win->buffer, "", 0);
}
static void
pause_cb(GtkWidget *w, PidginDebugWindow *win)
{
win->paused = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w));
if (!win->paused) {
GtkTextIter start, end;
gtk_text_buffer_get_bounds(win->buffer, &start, &end);
gtk_text_buffer_remove_tag(win->buffer, win->tags.paused,
&start, &end);
gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(win->textview),
win->end_mark, 0, TRUE, 0, 1);
}
}
/******************************************************************************
* regex stuff
*****************************************************************************/
static void
regex_clear_color(GtkWidget *w) {
GtkStyleContext *context = gtk_widget_get_style_context(w);
gtk_style_context_remove_class(context, "good-filter");
gtk_style_context_remove_class(context, "bad-filter");
}
static void
regex_change_color(GtkWidget *w, gboolean success) {
GtkStyleContext *context = gtk_widget_get_style_context(w);
if (success) {
gtk_style_context_add_class(context, "good-filter");
gtk_style_context_remove_class(context, "bad-filter");
} else {
gtk_style_context_add_class(context, "bad-filter");
gtk_style_context_remove_class(context, "good-filter");
}
}
static void
do_regex(PidginDebugWindow *win, GtkTextIter *start, GtkTextIter *end)
{
GError *error = NULL;
GMatchInfo *match;
gint initial_position;
gint start_pos, end_pos;
GtkTextIter match_start, match_end;
gchar *text;
if (!win->regex)
return;
initial_position = gtk_text_iter_get_offset(start);
if (!win->invert) {
/* First hide everything. */
gtk_text_buffer_apply_tag(win->buffer,
win->tags.filtered_invisible, start, end);
}
text = gtk_text_buffer_get_text(win->buffer, start, end, TRUE);
g_regex_match(win->regex, text, 0, &match);
while (g_match_info_matches(match)) {
g_match_info_fetch_pos(match, 0, &start_pos, &end_pos);
start_pos += initial_position;
end_pos += initial_position;
/* Expand match to full line of message. */
gtk_text_buffer_get_iter_at_offset(win->buffer,
&match_start, start_pos);
gtk_text_iter_set_line_index(&match_start, 0);
gtk_text_buffer_get_iter_at_offset(win->buffer,
&match_end, end_pos);
gtk_text_iter_forward_line(&match_end);
if (win->invert) {
/* Make invisible. */
gtk_text_buffer_apply_tag(win->buffer,
win->tags.filtered_invisible,
&match_start, &match_end);
} else {
/* Make visible again (with higher priority.) */
gtk_text_buffer_apply_tag(win->buffer,
win->tags.filtered_visible,
&match_start, &match_end);
if (win->highlight) {
gtk_text_buffer_get_iter_at_offset(
win->buffer,
&match_start,
start_pos);
gtk_text_buffer_get_iter_at_offset(
win->buffer,
&match_end,
end_pos);
gtk_text_buffer_apply_tag(win->buffer,
win->tags.match,
&match_start,
&match_end);
}
}
g_match_info_next(match, &error);
}
g_match_info_free(match);
g_free(text);
}
static void
regex_toggle_filter(PidginDebugWindow *win, gboolean filter)
{
GtkTextIter start, end;
gtk_text_buffer_get_bounds(win->buffer, &start, &end);
gtk_text_buffer_remove_tag(win->buffer, win->tags.match, &start, &end);
gtk_text_buffer_remove_tag(win->buffer, win->tags.filtered_invisible,
&start, &end);
gtk_text_buffer_remove_tag(win->buffer, win->tags.filtered_visible,
&start, &end);
if (filter) {
do_regex(win, &start, &end);
}
}
static void
regex_pref_filter_cb(const gchar *name, PurplePrefType type,
gconstpointer val, gpointer data)
{
PidginDebugWindow *win = (PidginDebugWindow *)data;
gboolean active = GPOINTER_TO_INT(val), current;
if (!win)
return;
current = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter));
if (active != current)
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), active);
}
static void
regex_pref_expression_cb(const gchar *name, PurplePrefType type,
gconstpointer val, gpointer data)
{
PidginDebugWindow *win = (PidginDebugWindow *)data;
const gchar *exp = (const gchar *)val;
gtk_entry_set_text(GTK_ENTRY(win->expression), exp);
}
static void
regex_pref_invert_cb(const gchar *name, PurplePrefType type,
gconstpointer val, gpointer data)
{
PidginDebugWindow *win = (PidginDebugWindow *)data;
gboolean active = GPOINTER_TO_INT(val);
win->invert = active;
if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter)))
regex_toggle_filter(win, TRUE);
}
static void
regex_pref_highlight_cb(const gchar *name, PurplePrefType type,
gconstpointer val, gpointer data)
{
PidginDebugWindow *win = (PidginDebugWindow *)data;
gboolean active = GPOINTER_TO_INT(val);
win->highlight = active;
if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter)))
regex_toggle_filter(win, TRUE);
}
static void
regex_changed_cb(GtkWidget *w, PidginDebugWindow *win) {
const gchar *text;
if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) {
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter),
FALSE);
}
text = gtk_entry_get_text(GTK_ENTRY(win->expression));
purple_prefs_set_string(PIDGIN_PREFS_ROOT "/debug/regex", text);
if (text == NULL || *text == '\0') {
regex_clear_color(win->expression);
gtk_widget_set_sensitive(win->filter, FALSE);
return;
}
if (win->regex)
g_regex_unref(win->regex);
win->regex = g_regex_new(text, G_REGEX_CASELESS|G_REGEX_JAVASCRIPT_COMPAT, 0, NULL);
if (win->regex == NULL) {
/* failed to compile */
regex_change_color(win->expression, FALSE);
gtk_widget_set_sensitive(win->filter, FALSE);
} else {
/* compiled successfully */
regex_change_color(win->expression, TRUE);
gtk_widget_set_sensitive(win->filter, TRUE);
}
}
static void
regex_key_release_cb(GtkWidget *w, GdkEventKey *e, PidginDebugWindow *win) {
if (gtk_widget_is_sensitive(win->filter)) {
GtkToggleToolButton *tb = GTK_TOGGLE_TOOL_BUTTON(win->filter);
if ((e->keyval == GDK_KEY_Return || e->keyval == GDK_KEY_KP_Enter) &&
!gtk_toggle_tool_button_get_active(tb))
{
gtk_toggle_tool_button_set_active(tb, TRUE);
}
if (e->keyval == GDK_KEY_Escape &&
gtk_toggle_tool_button_get_active(tb))
{
gtk_toggle_tool_button_set_active(tb, FALSE);
}
}
}
static void
regex_menu_cb(GtkWidget *item, PidginDebugWindow *win)
{
gboolean active;
active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(item));
if (item == win->popover_highlight) {
purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/highlight", active);
} else if (item == win->popover_invert) {
purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/invert", active);
}
}
static void
regex_popup_cb(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event,
PidginDebugWindow *win)
{
GdkRectangle rect;
if (icon_pos != GTK_ENTRY_ICON_PRIMARY) {
return;
}
gtk_entry_get_icon_area(entry, icon_pos, &rect);
gtk_popover_set_pointing_to(GTK_POPOVER(win->popover), &rect);
gtk_popover_popup(GTK_POPOVER(win->popover));
}
static void
regex_filter_toggled_cb(GtkToggleToolButton *button, PidginDebugWindow *win)
{
gboolean active;
active = gtk_toggle_tool_button_get_active(button);
purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/filter", active);
regex_toggle_filter(win, active);
}
static void
debug_window_set_filter_level(PidginDebugWindow *win, int level)
{
gboolean scroll;
int i;
if (level != gtk_combo_box_get_active(GTK_COMBO_BOX(win->filterlevel)))
gtk_combo_box_set_active(GTK_COMBO_BOX(win->filterlevel), level);
scroll = view_near_bottom(win);
for (i = 0; i <= PURPLE_DEBUG_FATAL; i++) {
g_object_set(G_OBJECT(win->tags.level[i]),
"invisible", i < level,
NULL);
}
if (scroll) {
gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(win->textview),
win->end_mark, 0, TRUE, 0, 1);
}
}
static void
filter_level_pref_changed(const char *name, PurplePrefType type, gconstpointer value, gpointer data)
{
PidginDebugWindow *win = data;
int level = GPOINTER_TO_INT(value);
debug_window_set_filter_level(win, level);
}
static void
filter_level_changed_cb(GtkWidget *combo, gpointer null)
{
purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/filterlevel",
gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
}
static void
toolbar_style_pref_changed_cb(const char *name, PurplePrefType type, gconstpointer value, gpointer data)
{
gtk_toolbar_set_style(GTK_TOOLBAR(data), GPOINTER_TO_INT(value));
}
static void
toolbar_icon_pref_changed(GtkWidget *item, GtkWidget *toolbar)
{
int style = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "user_data"));
purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/style", style);
}
static gboolean
toolbar_context(GtkWidget *toolbar, gint x, gint y, gint button, gpointer null)
{
GtkWidget *menu, *item;
const char *text[3];
GtkToolbarStyle value[3];
int i;
text[0] = _("_Icon Only"); value[0] = GTK_TOOLBAR_ICONS;
text[1] = _("_Text Only"); value[1] = GTK_TOOLBAR_TEXT;
text[2] = _("_Both Icon & Text"); value[2] = GTK_TOOLBAR_BOTH_HORIZ;
menu = gtk_menu_new();
for (i = 0; i < 3; i++) {
item = gtk_check_menu_item_new_with_mnemonic(text[i]);
g_object_set_data(G_OBJECT(item), "user_data", GINT_TO_POINTER(value[i]));
g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(toolbar_icon_pref_changed), toolbar);
if (value[i] == (GtkToolbarStyle)purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/style"))
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
}
gtk_widget_show_all(menu);
gtk_menu_popup_at_pointer(GTK_MENU(menu), NULL);
return FALSE;
}
static void
pidgin_debug_window_class_init(PidginDebugWindowClass *klass) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
gtk_widget_class_set_template_from_resource(
widget_class,
"/im/pidgin/Pidgin/Debug/debug.ui"
);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, toolbar);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, textview);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, buffer);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.category);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.filtered_invisible);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.filtered_visible);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.level[0]);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.level[1]);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.level[2]);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.level[3]);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.level[4]);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.level[5]);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.paused);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, filter);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, filterlevel);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, expression);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, tags.match);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, popover);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, popover_invert);
gtk_widget_class_bind_template_child(
widget_class, PidginDebugWindow, popover_highlight);
gtk_widget_class_bind_template_callback(widget_class, toolbar_context);
gtk_widget_class_bind_template_callback(widget_class, save_cb);
gtk_widget_class_bind_template_callback(widget_class, clear_cb);
gtk_widget_class_bind_template_callback(widget_class, pause_cb);
gtk_widget_class_bind_template_callback(widget_class,
regex_filter_toggled_cb);
gtk_widget_class_bind_template_callback(widget_class,
regex_changed_cb);
gtk_widget_class_bind_template_callback(widget_class, regex_popup_cb);
gtk_widget_class_bind_template_callback(widget_class, regex_menu_cb);
gtk_widget_class_bind_template_callback(widget_class,
regex_key_release_cb);
gtk_widget_class_bind_template_callback(widget_class,
filter_level_changed_cb);
}
static void
pidgin_debug_window_init(PidginDebugWindow *win)
{
gint width, height;
void *handle;
GtkTextIter end;
GtkStyleContext *context;
GtkCssProvider *filter_css;
const gchar *res = "/im/pidgin/Pidgin/Debug/filter.css";
gtk_widget_init_template(GTK_WIDGET(win));
width = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/width");
height = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/height");
purple_debug_info("pidgindebug", "Setting dimensions to %d, %d\n",
width, height);
gtk_window_set_default_size(GTK_WINDOW(win), width, height);
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(debug_window_destroy), NULL);
g_signal_connect(G_OBJECT(win), "configure_event",
G_CALLBACK(configure_cb), NULL);
handle = pidgin_debug_get_handle();
if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/toolbar")) {
/* Setup our top button bar thingie. */
gtk_toolbar_set_style(GTK_TOOLBAR(win->toolbar),
purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/style"));
purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/style",
toolbar_style_pref_changed_cb, win->toolbar);
/* we purposely disable the toggle button here in case
* /purple/gtk/debug/expression has an empty string. If it does not have
* an empty string, the change signal will get called and make the
* toggle button sensitive.
*/
gtk_widget_set_sensitive(win->filter, FALSE);
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter),
purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/filter"));
purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/filter",
regex_pref_filter_cb, win);
/* regex entry */
filter_css = gtk_css_provider_new();
gtk_css_provider_load_from_resource(filter_css, res);
context = gtk_widget_get_style_context(win->expression);
gtk_style_context_add_provider(context,
GTK_STYLE_PROVIDER(filter_css),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
gtk_entry_set_text(GTK_ENTRY(win->expression),
purple_prefs_get_string(PIDGIN_PREFS_ROOT "/debug/regex"));
purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/regex",
regex_pref_expression_cb, win);
/* connect the rest of our pref callbacks */
win->invert = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/invert");
purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/invert",
regex_pref_invert_cb, win);
win->highlight = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/highlight");
purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/highlight",
regex_pref_highlight_cb, win);
gtk_combo_box_set_active(GTK_COMBO_BOX(win->filterlevel),
purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel"));
purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/filterlevel",
filter_level_pref_changed, win);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win->popover_invert),
win->invert);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win->popover_highlight),
win->highlight);
}
/* The *start* and *end* marks bound the beginning and end of an
insertion, used for filtering. The *end* mark is also used for
auto-scrolling. */
gtk_text_buffer_get_end_iter(win->buffer, &end);
win->start_mark = gtk_text_buffer_create_mark(win->buffer,
"start", &end, TRUE);
win->end_mark = gtk_text_buffer_create_mark(win->buffer,
"end", &end, FALSE);
/* Set active filter level in textview */
debug_window_set_filter_level(win,
purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel"));
clear_cb(NULL, win);
}
static gboolean
debug_enabled_timeout_cb(gpointer data)
{
PidginDebugUi *ui = PIDGIN_DEBUG_UI(data);
ui->debug_enabled_timer = 0;
pidgin_debug_window_show();
return FALSE;
}
static gboolean
debug_disabled_timeout_cb(gpointer data)
{
PidginDebugUi *ui = PIDGIN_DEBUG_UI(data);
ui->debug_enabled_timer = 0;
pidgin_debug_window_hide();
return FALSE;
}
static void
debug_enabled_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
PidginDebugUi *ui = PIDGIN_DEBUG_UI(data);
if (GPOINTER_TO_INT(value))
ui->debug_enabled_timer = g_timeout_add(0, debug_enabled_timeout_cb, data);
else
ui->debug_enabled_timer = g_timeout_add(0, debug_disabled_timeout_cb, data);
}
static void
pidgin_debug_g_log_handler(const gchar *domain, GLogLevelFlags flags,
const gchar *msg, gpointer user_data)
{
PurpleDebugLevel level;
GString *category = g_string_new("GLog-");
if(domain != NULL) {
g_string_append_printf(category, "%s-", domain);
}
if((flags & G_LOG_LEVEL_ERROR) != 0) {
g_string_append(category, "Error");
level = PURPLE_DEBUG_ERROR;
} else if((flags & G_LOG_LEVEL_CRITICAL) != 0) {
g_string_append(category, "Fatal");
level = PURPLE_DEBUG_FATAL;
} else if((flags & G_LOG_LEVEL_WARNING) != 0) {
g_string_append(category, "Warning");
level = PURPLE_DEBUG_WARNING;
} else if((flags & G_LOG_LEVEL_MESSAGE) != 0) {
g_string_append(category, "Message");
level = PURPLE_DEBUG_INFO;
} else if((flags & G_LOG_LEVEL_INFO) != 0) {
g_string_append(category, "Info");
level = PURPLE_DEBUG_INFO;
} else if((flags & G_LOG_LEVEL_DEBUG) != 0) {
g_string_append(category, "Debug");
level = PURPLE_DEBUG_MISC;
} else {
g_string_append(category, "Unknown");
level = PURPLE_DEBUG_MISC;
}
purple_debug(level, category->str, "%s", msg);
g_string_free(category, TRUE);
}
static void
pidgin_debug_ui_init(PidginDebugUi *self)
{
/* Debug window preferences. */
/*
* NOTE: This must be set before prefs are loaded, and the callbacks
* set after they are loaded, since prefs sets the enabled
* preference here and that loads the window, which calls the
* configure event, which overrides the width and height! :P
*/
purple_prefs_add_none(PIDGIN_PREFS_ROOT "/debug");
/* Controls printing to the debug window */
purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/enabled", FALSE);
purple_prefs_add_int(PIDGIN_PREFS_ROOT "/debug/filterlevel", PURPLE_DEBUG_ALL);
purple_prefs_add_int(PIDGIN_PREFS_ROOT "/debug/style", GTK_TOOLBAR_BOTH_HORIZ);
purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/toolbar", TRUE);
purple_prefs_add_int(PIDGIN_PREFS_ROOT "/debug/width", 450);
purple_prefs_add_int(PIDGIN_PREFS_ROOT "/debug/height", 250);
purple_prefs_add_string(PIDGIN_PREFS_ROOT "/debug/regex", "");
purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/filter", FALSE);
purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/invert", FALSE);
purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/case_insensitive", FALSE);
purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/highlight", FALSE);
purple_prefs_connect_callback(NULL, PIDGIN_PREFS_ROOT "/debug/enabled",
debug_enabled_cb, self);
g_log_set_default_handler(pidgin_debug_g_log_handler, NULL);
}
static void
pidgin_debug_ui_finalize(GObject *gobject)
{
PidginDebugUi *self = PIDGIN_DEBUG_UI(gobject);
if (self->debug_enabled_timer != 0)
g_source_remove(self->debug_enabled_timer);
self->debug_enabled_timer = 0;
G_OBJECT_CLASS(pidgin_debug_ui_parent_class)->finalize(gobject);
}
void
pidgin_debug_window_show(void)
{
if (debug_win == NULL) {
debug_win = PIDGIN_DEBUG_WINDOW(
g_object_new(PIDGIN_TYPE_DEBUG_WINDOW, NULL));
}
gtk_widget_show(GTK_WIDGET(debug_win));
purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/enabled", TRUE);
}
void
pidgin_debug_window_hide(void)
{
if (debug_win != NULL) {
gtk_widget_destroy(GTK_WIDGET(debug_win));
debug_window_destroy(NULL, NULL, NULL);
}
}
static void
pidgin_debug_print(PurpleDebugUi *self,
PurpleDebugLevel level, const char *category,
const char *arg_s)
{
GtkTextTag *level_tag;
const char *mdate;
time_t mtime;
GtkTextIter end;
gboolean scroll;
if (debug_win == NULL)
return;
if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/enabled"))
return;
scroll = view_near_bottom(debug_win);
gtk_text_buffer_get_end_iter(debug_win->buffer, &end);
gtk_text_buffer_move_mark(debug_win->buffer, debug_win->start_mark,
&end);
level_tag = debug_win->tags.level[level];
mtime = time(NULL);
mdate = purple_utf8_strftime("(%H:%M:%S) ", localtime(&mtime));
gtk_text_buffer_insert_with_tags(
debug_win->buffer,
&end,
mdate,
-1,
level_tag,
debug_win->paused ? debug_win->tags.paused : NULL,
NULL);
if (category && *category) {
gtk_text_buffer_insert_with_tags(
debug_win->buffer,
&end,
category,
-1,
level_tag,
debug_win->tags.category,
debug_win->paused ? debug_win->tags.paused : NULL,
NULL);
gtk_text_buffer_insert_with_tags(
debug_win->buffer,
&end,
": ",
2,
level_tag,
debug_win->tags.category,
debug_win->paused ? debug_win->tags.paused : NULL,
NULL);
}
gtk_text_buffer_insert_with_tags(
debug_win->buffer,
&end,
arg_s,
-1,
level_tag,
debug_win->paused ? debug_win->tags.paused : NULL,
NULL);
gtk_text_buffer_insert_with_tags(
debug_win->buffer,
&end,
"\n",
1,
level_tag,
debug_win->paused ? debug_win->tags.paused : NULL,
NULL);
if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/filter") && debug_win->regex) {
/* Filter out any new messages. */
GtkTextIter start;
gtk_text_buffer_get_iter_at_mark(debug_win->buffer, &start,
debug_win->start_mark);
gtk_text_buffer_get_iter_at_mark(debug_win->buffer, &end,
debug_win->end_mark);
do_regex(debug_win, &start, &end);
}
if (scroll) {
gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(debug_win->textview),
debug_win->end_mark, 0, TRUE, 0, 1);
}
}
static gboolean
pidgin_debug_is_enabled(PurpleDebugUi *self, PurpleDebugLevel level, const char *category)
{
return (debug_win != NULL &&
purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/enabled"));
}
static void
pidgin_debug_ui_interface_init(PurpleDebugUiInterface *iface)
{
iface->print = pidgin_debug_print;
iface->is_enabled = pidgin_debug_is_enabled;
}
static void
pidgin_debug_ui_class_init(PidginDebugUiClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = pidgin_debug_ui_finalize;
}
PidginDebugUi *
pidgin_debug_ui_new(void)
{
return g_object_new(PIDGIN_TYPE_DEBUG_UI, NULL);
}
void *
pidgin_debug_get_handle() {
static int handle;
return &handle;
}