cpw.nader.asynclogging-3: eeec478b: Cleaned up a bunch of strange errors tha...

morshed.nader at gmail.com morshed.nader at gmail.com
Thu Jan 13 21:05:53 EST 2011


----------------------------------------------------------------------
Revision: eeec478be4753b8f5435b34f3b90a398792b82b4
Parent:   c198de7361c9db900c80ebe8fd7d0a53875e4ea8
Author:   morshed.nader at gmail.com
Date:     01/13/11 20:58:51
Branch:   im.pidgin.cpw.nader.asynclogging-3
URL: http://d.pidgin.im/viewmtn/revision/info/eeec478be4753b8f5435b34f3b90a398792b82b4

Changelog: 

Cleaned up a bunch of strange errors that were popping up, both in the logging part of libpurple and in gtklog.c
Made errors not be logged by the purple_logs_* when the code is G_IO_ERROR_NOT_SUPPORTED
Finished GObjectifying PidginLogViewer
Made listing logs for oldlog not return an error if the log file is missing (That just means the user has no logs)
Oldlog's total_size was also altered to return 0 for the size when the log file does not exist

Changes against parent c198de7361c9db900c80ebe8fd7d0a53875e4ea8

  patched  libpurple/log.c
  patched  libpurple/oldlog.c
  patched  pidgin/gtklog.c
  patched  pidgin/gtklog.h

-------------- next part --------------
============================================================
--- libpurple/log.c	e3600bffa8ead07dc65de588d879d09d731fd779
+++ libpurple/log.c	b3fd3e5e0c141c99f992caa5c31ced90275ea6a4
@@ -1217,7 +1217,7 @@ total_size_thread(GSimpleAsyncResult *si
 		GList *logs = purple_logs_get_logs(chat_type, name, account, cancellable, &error);
 		gssize total;
 
-		if (logs == NULL) {
+		if (logs == NULL && error != NULL) {
 			g_simple_async_result_set_from_error(simple, error);
 			return;
 		}
@@ -1423,7 +1423,7 @@ purple_log_get_activity_score(PurpleLogC
 
 			logs = purple_logs_get_logs(chat_type, name, account, cancellable, error);
 
-			if (logs == NULL)
+			if (logs == NULL && error != NULL)
 				return -1;
 
 			for ( ; logs != NULL; logs = g_list_delete_link(logs, logs)) {
@@ -1907,16 +1907,19 @@ purple_logs_get_logs(PurpleLogChatType c
 
 	for (i = 0; i < array->len; i++) {
 		PurpleLog *log;
+		GError *err = NULL;
 		GList *list;
 		GType log_type = g_array_index(array, GType, i);
 
 		log = g_object_new(log_type, NULL);
-		list = purple_log_get_logs(log, chat_type, name, account, cancellable, error);
+		list = purple_log_get_logs(log, chat_type, name, account, cancellable, &err);
 
-		if (list == NULL) {
+		if (list == NULL && err != NULL) {
+			g_propagate_error(error, err);
 			g_list_foreach(logs, (GFunc) g_object_unref, NULL);
 			g_list_free(logs);
 
+			g_clear_error(&err);
 			g_object_unref(log);
 
 			return NULL;
@@ -1943,7 +1946,7 @@ get_logs_thread(GSimpleAsyncResult *simp
 
 	logs = purple_log_get_logs(log, chat_type, name, account, cancellable, &error);
 
-	if (logs == NULL)
+	if (logs == NULL && error != NULL)
 		g_simple_async_result_set_from_error(simple, error);
 	else
 		g_simple_async_result_set_op_res_gpointer(simple, logs, NULL);
@@ -2369,7 +2372,7 @@ list_syslog_thread(GSimpleAsyncResult *s
 
 	list = purple_log_get_system_logs(PURPLE_LOG(object), account, cancellable, &error);
 
-	if (list == NULL)
+	if (list == NULL && error != NULL)
 		g_simple_async_result_set_from_error(simple, error);
 	else
 		g_simple_async_result_set_op_res_gpointer(simple, list, NULL);
@@ -2903,13 +2906,15 @@ log_list_cb(GObject *object, GAsyncResul
 
 	list = purple_log_get_logs_finish(log, res, &error);
 
-	if (list == NULL && error != NULL)
-		purple_debug_error("log", "Error listing %s logs: %s\n",
-			PURPLE_LOG_GET_CLASS(log)->logger_name, error->message);
+	if (list == NULL) {
+		if (error != NULL && error->code != G_IO_ERROR_NOT_SUPPORTED)
+			purple_debug_error("log", "Error listing %s logs: %s\n",
+				PURPLE_LOG_GET_CLASS(log)->logger_name, error->message);
+	} else
+		callback_data->logs = g_list_concat(callback_data->logs, list);
 
 	g_clear_error(&error);
 
-	callback_data->logs = g_list_concat(callback_data->logs, list);
 	callback_data->counter--;
 
 	if (callback_data->counter < 1) {
@@ -2943,13 +2948,15 @@ log_system_list_cb(GObject *object, GAsy
 
 	list = purple_log_get_system_logs_finish(log, res, &error);
 
-	if (list == NULL && error != NULL)
-		purple_debug_error("log", "Error listing %s system logs: %s\n",
-			PURPLE_LOG_GET_CLASS(log)->logger_name, error->message);
+	if (list == NULL) {
+		if (error != NULL && error->code != G_IO_ERROR_NOT_SUPPORTED)
+			purple_debug_error("log", "Error listing %s system logs: %s\n",
+				PURPLE_LOG_GET_CLASS(log)->logger_name, error->message);
+	} else
+		callback_data->logs = g_list_concat(callback_data->logs, list);
 
 	g_clear_error(&error);
 
-	callback_data->logs = g_list_concat(callback_data->logs, list);
 	callback_data->counter--;
 
 	if (callback_data->counter < 1) {
@@ -3018,10 +3025,11 @@ log_hash_cb(GObject *object, GAsyncResul
 
 	one_set = purple_log_get_log_sets_finish(log, res, &error);
 
-	if (one_set == NULL)
-		purple_debug_error("log", "Error getting log sets for %s: %s\n",
-			PURPLE_LOG_GET_CLASS(log)->logger_name, error->message);
-	else {
+	if (one_set == NULL) {
+		if (error->code != G_IO_ERROR_NOT_SUPPORTED)
+			purple_debug_error("log", "Error getting log sets for %s: %s\n",
+				PURPLE_LOG_GET_CLASS(log)->logger_name, error->message);
+	} else {
 		g_hash_table_foreach_steal(one_set, steal_log_sets, callback_data->sets);
 		g_hash_table_destroy(one_set);
 	}
============================================================
--- pidgin/gtklog.c	c27818744b39843433c8e9d8a18f75d2639873b6
+++ pidgin/gtklog.c	184ba64ea1e66f242ed9c6f311ec035d2cf06705
@@ -58,6 +58,21 @@ enum {
 
 enum {
 	PROP_0,
+	PROP_LOGS,
+	PROP_TREE_STORE,
+	PROP_TREE_VIEW,
+	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_SELECTED,
+	PROP_VIEWER_TYPE,
+	PROP_ICON,
+	PROP_NEED_LOG_SIZE,
 	LAST_PROP
 };
 
@@ -82,7 +97,9 @@ struct _PidginLogViewerPrivate {
 	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  chat_type;      /**< The log type of the window */
+	PurpleLogChatType  viewer_type;    /**< The log type of the window */
+	GtkWidget          *icon;
+	gboolean           need_log_size;
 #if GTK_CHECK_VERSION(2, 20, 0)
 	GtkWidget          *spinner;       /**< A spinner to indicate a read is in progress */
 #endif
@@ -167,7 +184,7 @@ pidgin_log_data_free(_pidgin_log_data *d
 pidgin_log_data_free(_pidgin_log_data *data)
 {
 	if (data->destroy_handler_id > 0)
-		g_signal_handler_disconnect(GTK_WINDOW(data->log_viewer),
+		g_signal_handler_disconnect(data->log_viewer,
 			data->destroy_handler_id);
 
 	g_free(data);
@@ -180,69 +197,6 @@ pidgin_window_destroy_cb(_pidgin_log_dat
 	data->is_window_open = FALSE;
 }
 
-void
-pidgin_log_viewer_set_read_cancel(PidginLogViewer *lv, GCancellable *cancel)
-{
-	PidginLogViewerPrivate *priv;
-
-	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
-	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
-
-	priv = PIDGIN_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;
-}
-
-void
-pidgin_log_viewer_set_search_cancel(PidginLogViewer *lv, GCancellable *cancel)
-{
-	PidginLogViewerPrivate *priv;
-
-	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
-	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
-
-	priv = PIDGIN_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;
-}
-
-void
-pidgin_log_viewer_set_list_cancel(PidginLogViewer *lv, GCancellable *cancel)
-{
-	PidginLogViewerPrivate *priv;
-
-	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
-	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
-
-	priv = PIDGIN_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;
-}
-
 static guint
 log_viewer_hash(gconstpointer data)
 {
@@ -282,7 +236,7 @@ select_first_log(PidginLogViewer *lv)
 select_first_log(PidginLogViewer *lv)
 {
 	PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
-	GtkTreeModel *model = GTK_TREE_MODEL(priv->treestore);
+	GtkTreeModel *model = GTK_TREE_MODEL(pidgin_log_viewer_get_tree_store(lv));
 	GtkTreeIter iter, it;
 	GtkTreePath *path;
 
@@ -367,16 +321,16 @@ search_cb(GtkWidget *button, PidginLogVi
 search_cb(GtkWidget *button, PidginLogViewer *lv)
 {
 	_pidgin_log_data *pidgin_log_data;
+	PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
 	GtkIMHtml *imhtml = GTK_IMHTML(pidgin_log_viewer_get_text_area(lv));
 	GtkTreeStore *treestore = pidgin_log_viewer_get_tree_store(lv);
-	GtkWidget *bar, *entry;
+	GtkWidget *bar;
 	GCancellable *cancel;
 	GList *logs;
 	const gchar *search_term, *old_search;
 	guint length;
 
-	entry = pidgin_log_viewer_get_entry(lv);
-	search_term = gtk_entry_get_text(GTK_ENTRY(entry));
+	search_term = gtk_entry_get_text(GTK_ENTRY(priv->entry));
 
 	if (!(*search_term)) {
 		/* reset the tree */
@@ -418,7 +372,7 @@ search_cb(GtkWidget *button, PidginLogVi
 	pidgin_log_data->log_viewer = lv;
 	pidgin_log_data->count = pidgin_log_data->total = length;
 
-	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(GTK_WINDOW(lv),
+	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(pidgin_window_destroy_cb), pidgin_log_data);
 
 	bar = pidgin_log_viewer_get_search_bar(lv);
@@ -478,6 +432,8 @@ destroy_cb(PidginLogViewer *lv, gint res
 		syslog_viewer = NULL;
 		G_UNLOCK(syslog_viewer);
 	}
+
+	gtk_widget_destroy(GTK_WIDGET(lv));
 }
 
 static void
@@ -493,7 +449,7 @@ delete_log_cleanup_cb(log_delete_callbac
 delete_log_cleanup_cb(log_delete_callback_data *data)
 {
 	if (data->destroy_handler_id > 0)
-		g_signal_handler_disconnect(GTK_WINDOW(data->log_data->log_viewer),
+		g_signal_handler_disconnect(data->log_data->log_viewer,
 			data->destroy_handler_id);
 
 	pidgin_log_data_free(data->log_data);
@@ -840,7 +796,7 @@ log_select_cb(GtkTreeSelection *sel, Pid
 	chat_type = purple_log_get_chat_type(log);
 
 	if (chat_type != PURPLE_LOG_SYSTEM) {
-		GtkWidget *label = pidgin_log_viewer_get_label(lv);
+		PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
 		const gchar *log_name = purple_log_get_name(log);
 		gchar *title;
 
@@ -851,7 +807,7 @@ log_select_cb(GtkTreeSelection *sel, Pid
 			title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"),
 				log_name, log_get_date(log));
 
-		gtk_label_set_markup(GTK_LABEL(label), title);
+		gtk_label_set_markup(GTK_LABEL(priv->label), title);
 		g_free(title);
 	}
 
@@ -1031,21 +987,6 @@ insert_log_viewer_log(PidginLogViewer *l
 	gtk_tree_store_set(store, &insertion, 0, log_get_date(log), 1, log, -1);
 }
 
-void
-pidgin_log_viewer_add_logs(PidginLogViewer *lv, GList *logs)
-{
-	PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
-	GList *list;
-
-	logs = g_list_sort(logs, purple_log_compare);
-
-	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);
-}
-
 static void
 pidgin_log_done_cb(_pidgin_log_data *pidgin_log_data)
 {
@@ -1131,21 +1072,11 @@ pidgin_log_size_cb(GObject *object, GAsy
 				error->message);
 	} else if (pidgin_log_data->is_window_open) {
 		PidginLogViewer *lv = pidgin_log_data->log_viewer;
-		gchar *sz_txt, *text;
 		gsize total;
 
 		total = pidgin_log_viewer_get_total_size(lv);
 		total += log_size;
 		pidgin_log_viewer_set_total_size(lv, total);
-
-		// sz_txt = purple_str_size_to_units(total);
-		// text = g_strdup_printf("<span weight='bold'>%s</span> %s",
-			// _("Total log size:"), sz_txt);
-
-		// gtk_label_set_markup(GTK_LABEL(lv_ex->lv->size_label), text);
-
-		// g_free(sz_txt);
-		// g_free(text);
 	}
 
 	g_clear_error(&error);
@@ -1267,7 +1198,7 @@ pidgin_log_show(PurpleLogChatType chat_t
 	if (prpl_icon != NULL)
 		g_object_unref(prpl_icon);
 
-	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(GTK_WINDOW(lv),
+	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(pidgin_window_destroy_cb), pidgin_log_data);
 
 	cancel = g_cancellable_new();
@@ -1347,7 +1278,7 @@ pidgin_log_show_contact(PurpleContact *c
 	g_free(title);
 	gtk_widget_show(GTK_WIDGET(lv));
 
-	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(GTK_WINDOW(lv),
+	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;
@@ -1390,12 +1321,12 @@ pidgin_syslog_show(void)
 
 	pidgin_log_data = g_new0(_pidgin_log_data, 1);
 	pidgin_log_data->is_window_open = TRUE;
-	
+
 	lv = pidgin_log_data->log_viewer = pidgin_log_viewer_new(NULL,
 		_("System Log"), NULL, FALSE);
 	gtk_widget_show(GTK_WIDGET(lv));
 
-	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(GTK_WINDOW(lv),
+	pidgin_log_data->destroy_handler_id = g_signal_connect_swapped(lv,
 		"destroy", G_CALLBACK(pidgin_window_destroy_cb), pidgin_log_data);
 
 	cancel = g_cancellable_new();
@@ -1421,64 +1352,343 @@ pidgin_syslog_show(void)
 	G_UNLOCK(syslog_viewer);
 }
 
-static void
-pidgin_log_viewer_constructed(GObject *object)
+GList *
+pidgin_log_viewer_get_logs(PidginLogViewer *lv)
 {
-	PidginLogViewer *lv;
-	PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
-	GtkCellRenderer *rend;
-	GtkTreeViewColumn *col;
-	GtkTreeSelection *sel;
-	GtkDialog *dialog = GTK_DIALOG(lv);
-	GtkWindow *window = GTK_WINDOW(lv);
-	GtkWidget *icon, *title_box, *pane, *sw, *frame;
-	GtkWidget *find_button, *content_area, *vbox, *hbox;
-	gchar *text;
-	gboolean need_log_size;
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
 
-	/* Window ***********/
-	gtk_dialog_add_buttons(dialog, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
-#ifdef G_OS_WIN32
-	/* Steal the "HELP" response and use it to trigger browsing to the logs folder */
-	gtk_dialog_add_button(dialog, _("_Browse logs folder"), GTK_RESPONSE_HELP);
-#endif
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->logs;
+}
 
-	gtk_container_set_border_width (GTK_CONTAINER(lv), PIDGIN_HIG_BOX_SPACE);
-	gtk_dialog_set_has_separator(dialog, FALSE);
-	content_area = gtk_dialog_get_content_area(dialog);
-	gtk_box_set_spacing(GTK_BOX(content_area), 0);
-	gtk_window_set_role(window, "log_viewer");
+GtkTreeStore *
+pidgin_log_viewer_get_tree_store(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
 
-	/* Icon *************/
-	icon = pidgin_log_viewer_get_icon(lv);
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->treestore;
+}
 
-	if (icon != NULL) {
-		title_box = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-		gtk_container_set_border_width(GTK_CONTAINER(title_box), PIDGIN_HIG_BOX_SPACE);
-		gtk_box_pack_start(GTK_BOX(content_area), title_box, FALSE, FALSE, 0);
-		gtk_box_pack_start(GTK_BOX(title_box), icon, FALSE, FALSE, 0);
-	} else
-		title_box = content_area;
+GtkWidget *
+pidgin_log_viewer_get_tree_view(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
 
-	/* Label ************/
-	priv->label = gtk_label_new(NULL);
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->treeview;
+}
 
-	text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>",
-		gtk_window_get_title(window));
+GtkWidget *
+pidgin_log_viewer_get_text_area(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
 
-	gtk_label_set_markup(GTK_LABEL(priv->label), text);
-	gtk_misc_set_alignment(GTK_MISC(priv->label), 0, 0);
-	gtk_box_pack_start(GTK_BOX(title_box), priv->label, FALSE, FALSE, 0);
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->imhtml;
+}
+
+G_CONST_RETURN gchar *
+pidgin_log_viewer_get_search_string(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->search;
+}
+
+gsize
+pidgin_log_viewer_get_total_size(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), 0);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->size;
+}
+
+GtkWidget *
+pidgin_log_viewer_get_list_bar(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->list_bar;
+}
+
+GtkWidget *
+pidgin_log_viewer_get_search_bar(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->search_bar;
+}
+
+GCancellable *
+pidgin_log_viewer_get_search_cancel(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->search_cancel;
+}
+
+GCancellable *
+pidgin_log_viewer_get_list_cancel(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->list_cancel;
+}
+
+GCancellable *
+pidgin_log_viewer_get_read_cancel(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->read_cancel;
+}
+
+gboolean
+pidgin_log_viewer_is_selected(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), FALSE);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->selected;
+}
+
+PurpleLogChatType
+pidgin_log_viewer_get_viewer_type(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), PURPLE_LOG_SYSTEM);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->viewer_type;
+}
+
+GtkWidget *
+pidgin_log_viewer_get_icon(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), NULL);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->icon;
+}
+
+gboolean
+pidgin_log_viewer_get_need_log_size(PidginLogViewer *lv)
+{
+	g_return_val_if_fail(PIDGIN_IS_LOG_VIEWER(lv), FALSE);
+
+	return PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->need_log_size;
+}
+
+void
+pidgin_log_viewer_add_logs(PidginLogViewer *lv, GList *logs)
+{
+	PidginLogViewerPrivate *priv;
+	GList *list;
+
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+
+	priv = PIDGIN_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
+pidgin_log_viewer_set_logs(PidginLogViewer *lv, GList *logs)
+{
+	PidginLogViewerPrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+
+	priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
+
+	g_list_foreach(priv->logs, (GFunc) g_object_unref, NULL);
+	g_list_free(priv->logs);
+
+	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);
+
+	g_object_notify(G_OBJECT(lv), "logs");
+}
+
+void
+pidgin_log_viewer_set_search_string(PidginLogViewer *lv, const gchar *search)
+{
+	PidginLogViewerPrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+
+	priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
+
+	g_free(priv->search);
+	priv->search = g_strdup(search);
+
+	g_object_notify(G_OBJECT(lv), "search-string");
+}
+
+void
+pidgin_log_viewer_set_total_size(PidginLogViewer *lv, gsize total)
+{
+	PidginLogViewerPrivate *priv;
+	gchar *sz_txt, *text;
+
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+	g_return_if_fail(pidgin_log_viewer_get_need_log_size(lv));
+
+	priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
+	priv->size = total;
+
+	sz_txt = purple_str_size_to_units(total);
+	text = g_strdup_printf("<span weight='bold'>%s</span> %s",
+		_("Total log size:"), sz_txt);
+
+	gtk_label_set_markup(GTK_LABEL(priv->size_label), text);
+
+	g_free(sz_txt);
 	g_free(text);
 
-	/* Pane *************/
+	g_object_notify(G_OBJECT(lv), "total-size");
+}
+
+void
+pidgin_log_viewer_set_search_cancel(PidginLogViewer *lv, GCancellable *cancel)
+{
+	PidginLogViewerPrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
+
+	priv = PIDGIN_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
+pidgin_log_viewer_set_list_cancel(PidginLogViewer *lv, GCancellable *cancel)
+{
+	PidginLogViewerPrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
+
+	priv = PIDGIN_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
+pidgin_log_viewer_set_read_cancel(PidginLogViewer *lv, GCancellable *cancel)
+{
+	PidginLogViewerPrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+	g_return_if_fail(cancel == NULL || G_IS_CANCELLABLE(cancel));
+
+	priv = PIDGIN_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");
+}
+
+void
+pidgin_log_viewer_set_selected(PidginLogViewer *lv, gboolean selected)
+{
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+
+	PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->selected = selected ? TRUE : FALSE;
+
+	g_object_notify(G_OBJECT(lv), "selected");
+}
+
+static void
+pidgin_log_viewer_set_viewer_type(PidginLogViewer *lv, PurpleLogChatType viewer_type)
+{
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+
+	PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->viewer_type = viewer_type;
+
+	g_object_notify(G_OBJECT(lv), "viewer-type");
+}
+
+static void
+pidgin_log_viewer_set_icon(PidginLogViewer *lv, GtkWidget *icon)
+{
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+	g_return_if_fail(icon == NULL || GTK_IS_IMAGE(icon));
+
+	PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->icon = icon;
+
+	g_object_notify(G_OBJECT(lv), "icon");
+}
+
+static void
+pidgin_log_viewer_set_need_log_size(PidginLogViewer *lv, gboolean need_log_size)
+{
+	g_return_if_fail(PIDGIN_IS_LOG_VIEWER(lv));
+
+	PIDGIN_LOG_VIEWER_GET_PRIVATE(lv)->need_log_size = need_log_size ? TRUE : FALSE;
+
+	g_object_notify(G_OBJECT(lv), "need-log-size");
+}
+
+static void
+pidgin_log_viewer_constructed(GObject *object)
+{
+	PidginLogViewer *lv = PIDGIN_LOG_VIEWER(object);
+	PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
+	GtkCellRenderer *rend;
+	GtkDialog *dialog = GTK_DIALOG(lv);
+	GtkTreeViewColumn *col;
+	GtkTreeSelection *sel;
+	GtkWidget *content_area = gtk_dialog_get_content_area(dialog);
+	GtkWidget *pane, *sw, *frame;
+	GtkWidget *find_button, *vbox, *hbox;
+	gchar *text;
+	gboolean need_log_size;
+
+	/* Pane */
 	pane = gtk_hpaned_new();
 	gtk_container_set_border_width(GTK_CONTAINER(pane), PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_start(GTK_BOX(content_area), pane, TRUE, TRUE, 0);
+	gtk_box_pack_end(GTK_BOX(content_area), pane, TRUE, TRUE, 0);
 
-	/* List *************/
-	sw = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
+	/* List */
+	sw = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
 	gtk_paned_add1(GTK_PANED(pane), sw);
 
@@ -1486,40 +1696,36 @@ pidgin_log_viewer_constructed(GObject *o
 	priv->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(priv->treestore));
 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(priv->treeview), FALSE);
 	pidgin_set_accessible_label(priv->treeview, priv->label);
-	// g_object_unref(priv->treestore);
 
 	rend = gtk_cell_renderer_text_new();
-	col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW(priv->treeview), col);
-	gtk_container_add (GTK_CONTAINER (sw), priv->treeview);
+	col = gtk_tree_view_column_new_with_attributes("time", rend, "markup", 0, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview), col);
+	gtk_container_add(GTK_CONTAINER(sw), priv->treeview);
 
 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview));
 
-	g_signal_connect(sel, "changed", G_CALLBACK (log_select_cb), lv);
+	g_signal_connect(sel, "changed", G_CALLBACK(log_select_cb), lv);
 	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);
 
-	/* Log size ************/
+	/* Log size */
 	need_log_size = pidgin_log_viewer_get_need_log_size(lv);
 
 	if (need_log_size) {
-		priv->size_label = gtk_label_new(NULL);
-
 		text = g_strdup_printf("<span weight='bold'>%s</span> %s",
 			_("Total log size:"), _("calculating..."));
+
 		gtk_label_set_markup(GTK_LABEL(priv->size_label), text);
 		g_free(text);
+	} else
+		gtk_widget_destroy(priv->size_label);
 
-		gtk_misc_set_alignment(GTK_MISC(priv->size_label), 0, 0);
-		gtk_box_pack_end(GTK_BOX(content_area), priv->size_label, FALSE, FALSE, 0);
-	}
-
-	/* A fancy little box ************/
+	/* A fancy little box */
 	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 	gtk_paned_add2(GTK_PANED(pane), vbox);
 
-	/* Viewer ************/
+	/* Viewer */
 	frame = pidgin_create_imhtml(FALSE, &priv->imhtml, NULL, NULL);
 	gtk_widget_set_name(priv->imhtml, "pidgin_log_imhtml");
 	gtk_widget_set_size_request(priv->imhtml, 320, 200);
@@ -1532,7 +1738,7 @@ pidgin_log_viewer_constructed(GObject *o
 	gtk_box_pack_start(GTK_BOX(vbox), priv->spinner, TRUE, FALSE, 0);
 #endif
 
-	/* Search box **********/
+	/* Search box */
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
@@ -1545,7 +1751,7 @@ pidgin_log_viewer_constructed(GObject *o
 	g_signal_connect(priv->entry, "activate", G_CALLBACK(search_cb), lv);
 	g_signal_connect(find_button, "clicked", G_CALLBACK(search_cb), lv);
 
-	/* Progress bars **********/
+	/* Progress bars */
 	priv->list_bar = gtk_progress_bar_new();
 	priv->search_bar = gtk_progress_bar_new();
 
@@ -1567,22 +1773,132 @@ pidgin_log_viewer_finalize(GObject *obje
 pidgin_log_viewer_finalize(GObject *object)
 {
 	PidginLogViewer *lv = PIDGIN_LOG_VIEWER(object);
-	// PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
+	PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
 
 	purple_request_close_with_handle(lv);
 
-	// Move these into a finalize function
-	pidgin_log_viewer_clear_logs(lv);
-	pidgin_log_viewer_set_search_string(lv, NULL);
-	pidgin_log_viewer_set_read_cancel(lv, NULL);
-	pidgin_log_viewer_set_search_cancel(lv, NULL);
-	pidgin_log_viewer_set_list_cancel(lv, NULL);
-	g_object_unref(lv);
+	g_list_foreach(priv->logs, (GFunc) g_object_unref, NULL);
+	g_list_free(priv->logs);
+	g_free(priv->search);
 
-	// gtk_widget_destroy(w);
+	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_unref(priv->treestore);
 }
 
 static void
+pidgin_log_viewer_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	PidginLogViewer *lv = PIDGIN_LOG_VIEWER(object);
+
+	switch (prop_id) {
+	case PROP_LOGS:
+		pidgin_log_viewer_set_logs(lv, g_value_get_pointer(value));
+		break;
+	case PROP_SEARCH_STRING:
+		pidgin_log_viewer_set_search_string(lv, g_value_get_string(value));
+		break;
+	case PROP_TOTAL_SIZE:
+		pidgin_log_viewer_set_total_size(lv, g_value_get_long(value));
+		break;
+	case PROP_SEARCH_CANCEL:
+		pidgin_log_viewer_set_search_cancel(lv, g_value_get_object(value));
+		break;
+	case PROP_LIST_CANCEL:
+		pidgin_log_viewer_set_list_cancel(lv, g_value_get_object(value));
+		break;
+	case PROP_READ_CANCEL:
+		pidgin_log_viewer_set_read_cancel(lv, g_value_get_object(value));
+		break;
+	case PROP_SELECTED:
+		pidgin_log_viewer_set_selected(lv, g_value_get_boolean(value));
+		break;
+	case PROP_VIEWER_TYPE:
+		pidgin_log_viewer_set_viewer_type(lv, g_value_get_enum(value));
+		break;
+	case PROP_ICON:
+		pidgin_log_viewer_set_icon(lv, g_value_get_object(value));
+		break;
+	case PROP_NEED_LOG_SIZE:
+		pidgin_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
+pidgin_log_viewer_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	PidginLogViewer *lv = PIDGIN_LOG_VIEWER(object);
+
+	switch (prop_id) {
+	case PROP_LOGS:
+		g_value_set_pointer(value, pidgin_log_viewer_get_logs(lv));
+		break;
+	case PROP_TREE_STORE:
+		g_value_set_object(value, pidgin_log_viewer_get_tree_store(lv));
+		break;
+	case PROP_TREE_VIEW:
+		g_value_set_object(value, pidgin_log_viewer_get_tree_view(lv));
+		break;
+	case PROP_TEXT_AREA:
+		g_value_set_object(value, pidgin_log_viewer_get_text_area(lv));
+		break;
+	case PROP_SEARCH_STRING:
+		g_value_set_string(value, pidgin_log_viewer_get_search_string(lv));
+		break;
+	case PROP_TOTAL_SIZE:
+		g_value_set_long(value, pidgin_log_viewer_get_total_size(lv));
+		break;
+	case PROP_LIST_BAR:
+		g_value_set_object(value, pidgin_log_viewer_get_list_bar(lv));
+		break;
+	case PROP_SEARCH_BAR:
+		g_value_set_object(value, pidgin_log_viewer_get_search_bar(lv));
+		break;
+	case PROP_SEARCH_CANCEL:
+		g_value_set_object(value, pidgin_log_viewer_get_search_cancel(lv));
+		break;
+	case PROP_LIST_CANCEL:
+		g_value_set_object(value, pidgin_log_viewer_get_list_cancel(lv));
+		break;
+	case PROP_READ_CANCEL:
+		g_value_set_object(value, pidgin_log_viewer_get_read_cancel(lv));
+		break;
+	case PROP_SELECTED:
+		g_value_set_boolean(value, pidgin_log_viewer_is_selected(lv));
+		break;
+	case PROP_VIEWER_TYPE:
+		g_value_set_enum(value, pidgin_log_viewer_get_viewer_type(lv));
+		break;
+	case PROP_ICON:
+		g_value_set_object(value, pidgin_log_viewer_get_icon(lv));
+		break;
+	case PROP_NEED_LOG_SIZE:
+		g_value_set_boolean(value, pidgin_log_viewer_get_need_log_size(lv));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
 pidgin_log_viewer_class_init(PidginLogViewerClass *class)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
@@ -1592,20 +1908,174 @@ pidgin_log_viewer_class_init(PidginLogVi
 	gobject_class->constructed = pidgin_log_viewer_constructed;
 	gobject_class->finalize = pidgin_log_viewer_finalize;
 
-	// properties[PROP_LOG_CHAT_TYPE] =
-		// g_param_spec_enum("chat-type",
-			// "Chat Type",
-			// "The chat type of the log",
-			// PURPLE_TYPE_LOG_CHAT_TYPE,
-			// PURPLE_LOG_SYSTEM,
-			// G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+	properties[PROP_LOGS] =
+		g_param_spec_pointer("logs",
+			"Log",
+			"A list of the logs being displayed by the viewer",
+			G_PARAM_READWRITE);
 
-	// Icon : Constructor only
+	properties[PROP_TREE_STORE] =
+		g_param_spec_object("tree-store",
+			"Tree Store",
+			"The storage device containing the logs displayed by the tree view",
+			GTK_TYPE_TREE_STORE,
+			G_PARAM_READABLE);
 
-	// g_object_class_install_property(gobject_class,
-		// PROP_LOG_CHAT_TYPE,
-		// properties[PROP_LOG_CHAT_TYPE]);
+	properties[PROP_TREE_VIEW] =
+		g_param_spec_object("tree-view",
+			"Tree View",
+			"The GtkTreeView that displays the list of logs to the users",
+			GTK_TYPE_TREE_VIEW,
+			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",
+			GTK_TYPE_WIDGET,
+			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",
+			GTK_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",
+			GTK_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_SELECTED] =
+		g_param_spec_boolean("selected",
+			"Selected",
+			"Indicates whether or not the user has selected"
+			"a log from the tree view since it was last cleared",
+			FALSE,
+			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_ICON] =
+		g_param_spec_object("icon",
+			"Icon",
+			"The User's Icon, if available",
+			GTK_TYPE_IMAGE,
+			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);
+
+	g_object_class_install_property(gobject_class,
+		PROP_LOGS,
+		properties[PROP_LOGS]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_TREE_STORE,
+		properties[PROP_TREE_STORE]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_TREE_VIEW,
+		properties[PROP_TREE_VIEW]);
+
+	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_SELECTED,
+		properties[PROP_SELECTED]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_VIEWER_TYPE,
+		properties[PROP_VIEWER_TYPE]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_ICON,
+		properties[PROP_ICON]);
+
+	g_object_class_install_property(gobject_class,
+		PROP_NEED_LOG_SIZE,
+		properties[PROP_NEED_LOG_SIZE]);
+
 	g_type_class_add_private(gobject_class, sizeof(PidginLogViewerPrivate));
 }
 
@@ -1613,13 +2083,60 @@ pidgin_log_viewer_init(PidginLogViewer *
 pidgin_log_viewer_init(PidginLogViewer *lv)
 {
 	PidginLogViewerPrivate *priv = PIDGIN_LOG_VIEWER_GET_PRIVATE(lv);
+	GtkDialog *dialog = GTK_DIALOG(lv);
+	GtkWindow *window = GTK_WINDOW(lv);
+	GtkWidget *icon, *title_box, *content_area;
+	gchar *text;
 
+	/* Window */
+	gtk_dialog_add_buttons(dialog, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+#ifdef G_OS_WIN32
+	/* Steal the "HELP" response and use it to trigger browsing to the logs folder */
+	gtk_dialog_add_button(dialog, _("_Browse logs folder"), GTK_RESPONSE_HELP);
+#endif
+
+	gtk_container_set_border_width (GTK_CONTAINER(lv), PIDGIN_HIG_BOX_SPACE);
+	gtk_dialog_set_has_separator(dialog, FALSE);
+	content_area = gtk_dialog_get_content_area(dialog);
+	gtk_box_set_spacing(GTK_BOX(content_area), 0);
+	gtk_window_set_role(window, "log_viewer");
+
+	/* Icon */
+	icon = pidgin_log_viewer_get_icon(lv);
+
+	if (icon != NULL) {
+		title_box = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+		gtk_container_set_border_width(GTK_CONTAINER(title_box), PIDGIN_HIG_BOX_SPACE);
+		gtk_box_pack_start(GTK_BOX(content_area), title_box, FALSE, FALSE, 0);
+		gtk_box_pack_start(GTK_BOX(title_box), icon, FALSE, FALSE, 0);
+	} else
+		title_box = content_area;
+
+	/* Label */
+	priv->label = gtk_label_new(NULL);
+
+	text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>",
+		gtk_window_get_title(window));
+
+	gtk_label_set_markup(GTK_LABEL(priv->label), text);
+	gtk_misc_set_alignment(GTK_MISC(priv->label), 0, 0);
+	gtk_box_pack_start(GTK_BOX(title_box), priv->label, FALSE, FALSE, 0);
+	g_free(text);
+
+	/* Log size */
+	priv->size_label = gtk_label_new(NULL);
+	gtk_misc_set_alignment(GTK_MISC(priv->size_label), 0, 0);
+	gtk_box_pack_end(GTK_BOX(content_area), priv->size_label, FALSE, FALSE, 0);
+
+
 	priv->logs = NULL;
+	priv->search = NULL;
 	priv->size = 0;
 	priv->read_cancel = NULL;
 	priv->search_cancel = NULL;
 	priv->list_cancel = NULL;
 	priv->selected = FALSE;
+	priv->icon = NULL;
 }
 
 /****************************************************************************
@@ -1644,6 +2161,10 @@ pidgin_log_init(void)
 	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,
@@ -1656,13 +2177,17 @@ pidgin_log_uninit(void)
 {
 	purple_signals_unregister_by_instance(pidgin_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);
 }
============================================================
--- pidgin/gtklog.h	8a817ee7c6fc35869d32dbf88ee7887ad33fcc1e
+++ pidgin/gtklog.h	acb614acb351d7fb5e6a8519c27923272fe92c52
@@ -78,15 +78,9 @@ GtkWidget *pidgin_log_viewer_get_text_ar
 //
 GtkWidget *pidgin_log_viewer_get_text_area(PidginLogViewer *lv);
 //
-GtkWidget *pidgin_log_viewer_get_entry(PidginLogViewer *lv);
-//
 G_CONST_RETURN gchar *pidgin_log_viewer_get_search_string(PidginLogViewer *lv);
-// Better name?
-GtkWidget *pidgin_log_viewer_get_label(PidginLogViewer *lv);
-// Better name?
-GtkWidget *pidgin_log_viewer_get_size_label(PidginLogViewer *lv);
 //
-gssize pidgin_log_viewer_get_total_size(PidginLogViewer *lv);
+gsize pidgin_log_viewer_get_total_size(PidginLogViewer *lv);
 //
 GtkWidget *pidgin_log_viewer_get_list_bar(PidginLogViewer *lv);
 //
@@ -101,15 +95,19 @@ PurpleLogChatType pidgin_log_viewer_get_
 gboolean pidgin_log_viewer_is_selected(PidginLogViewer *lv);
 //
 PurpleLogChatType pidgin_log_viewer_get_viewer_type(PidginLogViewer *lv);
-
 //
-void pidgin_log_viewer_clear_logs(PidginLogViewer *lv);
+GtkWidget *pidgin_log_viewer_get_icon(PidginLogViewer *lv);
 //
+gboolean pidgin_log_viewer_get_need_log_size(PidginLogViewer *lv);
+
+//
 void pidgin_log_viewer_add_logs(PidginLogViewer *lv, GList *logs);
 //
+void pidgin_log_viewer_set_logs(PidginLogViewer *lv, GList *logs);
+//
 void pidgin_log_viewer_set_search_string(PidginLogViewer *lv, const gchar *string);
 //
-void pidgin_log_viewer_set_total_size(PidginLogViewer *lv, gssize total);
+void pidgin_log_viewer_set_total_size(PidginLogViewer *lv, gsize total);
 //
 void pidgin_log_viewer_set_search_cancel(PidginLogViewer *lv, GCancellable *cancellable);
 //
@@ -120,6 +118,7 @@ void pidgin_log_viewer_set_selected(Pidg
 void pidgin_log_viewer_set_selected(PidginLogViewer *lv, gboolean selected);
 
 
+
 /**************************************************************************/
 /** @name Log Viewer Creators                                             */
 /**************************************************************************/
============================================================
--- libpurple/oldlog.c	5b3cef684d4c6174e28f23aca6b373e02425c8e2
+++ libpurple/oldlog.c	95078f43d7fb03295654348d8d64be8184467b6f
@@ -95,9 +95,13 @@ purple_old_log_list(PurpleLog *log, Purp
 
 	file = g_file_new_for_path(pathstr);
 	info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
-		G_FILE_QUERY_INFO_NONE, cancellable, error);
+		G_FILE_QUERY_INFO_NONE, cancellable, &err);
 
 	if (info == NULL) {
+		if (err->code != G_IO_ERROR_NOT_FOUND)
+			g_propagate_error(error, err);
+
+		g_clear_error(&err);
 		g_object_unref(file);
 		g_free(pathstr);
 
@@ -352,6 +356,7 @@ purple_old_log_total_size(PurpleLog *log
 purple_old_log_total_size(PurpleLog *log, PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error)
 {
 	/* Yes, only one file. */
+	GError *err = NULL;
 	GFile *file;
 	GFileInfo *info;
 	gchar *logfile, *pathstr;
@@ -366,12 +371,19 @@ purple_old_log_total_size(PurpleLog *log
 	g_free(pathstr);
 
 	info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
-		G_FILE_QUERY_INFO_NONE, cancellable, error);
+		G_FILE_QUERY_INFO_NONE, cancellable, &err);
 
 	if (info == NULL) {
 		g_object_unref(file);
 
-		return -1;
+		if (err->code != G_IO_ERROR_NOT_FOUND) {
+			g_propagate_error(error, err);
+			g_clear_error(&err);
+			return -1;
+		} else {
+			g_clear_error(&err);
+			return 0;
+		}
 	}
 
 	file_size = g_file_info_get_attribute_uint64(info,


More information about the Commits mailing list