cpw.nader.asynclogging-3: a6916d3a: Began work on gobjectifying gntlog.c

morshed.nader at gmail.com morshed.nader at gmail.com
Fri Jan 14 17:01:05 EST 2011


----------------------------------------------------------------------
Revision: a6916d3a58ecb85740b781e9b7cffa7e1838413b
Parent:   77bb4c8b032403cbae267c803125da3330346a7e
Author:   morshed.nader at gmail.com
Date:     01/14/11 03:06:26
Branch:   im.pidgin.cpw.nader.asynclogging-3
URL: http://d.pidgin.im/viewmtn/revision/info/a6916d3a58ecb85740b781e9b7cffa7e1838413b

Changelog: 

Began work on gobjectifying gntlog.c
Cleaned up gtklog.c a little more

Changes against parent 77bb4c8b032403cbae267c803125da3330346a7e

  patched  finch/gntlog.c
  patched  finch/gntlog.h
  patched  pidgin/gtklog.c
  patched  pidgin/gtklog.h

-------------- next part --------------
============================================================
--- pidgin/gtklog.c	39143275f7fed6278591e1c6aced8ea1106d7632
+++ pidgin/gtklog.c	e3a213ac451e1daae75111303754f1ba1b67cfdc
@@ -52,9 +52,6 @@ G_DEFINE_TYPE (PidginLogViewer, pidgin_l
 
 
 G_DEFINE_TYPE (PidginLogViewer, pidgin_log_viewer, GTK_TYPE_DIALOG)
-static void pidgin_log_viewer_get_property(GObject *, guint, GValue *, GParamSpec *);
-static void pidgin_log_viewer_set_property(GObject *, guint, const GValue *, GParamSpec *);
-static void pidgin_log_viewer_finalize(GObject *);
 
 enum {
 	PROP_0,
@@ -82,22 +79,25 @@ struct _PidginLogViewerPrivate {
 typedef struct _PidginLogViewerPrivate PidginLogViewerPrivate;
 
 struct _PidginLogViewerPrivate {
-	GList              *logs;       /**< The list of logs viewed in this viewer */
-	GtkTreeStore       *treestore;  /**< The treestore containing said logs */
-	GtkWidget          *treeview;   /**< The treeview representing said treestore */
-	GtkWidget          *imhtml;     /**< The imhtml to display said logs */
-	GtkWidget          *entry;      /**< The search entry, in which search terms are entered */
-	gchar              *search;     /**< The string currently being searched for */
-	GtkWidget          *label;      /**< The label at the top of the log viewer */
-	GtkWidget          *size_label; /**< The label with total log size */
+	GList              *logs;          /**< The list of logs viewed in this viewer */
+	GtkTreeStore       *treestore;     /**< The treestore containing said logs */
+	GtkWidget          *treeview;      /**< The treeview representing said treestore */
+	GtkWidget          *imhtml;        /**< The imhtml to display said logs */
+	GtkWidget          *entry;         /**< The search entry, in which search terms are entered */
+	gchar              *search;        /**< The string currently being searched for */
+	GtkWidget          *label;         /**< The label at the top of the log viewer */
+
 	gsize              size;           /**< The actual value of the total log size */
+	GtkWidget          *size_label;    /**< The label with total log size */
 	GtkWidget          *list_bar;      /**< The progress bar */
 	GtkWidget          *search_bar;    /**< The progess bar for searches */
+
 	GCancellable       *search_cancel; /**< A GCancellable to stop any searches */
 	GCancellable       *list_cancel;   /**< A GCancellable to stop any folder listings */
 	GCancellable       *read_cancel;   /**< A GCancellable to stop any reads */
 	gboolean           selected;       /**< A gboolean to indicate the user has already selected a log */
 	PurpleLogChatType  viewer_type;    /**< The log type of the window */
+
 	GtkWidget          *icon;
 	gboolean           need_log_size;
 	GtkWidget          *title_box;
@@ -345,15 +345,12 @@ search_cb(GtkWidget *button, PidginLogVi
 
 	search_term = gtk_entry_get_text(GTK_ENTRY(priv->entry));
 
-	if (!(*search_term)) {
+	if (*search_term == 0) {
 		/* reset the tree */
 		pidgin_log_viewer_set_search_cancel(lv, NULL);
-
-		gtk_tree_store_clear(treestore);
-		populate_log_tree(lv);
-
 		pidgin_log_viewer_set_search_string(lv, NULL);
 
+		populate_log_tree(lv);
 		gtk_imhtml_search_clear(imhtml);
 		select_first_log(lv);
 
@@ -385,7 +382,6 @@ search_cb(GtkWidget *button, PidginLogVi
 	pidgin_log_data->log_viewer = lv;
 	pidgin_log_data->string = g_strdup(search_term);
 	pidgin_log_data->count = pidgin_log_data->total = length;
-
 	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(pidgin_window_destroy_cb), pidgin_log_data);
 
@@ -435,7 +431,6 @@ destroy_cb(PidginLogViewer *lv, gint res
 
 	if (ht != NULL) {
 		G_LOCK(log_viewers);
-		lv = g_hash_table_lookup(log_viewers, ht);
 		g_hash_table_remove(log_viewers, ht);
 		G_UNLOCK(log_viewers);
 
@@ -812,17 +807,20 @@ log_select_cb(GtkTreeSelection *sel, Pid
 	if (chat_type != PURPLE_LOG_SYSTEM) {
 		PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
 		const gchar *log_name = purple_log_get_name(log);
-		gchar *title;
+		gchar *title, *bold_text;
 
 		if (chat_type == PURPLE_LOG_CHAT)
-			title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation in %s on %s</span>"),
+			title = g_strdup_printf(_("Conversation in %s on %s"),
 				log_name, log_get_date(log));
 		else
-			title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"),
+			title = g_strdup_printf(_("Conversation with %s on %s"),
 				log_name, log_get_date(log));
 
-		gtk_label_set_markup(GTK_LABEL(priv->label), title);
+		bold_text = g_strdup_printf("<span size='larger' weight='bold'>%s</span", title);
+		gtk_label_set_markup(GTK_LABEL(priv->label), bold_text);
+
 		g_free(title);
+		g_free(bold_text);
 	}
 
 	pidgin_log_data = g_new0(_pidgin_log_data, 1);
@@ -871,12 +869,11 @@ populate_log_tree(PidginLogViewer *lv)
 
 	for ( ; logs != NULL; logs = g_list_next(logs)) {
 		PurpleLog *log = logs->data;
-		const struct tm *log_tm;
-		time_t log_time;
+		const struct tm *log_tm = purple_log_get_tm(log);
+		time_t log_time = purple_log_get_time(log);
 
-		log_tm = purple_log_get_tm(log);
-		log_time = purple_log_get_time(log);
-		month = purple_utf8_strftime(_("%B %Y"), log_tm != NULL ? log_tm : localtime(&log_time));
+		month = purple_utf8_strftime(_("%B %Y"),
+			log_tm != NULL ? log_tm : localtime(&log_time));
 
 		if (strcmp(month, prev_top_month) != 0) {
 			/* top level */
@@ -1013,20 +1010,20 @@ pidgin_log_done_cb(_pidgin_log_data *pid
 
 		if (logs == NULL) {
 			/* No logs were found. */
-			PurpleLogChatType type = pidgin_log_viewer_get_viewer_type(lv);
+			PurpleLogChatType chat_type = pidgin_log_viewer_get_viewer_type(lv);
 			const gchar *log_preferences = NULL;
 
-			if (type == PURPLE_LOG_SYSTEM) {
+			if (chat_type == PURPLE_LOG_SYSTEM) {
 				if (!purple_prefs_get_bool("/purple/logging/log_system"))
 					log_preferences = _("System events will only be logged if "
 						"the \"Log all status changes to system log\" "
 						"preference is enabled.");
-			} else if (type == PURPLE_LOG_IM) {
+			} else if (chat_type == PURPLE_LOG_IM) {
 				if (!purple_prefs_get_bool("/purple/logging/log_ims"))
 					log_preferences = _("Instant messages will only be logged "
 					"if the \"Log all instant messages\" "
 					"preference is enabled.");
-			} else if (type == PURPLE_LOG_CHAT) {
+			} else if (chat_type == PURPLE_LOG_CHAT) {
 				if (!purple_prefs_get_bool("/purple/logging/log_chats"))
 					log_preferences = _("Chats will only be logged if the "
 						"\"Log all chats\" preference is enabled.");
@@ -1110,7 +1107,8 @@ pidgin_log_list_cb(GObject *object, GAsy
 
 	if (list == NULL) {
 		if (error != NULL && error->code != G_IO_ERROR_CANCELLED)
-			purple_debug_error("gtklog", "Error getting logs: %s\n", error->message);
+			purple_debug_error("gtklog", "Error getting logs: %s\n",
+				error->message);
 	} else if (pidgin_log_data->is_window_open)
 		pidgin_log_viewer_add_logs(pidgin_log_data->log_viewer, list);
 
@@ -1135,7 +1133,8 @@ pidgin_log_system_list_cb(GObject *objec
 
 	if (list == NULL) {
 		if (error != NULL && error->code != G_IO_ERROR_CANCELLED)
-			purple_debug_error("gtklog", "Error getting system logs: %s\n", error->message);
+			purple_debug_error("gtklog", "Error getting system logs: %s\n",
+				error->message);
 	} else if (pidgin_log_data->is_window_open)
 		pidgin_log_viewer_add_logs(pidgin_log_data->log_viewer, list);
 
@@ -1157,7 +1156,7 @@ pidgin_log_show(PurpleLogChatType chat_t
 	GdkPixbuf *prpl_icon;
 	GtkWidget *image;
 	GCancellable *cancel;
-	const gchar *name;
+	const gchar *name = buddyname;
 	gchar *title;
 
 	if (chat_type != PURPLE_LOG_IM) {
@@ -1165,9 +1164,7 @@ pidgin_log_show(PurpleLogChatType chat_t
 		g_return_if_fail(buddyname != NULL);
 	}
 
-	name = buddyname;
 	ht = g_new0(log_viewer_hash_t, 1);
-
 	ht->chat_type = chat_type;
 	ht->buddyname = g_strdup(buddyname);
 	ht->account = account;
@@ -1253,7 +1250,6 @@ pidgin_log_show_contact(PurpleContact *c
 
 	if (lv != NULL) {
 		gtk_window_present(GTK_WINDOW(lv));
-
 		g_free(ht);
 
 		return;
@@ -1271,23 +1267,25 @@ pidgin_log_show_contact(PurpleContact *c
 		image = NULL;
 	}
 
-	if (contact->alias != NULL)
-		name = contact->alias;
-	else if (contact->priority != NULL)
-		name = purple_buddy_get_contact_alias(contact->priority);
+	if ((name = purple_contact_get_alias(contact)) == NULL)
+		name = purple_buddy_get_contact_alias(purple_contact_get_priority_buddy(contact));
 
 	/* This will happen if the contact doesn't have an alias,
 	 * and none of the contact's buddies are online.
 	 * There is probably a better way to deal with this. */
 	if (name == NULL) {
-		if (contact->node.child != NULL && PURPLE_BLIST_NODE_IS_BUDDY(contact->node.child))
-			name = purple_buddy_get_contact_alias(PURPLE_BUDDY(contact->node.child));
+		child = purple_blist_node_get_first_child(PURPLE_BLIST_NODE(contact));
+
+		if (child != NULL && PURPLE_BLIST_NODE_IS_BUDDY(child))
+			name = purple_buddy_get_contact_alias(PURPLE_BUDDY(child));
+
 		if (name == NULL)
 			name = "";
 	}
 
 	pidgin_log_data = g_new0(_pidgin_log_data, 1);
 	pidgin_log_data->is_window_open = TRUE;
+	pidgin_log_data->count = pidgin_log_data->total = 0;
 
 	title = g_strdup_printf(_("Conversations with %s"), name);
 	lv = pidgin_log_data->log_viewer = pidgin_log_viewer_new(ht, title, image, TRUE);
@@ -1297,21 +1295,27 @@ pidgin_log_show_contact(PurpleContact *c
 	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(pidgin_window_destroy_cb), pidgin_log_data);
 
-	pidgin_log_data->count = pidgin_log_data->total = 0;
 	cancel = g_cancellable_new();
 	pidgin_log_viewer_set_list_cancel(lv, cancel);
 
-	for (child = contact->node.child; child != NULL; child = child->next) {
-		if (PURPLE_BLIST_NODE_IS_BUDDY(child)) {
-			PurpleBuddy *buddy = PURPLE_BUDDY(child);
+	for (child = purple_blist_node_get_first_child(PURPLE_BLIST_NODE(contact));
+		child != NULL; child = purple_blist_node_get_sibling_next(child))
+	{
+		const gchar *name;
+		PurpleAccount *account;
 
-			pidgin_log_data->count = (pidgin_log_data->total += 2);
+		if (!PURPLE_BLIST_NODE_IS_BUDDY(child))
+			continue;
 
-			purple_logs_get_logs_async(PURPLE_LOG_IM, buddy->name, buddy->account,
-				G_PRIORITY_DEFAULT, cancel, pidgin_log_list_cb, pidgin_log_data);
-			purple_logs_get_total_size_async(PURPLE_LOG_IM, buddy->name, buddy->account,
-				G_PRIORITY_DEFAULT, cancel, pidgin_log_size_cb, pidgin_log_data);
-		}
+		pidgin_log_data->count = (pidgin_log_data->total += 2);
+
+		name = purple_buddy_get_name(PURPLE_BUDDY(child));
+		account = purple_buddy_get_account(PURPLE_BUDDY(child));
+
+		purple_logs_get_logs_async(PURPLE_LOG_IM, name, account,
+			G_PRIORITY_DEFAULT, cancel, pidgin_log_list_cb, pidgin_log_data);
+		purple_logs_get_total_size_async(PURPLE_LOG_IM, name, account,
+			G_PRIORITY_DEFAULT, cancel, pidgin_log_size_cb, pidgin_log_data);
 	}
 
 	g_object_unref(cancel);
@@ -1336,6 +1340,7 @@ pidgin_syslog_show(void)
 
 	pidgin_log_data = g_new0(_pidgin_log_data, 1);
 	pidgin_log_data->is_window_open = TRUE;
+	pidgin_log_data->count = pidgin_log_data->total = 0;
 
 	lv = pidgin_log_data->log_viewer = pidgin_log_viewer_new(NULL,
 		_("System Log"), NULL, FALSE);
@@ -1346,20 +1351,19 @@ pidgin_syslog_show(void)
 
 	cancel = g_cancellable_new();
 	pidgin_log_viewer_set_list_cancel(lv, cancel);
-	pidgin_log_data->count = pidgin_log_data->total = 0;
 
 	for(accounts = purple_accounts_get_all(); accounts != NULL;
 		accounts = g_list_next(accounts))
 	{
 		PurpleAccount *account = accounts->data;
 
-		if(purple_find_prpl(purple_account_get_protocol_id(account)) != NULL) {
-			pidgin_log_data->count++;
-			pidgin_log_data->total++;
+		if (purple_find_prpl(purple_account_get_protocol_id(account)) == NULL)
+			continue;
 
-			purple_logs_get_system_logs_async(account, G_PRIORITY_DEFAULT, cancel,
-				pidgin_log_system_list_cb, pidgin_log_data);
-		}
+		pidgin_log_data->count = pidgin_log_data->total++;
+
+		purple_logs_get_system_logs_async(account, G_PRIORITY_DEFAULT,
+			cancel, pidgin_log_system_list_cb, pidgin_log_data);
 	}
 
 	g_object_unref(cancel);
@@ -1525,9 +1529,7 @@ pidgin_log_viewer_set_logs(PidginLogView
 
 	priv->logs = logs;
 
-	gtk_tree_store_clear(pidgin_log_viewer_get_tree_store(lv));
 	populate_log_tree(lv);
-
 	gtk_imhtml_clear(GTK_IMHTML(priv->imhtml));
 	select_first_log(lv);
 
@@ -1747,7 +1749,6 @@ pidgin_log_viewer_constructed(GObject *o
 	g_signal_connect(priv->treeview, "row-activated", G_CALLBACK(log_row_activated_cb), NULL);
 	g_signal_connect(priv->treeview, "button-press-event", G_CALLBACK(log_button_press_cb), lv);
 	g_signal_connect(priv->treeview, "popup-menu", G_CALLBACK(log_popup_menu_cb), lv);
-
 }
 
 static void
============================================================
--- pidgin/gtklog.h	acb614acb351d7fb5e6a8519c27923272fe92c52
+++ pidgin/gtklog.h	983cd6bf099ba32d6ff288b46cbed81d2e8d227f
@@ -38,7 +38,7 @@ G_BEGIN_DECLS
 #define PIDGIN_TYPE_LOG_VIEWER          (pidgin_log_viewer_get_type())
 #define PIDGIN_LOG_VIEWER(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), PIDGIN_TYPE_LOG_VIEWER, PidginLogViewer))
 #define PIDGIN_LOG_VIEWER_CLASS(k)      (G_TYPE_CHECK_CLASS_CAST((k), PIDGIN_TYPE_LOG_VIEWER, PidginLogViewerClass))
-#define PIDGIN_IS_LOG_VIEWER(o)	        (G_TYPE_CHECK_INSTANCE_TYPE ((o), PIDGIN_TYPE_LOG_VIEWER))
+#define PIDGIN_IS_LOG_VIEWER(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), PIDGIN_TYPE_LOG_VIEWER))
 #define PIDGIN_IS_LOG_VIEWER_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE((k), PIDGIN_TYPE_LOG_VIEWER))
 #define PIDGIN_LOG_VIEWER_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS((o), PIDGIN_TYPE_LOG_VIEWER, PidginLogViewerClass))
 
@@ -58,7 +58,6 @@ struct _PidginLogViewer {
 	GtkDialog parent_instance;
 };
 
-// Should this extend something else? Like GtkObject or GtkDialog?
 struct _PidginLogViewerClass {
 	GtkDialogClass parent_class;
 
============================================================
--- finch/gntlog.c	8e04b40f57a836b75c11be686f8183318695c93d
+++ finch/gntlog.c	6e36a0fcdd40b5c463cd80c038cd9edcfbf3e903
@@ -45,23 +45,56 @@
 
 #include "gntlog.h"
 
-// FinchLogViewer members are stored here to avoid an ABI break, will be moved back in 3.x
-typedef struct {
-	FinchLogViewer     *lv;            /**< The rest of the struct */
+G_DEFINE_TYPE (FinchLogViewer, finch_log_viewer, GNT_TYPE_DIALOG)
+
+enum {
+	PROP_0,
+	PROP_LOGS,
+	PROP_TREE,
+	PROP_TEXT_AREA,
+	PROP_SEARCH_STRING,
+	PROP_TOTAL_SIZE,
+	PROP_LIST_BAR,
+	PROP_SEARCH_BAR,
+	PROP_SEARCH_CANCEL,
+	PROP_LIST_CANCEL,
+	PROP_READ_CANCEL,
+	PROP_VIEWER_TYPE,
+	PROP_NEED_LOG_SIZE,
+	PROP_VIEWER_TITLE,
+	LAST_PROP
+};
+
+static GParamSpec *properties[LAST_PROP] = { 0 };
+
+#define FINCH_LOG_VIEWER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), FINCH_TYPE_LOG_VIEWER, FinchLogViewerPrivate))
+typedef struct _FinchLogViewerPrivate FinchLogViewerPrivate;
+
+struct _FinchLogViewerPrivate {
+	GList              *logs;          /**< The list of logs viewed in this viewer */
+	GntWidget          *tree;          /**< The treeview representing said treestore */
+	GntWidget          *text;          /**< The imhtml to display said logs */
+	GntWidget          *entry;         /**< The search entry, in which search terms are entered */
+	gchar              *search;        /**< The string currently being searched for */
+	GntWidget          *label;         /**< The label at the top of the log viewer */
+
 	gsize              size;           /**< The actual value of the total log size */
-	GntWidget          *size_label;    /**< The label of the size of the log */
+	GntWidget          *size_label;    /**< The label with total log size */
 	GntWidget          *list_bar;      /**< The progress bar */
 	GntWidget          *search_bar;    /**< The progess bar for searches */
 
-	GCancellable       *read_cancel;   /**< A GCancellable to stop any reads */
 	GCancellable       *search_cancel; /**< A GCancellable to stop any searches */
 	GCancellable       *list_cancel;   /**< A GCancellable to stop any folder listings */
+	GCancellable       *read_cancel;   /**< A GCancellable to stop any reads */
 
-	PurpleLogChatType  chat_type;      /**< The log type of the window */
-} FinchLogViewerEx;
+	PurpleLogChatType  viewer_type;    /**< The log type of the window */
+	gboolean           need_log_size;
+	GntWidget          *title_box;
+	gchar              *title;
+};
 
 typedef struct {
-	FinchLogViewerEx *log_viewer;
+	FinchLogViewer *log_viewer;
 	PurpleLog *log;
 
 	gboolean is_window_open;
@@ -81,20 +114,20 @@ static void finch_window_destroy_cb(_fin
 
 static void finch_log_data_free(_finch_log_data *);
 static void finch_window_destroy_cb(_finch_log_data *);
-static void finch_log_viewer_ex_set_read_cancel(FinchLogViewerEx *, GCancellable *);
-static void finch_log_viewer_ex_set_search_cancel(FinchLogViewerEx *, GCancellable *);
-static void finch_log_viewer_ex_set_list_cancel(FinchLogViewerEx *, GCancellable *);
+static void finch_log_viewer_set_read_cancel(FinchLogViewer *, GCancellable *);
+static void finch_log_viewer_set_search_cancel(FinchLogViewer *, GCancellable *);
+static void finch_log_viewer_set_list_cancel(FinchLogViewer *, GCancellable *);
 static guint log_viewer_hash(gconstpointer);
 static gboolean log_viewer_equal(gconstpointer, gconstpointer);
 static const gchar *log_get_date(PurpleLog *);
 static void finch_log_search_done_cb(_finch_log_data *);
 static void finch_log_search_cb(GObject *, GAsyncResult *, gpointer);
-static void search_cb(GntWidget *, FinchLogViewerEx *);
+static void search_cb(GntWidget *, FinchLogViewer *);
 static void destroy_cb(GntWidget *, log_viewer_hash_t *);
 static void finch_log_read_cb(GObject *, GAsyncResult *, gpointer);
-static void log_select_cb(GntWidget *, gpointer, gpointer, FinchLogViewerEx *);
-static void populate_log_tree(FinchLogViewerEx *);
-static FinchLogViewerEx *display_log_viewer_nonblocking(log_viewer_hash_t *,
+static void log_select_cb(GntWidget *, gpointer, gpointer, FinchLogViewer *);
+static void populate_log_tree(FinchLogViewer *);
+static FinchLogViewer *finch_log_viewer_new(log_viewer_hash_t *,
 	const gchar *, gboolean);
 static void finch_log_done_cb(_finch_log_data *);
 static void finch_log_viewer_update_list_bar(_finch_log_data *);
@@ -105,52 +138,14 @@ static void finch_log_sets_cb(GObject *,
 static void finch_log_sets_cb(GObject *, GAsyncResult *, gpointer);
 
 
-static GHashTable *log_viewers = NULL;
-static FinchLogViewerEx *syslog_viewer = NULL;
+G_LOCK_DEFINE(log_viewers);
+G_LOCK_DEFINE(syslog_viewer);
 
 
-static void
-finch_log_viewer_ex_set_read_cancel(FinchLogViewerEx *lv_ex, GCancellable *cancel)
-{
-	if (lv_ex->read_cancel != NULL) {
-		g_cancellable_cancel(lv_ex->read_cancel);
-		g_object_unref(lv_ex->read_cancel);
-	}
+static GHashTable *log_viewers = NULL;
+static FinchLogViewer *syslog_viewer = NULL;
 
-	if (cancel != NULL)
-		g_object_ref(cancel);
 
-	lv_ex->read_cancel = cancel;
-}
-
-static void
-finch_log_viewer_ex_set_search_cancel(FinchLogViewerEx *lv_ex, GCancellable *cancel)
-{
-	if (lv_ex->search_cancel != NULL) {
-		g_cancellable_cancel(lv_ex->search_cancel);
-		g_object_unref(lv_ex->search_cancel);
-	}
-
-	if (cancel != NULL)
-		g_object_ref(cancel);
-
-	lv_ex->search_cancel = cancel;
-}
-
-static void
-finch_log_viewer_ex_set_list_cancel(FinchLogViewerEx *lv_ex, GCancellable *cancel)
-{
-	if (lv_ex->list_cancel != NULL) {
-		g_cancellable_cancel(lv_ex->list_cancel);
-		g_object_unref(lv_ex->list_cancel);
-	}
-
-	if (cancel != NULL)
-		g_object_ref(cancel);
-
-	lv_ex->list_cancel = cancel;
-}
-
 static guint
 log_viewer_hash(gconstpointer data)
 {
@@ -230,9 +225,9 @@ finch_log_search_done_cb(_finch_log_data
 finch_log_search_done_cb(_finch_log_data *finch_log_data)
 {
 //	if (finch_log_data->is_window_open) {
-//		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
+//		FinchLogViewer *lv = finch_log_data->log_viewer;
 //
-//		gnt_widget_hide(lv_ex->search_bar);
+//		gnt_widget_hide(finch_log_viewer_get_search_bar(lv));
 //	}
 
 	finch_log_data_free(finch_log_data);
@@ -270,56 +265,63 @@ static void
 }
 
 static void
-search_cb(GntWidget *button, FinchLogViewerEx *lv_ex)
+search_cb(GntWidget *button, FinchLogViewer *lv)
 {
 	_finch_log_data *finch_log_data;
-	FinchLogViewer *lv = lv_ex->lv;
+	FinchLogViewerPrivate *priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+	GntTree *tree = GNT_TREE(finch_log_viewer_get_tree(lv));
+	GntTextView *view = GNT_TEXT_VIEW(finch_log_viewer_get_text_area(lv));
+	GntWidget *bar;
 	GCancellable *cancel;
 	GList *logs;
-	const gchar *search_term = gnt_entry_get_text(GNT_ENTRY(lv->entry));
+	const gchar *search_term, *old_search;
 	guint length;
 
-	if (!(*search_term)) {
+	search_term = gnt_entry_get_text(GNT_ENTRY(priv->entry));
+
+	if (*search_term == 0) {
 		/* Reset the tree, make sure we clear the search term first so that
 		   log_select_cb knows how to tell the months from the individual logs
 		 */
-		g_free(lv->search);
-		lv->search = NULL;
+		finch_log_viewer_set_search_string(lv, NULL);
+		finch_log_viewer_set_search_cancel(lv, NULL);
 
-		finch_log_viewer_ex_set_search_cancel(lv_ex, NULL);
-		gnt_tree_remove_all(GNT_TREE(lv->tree));
-		populate_log_tree(lv_ex);
+		populate_log_tree(lv);
 
 		return;
 	}
 
-	if (lv->search != NULL && !strcmp(lv->search, search_term))
+	old_search = finch_log_viewer_get_search_string(lv);
+
+	if (old_search != NULL && !strcmp(old_search, search_term))
 		return;
 
-	g_free(lv->search);
-	lv->search = g_strdup(search_term);
+	logs = finch_log_viewer_get_logs(lv);
+	length = g_list_length(logs);
 
-	length = g_list_length(lv->logs);
-
 	if (length < 1)
 		return;
 
-	gnt_tree_remove_all(GNT_TREE(lv->tree));
-	gnt_text_view_clear(GNT_TEXT_VIEW(lv->text));
+	finch_log_viewer_set_search_string(lv, search_term);
+	gnt_tree_remove_all(tree);
+	gnt_text_view_clear(lv->text));
 
 	finch_log_data = g_new0(_finch_log_data, 1);
 	finch_log_data->is_window_open = TRUE;
-	finch_log_data->log_viewer = lv_ex;
+	finch_log_data->log_viewer = lv;
+	finch_log_data->string = g_strdup(search_term);
 	finch_log_data->count = finch_log_data->total = length;
-	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv->window,
+	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(finch_window_destroy_cb), finch_log_data);
 
-	gnt_progress_bar_set_fraction(GNT_PROGRESS_BAR(lv_ex->search_bar), 0.0);
+	bar = finch_log_viewer_get_search_bar(lv);
+	// gnt_widget_show(bar);
+	gnt_progress_bar_set_fraction(GNT_PROGRESS_BAR(bar), 0.0);
 
 	cancel = g_cancellable_new();
-	finch_log_viewer_ex_set_search_cancel(lv_ex, cancel);
+	finch_log_viewer_set_search_cancel(lv, cancel);
 
-	for (logs = lv->logs; logs != NULL; logs = g_list_next(logs))
+	for ( ; logs != NULL; logs = g_list_next(logs))
 		purple_log_read_async(logs->data, G_PRIORITY_DEFAULT_IDLE, cancel,
 			finch_log_search_cb, finch_log_data);
 
@@ -329,44 +331,20 @@ destroy_cb(GntWidget *w, log_viewer_hash
 static void
 destroy_cb(GntWidget *w, log_viewer_hash_t *ht)
 {
-	FinchLogViewerEx *lv_ex = syslog_viewer;
-	FinchLogViewer *lv;
-
 	if (ht != NULL) {
-		lv_ex = g_hash_table_lookup(log_viewers, ht);
+		G_LOCK(log_viewers);
 		g_hash_table_remove(log_viewers, ht);
+		G_UNLOCK(log_viewers);
 
-		g_free(ht->username);
+		g_free(ht->buddyname);
 		g_free(ht);
-	} else
+	} else {
+		G_LOCK(syslog_viewer);
 		syslog_viewer = NULL;
-
-	lv = lv_ex->lv;
-	purple_request_close_with_handle(lv);
-
-	g_list_foreach(lv->logs, (GFunc) g_object_unref, NULL);
-	g_list_free(lv->logs);
-
-	g_free(lv->search);
-	g_free(lv);
-
-	if (lv_ex->read_cancel != NULL) {
-		g_cancellable_cancel(lv_ex->read_cancel);
-		g_object_unref(lv_ex->read_cancel);
+		G_UNLOCK(syslog_viewer);
 	}
 
-	if (lv_ex->search_cancel != NULL) {
-		g_cancellable_cancel(lv_ex->search_cancel);
-		g_object_unref(lv_ex->search_cancel);
-	}
-
-	if (lv_ex->list_cancel != NULL) {
-		g_cancellable_cancel(lv_ex->list_cancel);
-		g_object_unref(lv_ex->list_cancel);
-	}
-
-	g_free(lv_ex);
-	gnt_widget_destroy(w);
+	gnt_widget_destroy(GNT_WIDGET(lv));
 }
 
 static void
@@ -377,22 +355,23 @@ finch_log_read_cb(GObject *object, GAsyn
 	if (finch_log_data->is_window_open) {
 		PurpleLog *log = finch_log_data->log;
 		PurpleLogReadFlags flags;
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		FinchLogViewer *lv = lv_ex->lv;
-		GError *err = NULL;
+		FinchLogViewer *lv = finch_log_data->log_viewer;
+		GntTextView *view = GNT_TEXT_VIEW(finch_log_viewer_get_text_area(lv));
+		GError *error = NULL;
+		const gchar *search = finch_log_viewer_get_search_string(lv);
 		gchar *text, *strip;
 
-		text = purple_log_read_finish(log, res, &flags, &err);
+		text = purple_log_read_finish(log, res, &flags, &error);
 
 		if (text == NULL) {
-			if (err->code == G_IO_ERROR_CANCELLED) {
+			if (error->code == G_IO_ERROR_CANCELLED) {
 				finch_log_data_free(finch_log_data);
-				g_clear_error(&err);
+				g_clear_error(&error);
 
 				return;
 			}
 
-			text = err->message;
+			text = error->message;
 		}
 
 		if (!(flags & PURPLE_LOG_READ_NO_NEWLINE)) {
@@ -402,32 +381,31 @@ finch_log_read_cb(GObject *object, GAsyn
 		} else
 			strip = purple_markup_strip_html(text);
 
-		gnt_text_view_clear(GNT_TEXT_VIEW(lv->text));
+		gnt_text_view_clear(view);
 
 		purple_signal_emit(finch_log_get_handle(), "log-displaying", lv, log);
 
-		gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(lv->text), strip,
-			GNT_TEXT_FLAG_NORMAL);
+		gnt_text_view_append_text_with_flags(view, strip, GNT_TEXT_FLAG_NORMAL);
 
 		g_free(strip);
-		g_clear_error(&err);
+		g_clear_error(&error);
 	}
 
 	finch_log_data_free(finch_log_data);
 }
 
 static void
-log_select_cb(GntWidget *w, gpointer old_row, gpointer new_row, FinchLogViewerEx *lv_ex)
+log_select_cb(GntWidget *w, gpointer old_row, gpointer new_row, FinchLogViewer *lv)
 {
 	_finch_log_data *finch_log_data;
-	FinchLogViewer *lv = lv_ex->lv;
 	PurpleLog *log;
 	PurpleLogChatType chat_type;
 	GntTree *tree = GNT_TREE(w);
 	GCancellable *cancel;
 
 	/* Make sure we don't select the month row */
-	if (lv->search == NULL && gnt_tree_get_parent_key(tree, new_row) == NULL)
+	if (finch_log_viewer_get_search_string(lv) == NULL &&
+		gnt_tree_get_parent_key(tree, new_row) == NULL)
 		return;
 
 	log = new_row;
@@ -438,6 +416,7 @@ log_select_cb(GntWidget *w, gpointer old
 	chat_type = purple_log_get_chat_type(log);
 
 	if (chat_type != PURPLE_LOG_SYSTEM) {
+		FinchLogViewerPrivate *priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
 		const gchar *name = purple_log_get_name(log);
 		gchar *title;
 
@@ -448,19 +427,20 @@ log_select_cb(GntWidget *w, gpointer old
 			title = g_strdup_printf(_("Conversation with %s on %s"),
 				name, log_get_date(log));
 
-		gnt_label_set_text(GNT_LABEL(lv->label), title);
+		gnt_label_set_text(GNT_LABEL(priv->label), title);
 		g_free(title);
 	}
 
 	finch_log_data = g_new0(_finch_log_data, 1);
 	finch_log_data->is_window_open = TRUE;
-	finch_log_data->log_viewer = lv_ex;
+	finch_log_data->count = 1;
+	finch_log_data->log_viewer = lv;
 	finch_log_data->log = log;
-	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv->window,
+	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
         "destroy", G_CALLBACK(finch_window_destroy_cb), finch_log_data);
 
 	cancel = g_cancellable_new();
-	finch_log_viewer_ex_set_read_cancel(lv_ex, cancel);
+	finch_log_viewer_set_read_cancel(lv, cancel);
 
 	purple_log_read_async(log, G_PRIORITY_DEFAULT, cancel,
 		finch_log_read_cb, finch_log_data);
@@ -475,16 +455,18 @@ static void
  * For now, I'll just make it a flat list.
  */
 static void
-populate_log_tree(FinchLogViewerEx *lv_ex)
+populate_log_tree(FinchLogViewer *lv)
      /* Logs are made from trees in real life.
         This is a tree made from logs */
 {
-	FinchLogViewer *lv = lv_ex->lv;
-	GList *logs;
+	GntTree *tree = GNT_TREE(finch_log_viewer_get_tree(lv));
+	GList *logs = finch_log_viewer_get_logs(lv);
 	const gchar *pmonth;
 	gchar *month = NULL, prev_top_month[30] = "";
 
-	for (logs = lv->logs; logs != NULL; logs = g_list_next(logs)) {
+	gnt_tree_remove_all(tree);
+
+	for ( ; logs != NULL; logs = g_list_next(logs)) {
 		PurpleLog *log = logs->data;
 		const struct tm *tm = purple_log_get_tm(log);
 		time_t log_time = purple_log_get_time(log);
@@ -496,31 +478,51 @@ populate_log_tree(FinchLogViewerEx *lv_e
 			month = g_strdup(pmonth);
 
 			/* top level */
-			gnt_tree_add_row_last(GNT_TREE(lv->tree), month,
-				gnt_tree_create_row(GNT_TREE(lv->tree), month),
+			gnt_tree_add_row_last(tree, month,
+				gnt_tree_create_row(tree, month),
 				NULL);
-			gnt_tree_set_expanded(GNT_TREE(lv->tree), month, FALSE);
+			gnt_tree_set_expanded(tree, month, FALSE);
 
 			strncpy(prev_top_month, month, sizeof(prev_top_month));
 		}
 
 		/* sub */
-		gnt_tree_add_row_last(GNT_TREE(lv->tree), log,
-			gnt_tree_create_row(GNT_TREE(lv->tree), log_get_date(log)),
+		gnt_tree_add_row_last(tree, log,
+			gnt_tree_create_row(tree, log_get_date(log)),
 			month);
 	}
 }
 
-static FinchLogViewerEx *
-display_log_viewer_nonblocking(log_viewer_hash_t *ht,
+FinchLogViewer *
+finch_log_viewer_new(log_viewer_hash_t *ht,
 	const gchar *title, gboolean need_log_size)
 {
-	FinchLogViewerEx *lv_ex;
 	FinchLogViewer *lv;
+
+	lv = g_object_new(Finch_TYPE_LOG_VIEWER,
+		"viewer-title", title,
+		"viewer-type", ht != NULL ? ht->chat_type : PURPLE_LOG_SYSTEM,
+		"need-log-size", need_log_size,
+		NULL);
+
+	/* Store the information to later prevent duplicate windows from popping up */
+	if (ht != NULL) {
+		G_LOCK(log_viewers);
+		g_hash_table_insert(log_viewers, ht, g_object_ref(lv));
+		G_UNLOCK(log_viewers);
+	}
+
+	g_signal_connect(lv, "response", G_CALLBACK(destroy_cb), ht);
+
+	return lv;
+}
+#if 0
+	FinchLogViewer *lv_ex;
+	FinchLogViewer *lv;
 	GntWidget *vbox, *hbox;
 	gchar *text;
 
-	lv_ex = g_new0(FinchLogViewerEx, 1);
+	lv_ex = g_new0(FinchLogViewer, 1);
 	lv = g_new0(FinchLogViewer, 1);
 	lv->logs = NULL;
 	lv_ex->lv = lv;
@@ -552,7 +554,7 @@ display_log_viewer_nonblocking(log_viewe
 	lv->tree = gnt_tree_new();
 	gnt_widget_set_size(lv->tree, 30, 0);
 	g_signal_connect(lv->tree, "selection-changed",
-		G_CALLBACK(log_select_cb), lv_ex);
+		G_CALLBACK(log_select_cb), lv);
 	gnt_box_add_widget(GNT_BOX(hbox), lv->tree);
 
 	/* Viewer ************/
@@ -565,11 +567,11 @@ display_log_viewer_nonblocking(log_viewe
 
 	/* Log size ************/
 	if (need_log_size) {
-		lv_ex->size = 0;
+		priv->size = 0;
 		text = g_strdup_printf("%s %s", _("Total log size:"), _("calculating..."));
 
-		lv_ex->size_label = gnt_label_new(text);
-		gnt_box_add_widget(GNT_BOX(hbox), lv_ex->size_label);
+		priv->size_label = gnt_label_new(text);
+		gnt_box_add_widget(GNT_BOX(hbox), priv->size_label);
 
 		g_free(text);
 	}
@@ -600,32 +602,37 @@ display_log_viewer_nonblocking(log_viewe
 	lv_ex->list_cancel = NULL;
 
 	return lv_ex;
-}
+#endif
 
 static void
 finch_log_done_cb(_finch_log_data *finch_log_data)
 {
 	if (finch_log_data->is_window_open) {
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		FinchLogViewer *lv = lv_ex->lv;
+		FinchLogViewer *lv = finch_log_data->log_viewer;
+		GntWidget *bar = finch_log_viewer_get_list_bar(lv);
+		GList *logs = finch_log_viewer_get_logs(lv);
 
-//		gnt_widget_hide(lv_ex->list_bar);
+//		gnt_widget_hide(bar);
 
-		if (lv->logs == NULL) {
+		if (logs == NULL) {
 			/* No logs were found. */
+			PurpleLogChatType chat_type = finch_log_viewer_get_viewer_type(lv);
 			const gchar *log_preferences = NULL;
 
-			if (lv_ex->chat_type == PURPLE_LOG_SYSTEM) {
+			if (chat_type == PURPLE_LOG_SYSTEM) {
 				if (!purple_prefs_get_bool("/purple/logging/log_system"))
-					log_preferences = _("System events will only be logged if the \"Log all status changes to system log\""
+					log_preferences = _("System events will only be logged if the "
+						"\"Log all status changes to system log\" "
 						"preference is enabled.");
-			} else if (lv_ex->chat_type == PURPLE_LOG_IM) {
+			} else if (chat_type == PURPLE_LOG_IM) {
 				if (!purple_prefs_get_bool("/purple/logging/log_ims"))
-					log_preferences = _("Instant messages will only be logged if the \"Log all instant messages\""
+					log_preferences = _("Instant messages will only be logged if the "
+						"\"Log all instant messages\" "
 						"preference is enabled.");
-			} else if (lv_ex->chat_type == PURPLE_LOG_CHAT) {
+			} else if (chat_type == PURPLE_LOG_CHAT) {
 				if (!purple_prefs_get_bool("/purple/logging/log_chats"))
-					log_preferences = _("Chats will only be logged if the \"Log all chats\" preference is enabled.");
+					log_preferences = _("Chats will only be logged if the "
+						"\"Log all chats\" preference is enabled.");
 			}
 
 			purple_notify_info(NULL, GNT_BOX(lv->window)->title,
@@ -640,66 +647,55 @@ finch_log_viewer_update_list_bar(_finch_
 static void
 finch_log_viewer_update_list_bar(_finch_log_data *finch_log_data)
 {
-	if (finch_log_data->is_window_open) {
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		gdouble fraction;
+	FinchLogViewer *lv = finch_log_data->log_viewer;
+	GntWidget *bar = finch_log_viewer_get_list_bar(lv);
+	gdouble fraction;
 
-		fraction = (gdouble) finch_log_data->count /
-			(gdouble) finch_log_data->total;
-		gnt_progress_bar_set_fraction(GNT_PROGRESS_BAR(lv_ex->list_bar),
-			1.0 - fraction);
-	}
+	fraction = (gdouble) finch_log_data->count /
+		(gdouble) finch_log_data->total;
+	gnt_progress_bar_set_fraction(GNT_PROGRESS_BAR(bar), 1.0 - fraction);
 }
 
 static void
 finch_log_viewer_update_search_bar(_finch_log_data *finch_log_data)
 {
-	if (finch_log_data->is_window_open) {
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		gdouble fraction;
+	FinchLogViewer *lv = finch_log_data->log_viewer;
+	GtkWidget *bar = finch_log_viewer_get_search_bar(lv);
+	gdouble fraction;
 
-		fraction = (gdouble) finch_log_data->count /
-			(gdouble) finch_log_data->total;
-		gnt_progress_bar_set_fraction(GNT_PROGRESS_BAR(lv_ex->search_bar),
-			1.0 - fraction);
-	}
+	fraction = (gdouble) finch_log_data->count /
+		(gdouble) finch_log_data->total;
+	gnt_progress_bar_set_fraction(GNT_PROGRESS_BAR(bar), 1.0 - fraction);
 }
 
 static void
 finch_log_size_cb(GObject *object, GAsyncResult *res, gpointer userdata)
 {
 	_finch_log_data *finch_log_data = userdata;
-	GError *err = NULL;
+	GError *error = NULL;
 	gssize log_size;
 
-	log_size = purple_logs_get_total_size_finish(res, &err);
+	log_size = purple_logs_get_total_size_finish(res, &error);
 	finch_log_data->count--;
 
 	if (log_size < 0) {
-		if (err->code != G_IO_ERROR_CANCELLED)
-			purple_debug_error("gntlog", "Error getting total log size: %s\n", err->message);
+		if (error->code != G_IO_ERROR_CANCELLED)
+			purple_debug_error("gntlog", "Error getting total log size: %s\n",
+				error->message);
 	} else if (finch_log_data->is_window_open) {
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		gchar *sz_txt, *text;
+		FinchLogViewer *lv = finch_log_data->log_viewer;
 		gsize total;
 
-		total = lv_ex->size;
+		total = finch_log_viewer_get_total_size(lv);
 		total += log_size;
+		finch_log_viewer_set_total_size(lv, total);
+	}
 
-		lv_ex->size = total;
+	g_clear_error(&error);
 
-		sz_txt = purple_str_size_to_units(total);
-		text = g_strdup_printf("%s: %s", _("Total log size"), sz_txt);
+	if (finch_log_data->is_window_open)
+		finch_log_viewer_update_list_bar(finch_log_data);
 
-		gnt_label_set_text(GNT_LABEL(lv_ex->size_label), text);
-
-		g_free(sz_txt);
-		g_free(text);
-	}
-
-	g_clear_error(&err);
-	finch_log_viewer_update_list_bar(finch_log_data);
-
 	if (finch_log_data->count < 1)
 		finch_log_done_cb(finch_log_data);
 }
@@ -708,29 +704,24 @@ finch_log_list_cb(GObject *object, GAsyn
 finch_log_list_cb(GObject *object, GAsyncResult *res, gpointer userdata)
 {
 	_finch_log_data *finch_log_data = userdata;
-	GError *err = NULL;
+	GError *error = NULL;
 	GList *list;
 
-	list = purple_logs_get_logs_finish(res, &err);
+	list = purple_logs_get_logs_finish(res, &error);
 	finch_log_data->count--;
 
 	if (list == NULL) {
-		if (err != NULL && err->code != G_IO_ERROR_CANCELLED)
-			purple_debug_error("gntlog", "Error getting logs: %s\n", err->message);
-	} else if (finch_log_data->is_window_open) {
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		FinchLogViewer *lv = lv_ex->lv;
+		if (error != NULL && error->code != G_IO_ERROR_CANCELLED)
+			purple_debug_error("gntlog", "Error getting logs: %s\n",
+				error->message);
+	} else if (finch_log_data->is_window_open)
+		finch_log_viewer_add_logs(finch_log_data->log_viewer, list);
 
-		lv->logs = g_list_concat(lv->logs, list);
-		lv->logs = g_list_sort(lv->logs, purple_log_compare);
+	g_clear_error(&error);
 
-		gnt_tree_remove_all(GNT_TREE(lv->tree));
-		populate_log_tree(lv_ex);
-	}
+	if (finch_log_data->is_window_open)
+		finch_log_viewer_update_list_bar(finch_log_data);
 
-	g_clear_error(&err);
-	finch_log_viewer_update_list_bar(finch_log_data);
-
 	if (finch_log_data->count < 1)
 		finch_log_done_cb(finch_log_data);
 }
@@ -739,29 +730,24 @@ finch_log_system_list_cb(GObject *object
 finch_log_system_list_cb(GObject *object, GAsyncResult *res, gpointer userdata)
 {
 	_finch_log_data *finch_log_data = userdata;
-	GError *err = NULL;
+	GError *error = NULL;
 	GList *list;
 
-	list = purple_logs_get_system_logs_finish(res, &err);
+	list = purple_logs_get_system_logs_finish(res, &error);
 	finch_log_data->count--;
 
 	if (list == NULL) {
-		if (err != NULL && err->code != G_IO_ERROR_CANCELLED)
-			purple_debug_error("gntlog", "Error getting system logs: %s\n", err->message);
-	} else if (finch_log_data->is_window_open) {
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		FinchLogViewer *lv = lv_ex->lv;
+		if (error != NULL && error->code != G_IO_ERROR_CANCELLED)
+			purple_debug_error("gntlog", "Error getting system logs: %s\n",
+				error->message);
+	} else if (finch_log_data->is_window_open)
+		finch_log_viewer_add_logs(finch_log_data->log_viewer, list);
 
-		lv->logs = g_list_concat(lv->logs, list);
-		lv->logs = g_list_sort(lv->logs, purple_log_compare);
-
-		gnt_tree_remove_all(GNT_TREE(lv->tree));
-		populate_log_tree(lv_ex);
-	}
-
 	g_clear_error(&err);
-	finch_log_viewer_update_list_bar(finch_log_data);
 
+	if (finch_log_data->is_window_open)
+		finch_log_viewer_update_list_bar(finch_log_data);
+
 	if (finch_log_data->count < 1)
 		finch_log_done_cb(finch_log_data);
 }
@@ -770,29 +756,29 @@ finch_log_sets_cb(GObject *object, GAsyn
 finch_log_sets_cb(GObject *object, GAsyncResult *res, gpointer userdata)
 {
 	_finch_log_data *finch_log_data = userdata;
-	GError *err = NULL;
+	GError *error = NULL;
 	GHashTable *table;
 
-	table = purple_logs_get_log_sets_finish(res, &err);
+	table = purple_logs_get_log_sets_finish(res, &error);
 
 	if (table == NULL) {
-		if (err != NULL && err->code != G_IO_ERROR_CANCELLED)
-			purple_debug_error("gntlog", "Error getting log sets: %s\n", err->message);
+		if (error->code != G_IO_ERROR_CANCELLED)
+			purple_debug_error("gntlog", "Error getting log sets: %s\n",
+				error->message);
 
 		finch_log_data_free(finch_log_data);
 	} else if (finch_log_data->is_window_open) {
-		FinchLogViewerEx *lv_ex = finch_log_data->log_viewer;
-		GList *list, *n;
-		guint length;
+		FinchLogViewer *lv = finch_log_data->log_viewer;
+		GList *list = g_hash_table_get_keys(table), *n;
+		guint length = g_list_length(list);
 
-		list = g_hash_table_get_keys(table);
-		length = g_list_length(list);
+		if (length > 0) {
+			GCancellable *cancel = finch_log_viewer_get_list_cancel(lv);
 
-		if (length > 0) {
 			finch_log_data->count = finch_log_data->total = 0;
 
-			for (n = list; n != NULL; n = g_list_next(n)) {
-				PurpleLogSet *set = n->data;
+			for (n = list ; n != NULL; n = g_list_next(n)) {
+				PurpleLogSet *set = list->data;
 
 				if (set->type != PURPLE_LOG_IM)
 					continue;
@@ -800,18 +786,19 @@ finch_log_sets_cb(GObject *object, GAsyn
 				finch_log_data->count = (finch_log_data->total += 2);
 
 				purple_logs_get_logs_async(PURPLE_LOG_IM, set->name, set->account,
-					G_PRIORITY_DEFAULT, lv_ex->list_cancel, finch_log_list_cb, finch_log_data);
+					G_PRIORITY_DEFAULT, cancel, finch_log_list_cb, finch_log_data);
 				purple_logs_get_total_size_async(PURPLE_LOG_IM, set->name, set->account,
-					G_PRIORITY_DEFAULT, lv_ex->list_cancel, finch_log_size_cb, finch_log_data);
+					G_PRIORITY_DEFAULT, cancel, finch_log_size_cb, finch_log_data);
 			}
 		}
 
+		g_list_foreach(list, (GFunc) purple_log_set_free, NULL);
 		g_list_free(list);
 		g_hash_table_unref(table);
 	} else
 		finch_log_data_free(finch_log_data);
 
-	g_clear_error(&err);
+	g_clear_error(&error);
 }
 
 void
@@ -819,7 +806,7 @@ finch_log_show(PurpleLogChatType chat_ty
 {
 	log_viewer_hash_t *ht;
 	_finch_log_data *finch_log_data;
-	FinchLogViewerEx *lv_ex;
+	FinchLogViewer *lv;
 	GCancellable *cancel;
 	const gchar *name = username;
 	gchar *title;
@@ -830,16 +817,17 @@ finch_log_show(PurpleLogChatType chat_ty
 	}
 
 	ht = g_new0(log_viewer_hash_t, 1);
-
 	ht->chat_type = chat_type;
 	ht->username = g_strdup(username);
 	ht->account = account;
 
-	if (log_viewers == NULL)
-		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
-	else if ((lv_ex = g_hash_table_lookup(log_viewers, ht)) != NULL) {
-		gnt_window_present(lv_ex->lv->window);
+	G_LOCK(log_viewers);
+	lv = g_hash_table_lookup(log_viewers, ht);
+	G_UNLOCK(log_viewers);
 
+	if (lv != NULL) {
+		gnt_window_present(GNT_WINDOW(lv));
+
 		g_free(ht->username);
 		g_free(ht);
 
@@ -868,16 +856,17 @@ finch_log_show(PurpleLogChatType chat_ty
 	finch_log_data = g_new0(_finch_log_data, 1);
 	finch_log_data->is_window_open = TRUE;
 
-	lv_ex = finch_log_data->log_viewer = display_log_viewer_nonblocking(ht,
+	lv = finch_log_data->log_viewer = finch_log_viewer_new(ht,
 		title, TRUE);
+	gnt_widget_show(GNT_WIDGET(lv));
 
-	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv_ex->lv->window,
+	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(finch_window_destroy_cb), finch_log_data);
 
 	g_free(title);
 
 	cancel = g_cancellable_new();
-	finch_log_viewer_ex_set_list_cancel(lv_ex, cancel);
+	finch_log_viewer_set_list_cancel(lv, cancel);
 
 	if (username != NULL) {
 		finch_log_data->count = finch_log_data->total = 2;
@@ -903,7 +892,7 @@ finch_log_show_contact(PurpleContact *co
 	_finch_log_data *finch_log_data;
 	log_viewer_hash_t *ht;
 	PurpleBlistNode *child;
-	FinchLogViewerEx *lv_ex;
+	FinchLogViewer *lv;
 	GCancellable *cancel;
 	const gchar *name = NULL;
 	gchar *title;
@@ -914,10 +903,12 @@ finch_log_show_contact(PurpleContact *co
 	ht->chat_type = PURPLE_LOG_IM;
 	ht->contact = contact;
 
-	if (log_viewers == NULL)
-		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
-	else if ((lv_ex = g_hash_table_lookup(log_viewers, ht)) != NULL) {
-		gnt_window_present(lv_ex->lv->window);
+	G_LOCK(log_viewers);
+	lv = g_hash_table_lookup(log_viewers, ht);
+	G_UNLOCK(log_viewers);
+
+	if (lv != NULL) {
+		gnt_window_present(GNT_WINDOW(lv));
 		g_free(ht);
 
 		return;
@@ -944,17 +935,18 @@ finch_log_show_contact(PurpleContact *co
 	finch_log_data->count = finch_log_data->total = 0;
 
 	title = g_strdup_printf(_("Conversations with %s"), name);
-	lv_ex = finch_log_data->log_viewer = display_log_viewer_nonblocking(ht, title, TRUE);
+	lv = finch_log_data->log_viewer = finch_log_viewer_new(ht, title, TRUE);
 	g_free(title);
+	gnt_widget_show(GNT_WIDGET(lv));
 
-	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv_ex->lv->window,
+	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(finch_window_destroy_cb), finch_log_data);
 
 	cancel = g_cancellable_new();
-	finch_log_viewer_ex_set_list_cancel(lv_ex, cancel);
+	finch_log_viewer_set_list_cancel(lv, cancel);
 
-	for (child = purple_blist_node_get_first_child(PURPLE_BLIST_NODE(contact)); child != NULL;
-		child = purple_blist_node_get_sibling_next(child))
+	for (child = purple_blist_node_get_first_child(PURPLE_BLIST_NODE(contact));
+		child != NULL; child = purple_blist_node_get_sibling_next(child))
 	{
 		const gchar *name;
 		PurpleAccount *account;
@@ -980,12 +972,16 @@ finch_syslog_show(void)
 finch_syslog_show(void)
 {
 	_finch_log_data *finch_log_data;
+	PidginLogViewer *lv;
 	GCancellable *cancel;
 	GList *accounts = NULL;
 
-	if (syslog_viewer != NULL) {
-		gnt_window_present(syslog_viewer->lv->window);
+	G_LOCK(syslog_viewer);
+	lv = syslog_viewer;
+	G_UNLOCK(syslog_viewer);
 
+	if (lv != NULL) {
+		gnt_window_present(GNT_WINDOW(lv));
 		return;
 	}
 
@@ -993,30 +989,606 @@ finch_syslog_show(void)
 	finch_log_data->is_window_open = TRUE;
 	finch_log_data->count = finch_log_data->total = 0;
 
-	syslog_viewer = finch_log_data->log_viewer = display_log_viewer_nonblocking(NULL,
+	lv = finch_log_data->log_viewer = finch_log_viewer_new(NULL,
 		_("System Log"), FALSE);
+	gnt_widget_show(GNT_WIDGET(lv));
 
-	finch_log_data->destroy_handler_id = g_signal_connect_swapped(syslog_viewer->lv->window,
+	finch_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(finch_window_destroy_cb), finch_log_data);
 
 	cancel = g_cancellable_new();
-	finch_log_viewer_ex_set_list_cancel(syslog_viewer, cancel);
+	finch_log_viewer_set_list_cancel(lv, cancel);
 
-	for (accounts = purple_accounts_get_all(); accounts != NULL; accounts = g_list_next(accounts)) {
+	for(accounts = purple_accounts_get_all(); accounts != NULL;
+		accounts = g_list_next(accounts))
+	{
 		PurpleAccount *account = accounts->data;
 
-		if(purple_find_prpl(purple_account_get_protocol_id(account)) == NULL)
+		if (purple_find_prpl(purple_account_get_protocol_id(account)) == NULL)
 			continue;
 
 		finch_log_data->count = finch_log_data->total++;
 
-		purple_logs_get_system_logs_async(account,
-			G_PRIORITY_DEFAULT, cancel, finch_log_system_list_cb, finch_log_data);
+		purple_logs_get_system_logs_async(account, G_PRIORITY_DEFAULT,
+			cancel, finch_log_system_list_cb, finch_log_data);
 	}
 
 	g_object_unref(cancel);
+
+	G_LOCK(syslog_viewer);
+	syslog_viewer = lv;
+	G_UNLOCK(syslog_viewer);
 }
 
+GList *
+finch_log_viewer_get_logs(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->logs;
+}
+
+GntWidget *
+finch_log_viewer_get_tree(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->tree;
+}
+
+GntWidget *
+finch_log_viewer_get_text_area(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->imhtml;
+}
+
+G_CONST_RETURN gchar *
+finch_log_viewer_get_search_string(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->search;
+}
+
+gsize
+finch_log_viewer_get_total_size(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), 0);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->size;
+}
+
+GntWidget *
+finch_log_viewer_get_list_bar(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->list_bar;
+}
+
+GntWidget *
+finch_log_viewer_get_search_bar(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->search_bar;
+}
+
+GCancellable *
+finch_log_viewer_get_search_cancel(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->search_cancel;
+}
+
+GCancellable *
+finch_log_viewer_get_list_cancel(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->list_cancel;
+}
+
+GCancellable *
+finch_log_viewer_get_read_cancel(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), NULL);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->read_cancel;
+}
+
+PurpleLogChatType
+finch_log_viewer_get_viewer_type(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), PURPLE_LOG_SYSTEM);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->viewer_type;
+}
+
+gboolean
+finch_log_viewer_get_need_log_size(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), FALSE);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->need_log_size;
+}
+
+G_CONST_RETURN gchar *
+finch_log_viewer_get_viewer_title(FinchLogViewer *lv)
+{
+	g_return_val_if_fail(FINCH_IS_LOG_VIEWER(lv), FALSE);
+
+	return FINCH_LOG_VIEWER_GET_PRIVATE(lv)->title;
+}
+
+void
+finch_log_viewer_add_logs(FinchLogViewer *lv, GList *logs)
+{
+	FinchLogViewerPrivate *priv;
+	GList *list;
+
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+
+	priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+	logs = g_list_sort(logs, purple_log_compare);
+
+	// faster if we reverse the list?
+
+	for (list = logs; list != NULL; list = g_list_next(list))
+		insert_log_viewer_log(lv, list->data);
+
+	priv->logs = g_list_concat(priv->logs, logs);
+	priv->logs = g_list_sort(priv->logs, purple_log_compare);
+
+	g_object_notify(G_OBJECT(lv), "logs");
+}
+
+void
+finch_log_viewer_set_logs(FinchLogViewer *lv, GList *logs)
+{
+	FinchLogViewerPrivate *priv;
+
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+
+	priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+
+	g_list_foreach(priv->logs, (GFunc) g_object_unref, NULL);
+	g_list_free(priv->logs);
+
+	priv->logs = logs;
+
+	populate_log_tree(lv);
+
+	g_object_notify(G_OBJECT(lv), "logs");
+}
+
+void
+finch_log_viewer_set_search_string(FinchLogViewer *lv, const gchar *search)
+{
+	FinchLogViewerPrivate *priv;
+
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+
+	priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+
+	g_free(priv->search);
+	priv->search = g_strdup(search);
+
+	g_object_notify(G_OBJECT(lv), "search-string");
+}
+
+void
+finch_log_viewer_set_total_size(FinchLogViewer *lv, gsize total)
+{
+	FinchLogViewerPrivate *priv;
+
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+	g_return_if_fail(finch_log_viewer_get_need_log_size(lv));
+
+	priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+	priv->size = total;
+
+	if (priv->size_label != NULL) {
+		gchar *sz_txt, *text;
+
+		sz_txt = purple_str_size_to_units(total);
+		text = g_strdup_printf("<span weight='bold'>%s</span> %s",
+			_("Total log size:"), sz_txt);
+
+		gnt_label_set_text(GNT_LABEL(priv->size_label), text);
+
+		g_free(sz_txt);
+		g_free(text);
+	}
+
+	g_object_notify(G_OBJECT(lv), "total-size");
+}
+
+void
+finch_log_viewer_set_search_cancel(FinchLogViewer *lv, GCancellable *cancel)
+{
+	FinchLogViewerPrivate *priv;
+
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
+
+	priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+
+	if (priv->search_cancel != NULL) {
+		g_cancellable_cancel(priv->search_cancel);
+		g_object_unref(priv->search_cancel);
+	}
+
+	if (cancel != NULL)
+		g_object_ref(cancel);
+
+	priv->search_cancel = cancel;
+
+	g_object_notify(G_OBJECT(lv), "search-cancel");
+}
+
+void
+finch_log_viewer_set_list_cancel(FinchLogViewer *lv, GCancellable *cancel)
+{
+	FinchLogViewerPrivate *priv;
+
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
+
+	priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+
+	if (priv->list_cancel != NULL) {
+		g_cancellable_cancel(priv->list_cancel);
+		g_object_unref(priv->list_cancel);
+	}
+
+	if (cancel != NULL)
+		g_object_ref(cancel);
+
+	priv->list_cancel = cancel;
+
+	g_object_notify(G_OBJECT(lv), "list-cancel");
+}
+
+void
+finch_log_viewer_set_read_cancel(FinchLogViewer *lv, GCancellable *cancel)
+{
+	FinchLogViewerPrivate *priv;
+
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
+
+	priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+
+	if (priv->read_cancel != NULL) {
+		g_cancellable_cancel(priv->read_cancel);
+		g_object_unref(priv->read_cancel);
+	}
+
+	if (cancel != NULL)
+		g_object_ref(cancel);
+
+	priv->read_cancel = cancel;
+
+	g_object_notify(G_OBJECT(lv), "read-cancel");
+}
+
+static void
+finch_log_viewer_set_viewer_type(FinchLogViewer *lv, PurpleLogChatType viewer_type)
+{
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+
+	FINCH_LOG_VIEWER_GET_PRIVATE(lv)->viewer_type = viewer_type;
+
+	g_object_notify(G_OBJECT(lv), "viewer-type");
+}
+
+static void
+finch_log_viewer_set_need_log_size(FinchLogViewer *lv, gboolean need_log_size)
+{
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+
+	FINCH_LOG_VIEWER_GET_PRIVATE(lv)->need_log_size = need_log_size ? TRUE : FALSE;
+
+	g_object_notify(G_OBJECT(lv), "need-log-size");
+}
+
+static void
+finch_log_viewer_set_viewer_title(FinchLogViewer *lv, const gchar *title)
+{
+	g_return_if_fail(FINCH_IS_LOG_VIEWER(lv));
+	g_return_if_fail(title != NULL
+
+	FINCH_LOG_VIEWER_GET_PRIVATE(lv)->title = g_strdup(title);
+
+	g_object_notify(G_OBJECT(lv), "viewer-title");
+}
+
+static void
+finch_log_viewer_constructed(GObject *object)
+{
+}
+
+static void
+finch_log_viewer_finalize(GObject *object)
+{
+	FinchLogViewer *lv = FINCH_LOG_VIEWER(object);
+	FinchLogViewerPrivate *priv = FINCH_LOG_VIEWER_GET_PRIVATE(lv);
+
+	purple_request_close_with_handle(lv);
+
+	g_list_foreach(priv->logs, (GFunc) g_object_unref, NULL);
+	g_list_free(priv->logs);
+	g_free(priv->search);
+
+	if (priv->search_cancel != NULL) {
+		g_cancellable_cancel(priv->search_cancel);
+		g_object_unref(priv->search_cancel);
+	}
+
+	if (priv->list_cancel != NULL) {
+		g_cancellable_cancel(priv->list_cancel);
+		g_object_unref(priv->list_cancel);
+	}
+
+	if (priv->read_cancel != NULL) {
+		g_cancellable_cancel(priv->read_cancel);
+		g_object_unref(priv->read_cancel);
+	}
+
+	G_OBJECT_CLASS(finch_log_viewer_parent_class)->finalize(object);
+}
+
+static void
+finch_log_viewer_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	FinchLogViewer *lv = FINCH_LOG_VIEWER(object);
+
+	switch (prop_id) {
+	case PROP_LOGS:
+		finch_log_viewer_set_logs(lv, g_value_get_pointer(value));
+		break;
+	case PROP_SEARCH_STRING:
+		finch_log_viewer_set_search_string(lv, g_value_get_string(value));
+		break;
+	case PROP_TOTAL_SIZE:
+		finch_log_viewer_set_total_size(lv, g_value_get_long(value));
+		break;
+	case PROP_SEARCH_CANCEL:
+		finch_log_viewer_set_search_cancel(lv, g_value_get_object(value));
+		break;
+	case PROP_LIST_CANCEL:
+		finch_log_viewer_set_list_cancel(lv, g_value_get_object(value));
+		break;
+	case PROP_READ_CANCEL:
+		finch_log_viewer_set_read_cancel(lv, g_value_get_object(value));
+		break;
+	case PROP_VIEWER_TYPE:
+		finch_log_viewer_set_viewer_type(lv, g_value_get_enum(value));
+		break;
+	case PROP_NEED_LOG_SIZE:
+		finch_log_viewer_set_need_log_size(lv, g_value_get_boolean(value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+finch_log_viewer_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	FinchLogViewer *lv = FINCH_LOG_VIEWER(object);
+
+	switch (prop_id) {
+	case PROP_LOGS:
+		g_value_set_pointer(value, finch_log_viewer_get_logs(lv));
+		break;
+	case PROP_TREE:
+		g_value_set_object(value, finch_log_viewer_get_tree(lv));
+		break;
+	case PROP_TEXT_AREA:
+		g_value_set_object(value, finch_log_viewer_get_text_area(lv));
+		break;
+	case PROP_SEARCH_STRING:
+		g_value_set_string(value, finch_log_viewer_get_search_string(lv));
+		break;
+	case PROP_TOTAL_SIZE:
+		g_value_set_long(value, finch_log_viewer_get_total_size(lv));
+		break;
+	case PROP_LIST_BAR:
+		g_value_set_object(value, finch_log_viewer_get_list_bar(lv));
+		break;
+	case PROP_SEARCH_BAR:
+		g_value_set_object(value, finch_log_viewer_get_search_bar(lv));
+		break;
+	case PROP_SEARCH_CANCEL:
+		g_value_set_object(value, finch_log_viewer_get_search_cancel(lv));
+		break;
+	case PROP_LIST_CANCEL:
+		g_value_set_object(value, finch_log_viewer_get_list_cancel(lv));
+		break;
+	case PROP_READ_CANCEL:
+		g_value_set_object(value, finch_log_viewer_get_read_cancel(lv));
+		break;
+	case PROP_VIEWER_TYPE:
+		g_value_set_enum(value, finch_log_viewer_get_viewer_type(lv));
+		break;
+	case PROP_NEED_LOG_SIZE:
+		g_value_set_boolean(value, finch_log_viewer_get_need_log_size(lv));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+finch_log_viewer_class_init(FinchLogViewerClass *class)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
+
+	gobject_class->set_property = finch_log_viewer_set_property;
+	gobject_class->get_property = finch_log_viewer_get_property;
+	gobject_class->constructed = finch_log_viewer_constructed;
+	gobject_class->finalize = finch_log_viewer_finalize;
+
+	properties[PROP_LOGS] =
+		g_param_spec_pointer("logs",
+			"Log",
+			"A list of the logs being displayed by the viewer",
+			G_PARAM_READWRITE);
+
+	properties[PROP_TREE] =
+		g_param_spec_object("tree",
+			"Tree",
+			"The tree that displays the list of logs to the users",
+			GNT_TYPE_TREE,
+			G_PARAM_READABLE);
+
+	properties[PROP_TEXT_AREA] =
+		g_param_spec_object("text-area",
+			"Text Area",
+			"The text area that displays the currently selected log to the user",
+			GNT_TYPE_TEXT_VIEW,
+			G_PARAM_READABLE);
+
+	properties[PROP_SEARCH_STRING] =
+		g_param_spec_string("search-string",
+			"Search String",
+			"The string containing the current search term",
+			NULL,
+			G_PARAM_READWRITE);
+
+	properties[PROP_TOTAL_SIZE] =
+		g_param_spec_ulong("total-size",
+			"Total Size",
+			"The total number of bytes on disk for the logs",
+			0,
+			G_MAXSIZE,
+			0,
+			G_PARAM_READWRITE);
+
+	properties[PROP_LIST_BAR] =
+		g_param_spec_object("list-bar",
+			"List Bar",
+			"The widget used to display the progress of loading the logs",
+			GNT_TYPE_PROGRESS_BAR,
+			G_PARAM_READABLE);
+
+	properties[PROP_SEARCH_BAR] =
+		g_param_spec_object("search-bar",
+			"Search Bar",
+			"The widget used to display the progress of searching the logs",
+			GNT_TYPE_PROGRESS_BAR,
+			G_PARAM_READABLE);
+
+	properties[PROP_SEARCH_CANCEL] =
+		g_param_spec_object("search-cancel",
+			"Search Cancellable",
+			"A GCancellable object used to stop searches that are in progress",
+			G_TYPE_CANCELLABLE,
+			G_PARAM_READWRITE);
+
+	properties[PROP_LIST_CANCEL] =
+		g_param_spec_object("list-cancel",
+			"List Cancellable",
+			"A GCancellable object used to stop log-listings that are in progress",
+			G_TYPE_CANCELLABLE,
+			G_PARAM_READWRITE);
+
+	properties[PROP_READ_CANCEL] =
+		g_param_spec_object("read-cancel",
+			"Read Cancellable",
+			"A GCancellable object used to stop log-listings that are in progress",
+			G_TYPE_CANCELLABLE,
+			G_PARAM_READWRITE);
+
+	properties[PROP_VIEWER_TYPE] =
+		g_param_spec_enum("viewer-type",
+			"Viewer Type",
+			"The chat type being displayed by the viewer",
+			PURPLE_TYPE_LOG_CHAT_TYPE,
+			PURPLE_LOG_SYSTEM,
+			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+	properties[PROP_NEED_LOG_SIZE] =
+		g_param_spec_boolean("need-log-size",
+			"Need log size",
+			"Indicates whether or not to show the log size",
+			FALSE,
+			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+	properties[PROP_VIEWER_TITLE] =
+		g_param_spec_string("viewer-title",
+			"Viewer Title",
+			"The title of the log viewer",
+			NULL,
+			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+	g_object_class_install_property(gobject_class,
+		PROP_LOGS,
+		properties[PROP_LOGS]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_TREE,
+		properties[PROP_TREE]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_TEXT_AREA,
+		properties[PROP_TEXT_AREA]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_SEARCH_STRING,
+		properties[PROP_SEARCH_STRING]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_TOTAL_SIZE,
+		properties[PROP_TOTAL_SIZE]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_LIST_BAR,
+		properties[PROP_LIST_BAR]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_SEARCH_BAR,
+		properties[PROP_SEARCH_BAR]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_SEARCH_CANCEL,
+		properties[PROP_SEARCH_CANCEL]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_LIST_CANCEL,
+		properties[PROP_LIST_CANCEL]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_READ_CANCEL,
+		properties[PROP_READ_CANCEL]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_VIEWER_TYPE,
+		properties[PROP_VIEWER_TYPE]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_NEED_LOG_SIZE,
+		properties[PROP_NEED_LOG_SIZE]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_VIEWER_TITLE,
+		properties[PROP_VIEWER_TITLE]);
+
+	g_type_class_add_private(gobject_class, sizeof(FinchLogViewerPrivate));
+}
+
+static void
+finch_log_viewer_init(FinchLogViewer *lv)
+{
+}
+
 /****************************************************************************
  * GNT LOG SUBSYSTEM *******************************************************
  ****************************************************************************/
@@ -1034,6 +1606,15 @@ finch_log_init(void)
 {
 	void *handle = finch_log_get_handle();
 
+	G_LOCK(log_viewers);
+	// Is the ht stuff leaking?
+	log_viewers = g_hash_table_new_full(log_viewer_hash, log_viewer_equal, NULL, g_object_unref);
+	G_UNLOCK(log_viewers);
+
+	G_LOCK(syslog_viewer);
+	syslog_viewer = NULL;
+	G_UNLOCK(syslog_viewer);
+
 	purple_signal_register(handle, "log-displaying",
 		purple_marshal_VOID__POINTER_POINTER,
 		NULL, 2,
@@ -1045,4 +1626,18 @@ finch_log_uninit(void)
 finch_log_uninit(void)
 {
 	purple_signals_unregister_by_instance(finch_log_get_handle());
+
+	G_LOCK(log_viewers);
+	if (log_viewers != NULL) {
+		g_hash_table_destroy(log_viewers);
+		log_viewers = NULL;
+	}
+	G_UNLOCK(log_viewers);
+
+	G_LOCK(syslog_viewer);
+	if (syslog_viewer != NULL) {
+		g_object_unref(syslog_viewer);
+		syslog_viewer = NULL;
+	}
+	G_UNLOCK(syslog_viewer);
 }
============================================================
--- finch/gntlog.h	8e28b625b4642455c76a3e114852718779abcf67
+++ finch/gntlog.h	70db9cdb8cb3a641f176bbfc3d5f517b3e889422
@@ -26,12 +26,25 @@
 #ifndef _FINCHLOG_H_
 #define _FINCHLOG_H_
 
+#include <glib-object.h>
+
 #include "log.h"
 #include "account.h"
-#include "gntwidget.h"
+#include "gntwindow.h"
 
+G_BEGIN_DECLS
+
+#define FINCH_TYPE_LOG_VIEWER          (finch_log_viewer_get_type())
+#define FINCH_LOG_VIEWER(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), FINCH_TYPE_LOG_VIEWER, FinchLogViewer))
+#define FINCH_LOG_VIEWER_CLASS(k)      (G_TYPE_CHECK_CLASS_CAST((k), FINCH_TYPE_LOG_VIEWER, FinchLogViewerClass))
+#define FINCH_IS_LOG_VIEWER(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), FINCH_TYPE_LOG_VIEWER))
+#define FINCH_IS_LOG_VIEWER_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE((k), FINCH_TYPE_LOG_VIEWER))
+#define FINCH_LOG_VIEWER_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS((o), FINCH_TYPE_LOG_VIEWER, FinchLogViewerClass))
+
 /** @copydoc _FinchLogViewer */
 typedef struct _FinchLogViewer FinchLogViewer;
+/** @copydoc _PidginLogViewerClass */
+typedef struct _FinchLogViewerClass FinchLogViewerClass;
 
 /********************************************************
  * DATA STRUCTURES **************************************
@@ -41,19 +54,61 @@ struct _FinchLogViewer {
  * A GNT Log Viewer.  You can look at logs with it.
  */
 struct _FinchLogViewer {
-	GList              *logs;    /**< The list of logs viewed in this viewer */
+	GntWindow parent_instance;
+};
 
-	GntWidget          *window;  /**< The viewer's window */
-	GntWidget          *tree;    /**< The tree representing said treestore */
-	GntWidget          *text;    /**< The text to display said logs */
-	GntWidget          *entry;   /**< The search entry, in which search terms
-	                               *  are entered */
-	GntWidget          *label;   /**< The label widget with the title */
-	gchar              *search;  /**< The string currently being searched for */
+struct _FinchLogViewerClass {
+	GntWindowClass parent_class;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
 };
 
-G_BEGIN_DECLS
 
+//
+GList *finch_log_viewer_get_logs(FinchLogViewer *lv);
+//
+GntWidget *finch_log_viewer_get_tree(FinchLogViewer *lv);
+//
+GntWidget *finch_log_viewer_get_text_area(FinchLogViewer *lv);
+//
+G_CONST_RETURN gchar *finch_log_viewer_get_search_string(FinchLogViewer *lv);
+//
+gsize finch_log_viewer_get_total_size(FinchLogViewer *lv);
+//
+GntWidget *finch_log_viewer_get_list_bar(FinchLogViewer *lv);
+//
+GntWidget *finch_log_viewer_get_search_bar(FinchLogViewer *lv);
+//
+GCancellable *finch_log_viewer_get_search_cancel(FinchLogViewer *lv);
+//
+GCancellable *finch_log_viewer_get_list_cancel(FinchLogViewer *lv);
+//
+GCancellable *finch_log_viewer_get_read_cancel(FinchLogViewer *lv);
+//
+PurpleLogChatType finch_log_viewer_get_viewer_type(FinchLogViewer *lv);
+//
+gboolean finch_log_viewer_get_need_log_size(FinchLogViewer *lv);
+
+//
+void finch_log_viewer_add_logs(FinchLogViewer *lv, GList *logs);
+//
+void finch_log_viewer_set_logs(FinchLogViewer *lv, GList *logs);
+//
+void finch_log_viewer_set_search_string(FinchLogViewer *lv, const gchar *string);
+//
+void finch_log_viewer_set_total_size(FinchLogViewer *lv, gsize total);
+//
+void finch_log_viewer_set_search_cancel(FinchLogViewer *lv, GCancellable *cancellable);
+//
+void finch_log_viewer_set_list_cancel(FinchLogViewer *lv, GCancellable *cancellable);
+//
+void finch_log_viewer_set_read_cancel(FinchLogViewer *lv, GCancellable *cancellable);
+
+
+
 /**************************************************************************/
 /** @name Log Viewer Creators                                             */
 /**************************************************************************/
@@ -107,4 +162,6 @@ void finch_log_uninit(void);
 
 /*@}*/
 
+G_END_DECLS
+
 #endif


More information about the Commits mailing list