Convert log viewer to Glade.

Fri, 24 May 2019 03:21:48 -0400

author
Elliott Sales de Andrade <qulogic@pidgin.im>
date
Fri, 24 May 2019 03:21:48 -0400
changeset 39628
52c772b30a1c
parent 39627
d5e89e5381cd
child 39630
d5d92880d39e

Convert log viewer to Glade.

Currently, the search is hooked up, but Talkatu does not support it, so
the trigger to show the search box is _not_ connected yet. I don't know
if it works entirely yet.

pidgin/pidginlog.c file | annotate | diff | comparison | revisions
pidgin/resources/Log/log-viewer.ui file | annotate | diff | comparison | revisions
pidgin/resources/pidgin.gresource.xml file | annotate | diff | comparison | revisions
--- a/pidgin/pidginlog.c	Wed Jun 05 02:25:52 2019 -0400
+++ b/pidgin/pidginlog.c	Fri May 24 03:21:48 2019 -0400
@@ -21,6 +21,8 @@
 #include "internal.h"
 #include "pidgin.h"
 
+#include <talkatu.h>
+
 #include "account.h"
 #include "debug.h"
 #include "log.h"
@@ -31,7 +33,6 @@
 #include "pidginstock.h"
 #include "gtkblist.h"
 #include "gtkutils.h"
-#include "gtkwebview.h"
 #include "pidginlog.h"
 
 #include "gtk3compat.h"
@@ -39,13 +40,17 @@
 #define PIDGIN_TYPE_LOG_VIEWER pidgin_log_viewer_get_type()
 /**
  * PidginLogViewer:
- * @logs:      The list of logs viewed in this viewer
- * @treestore: The treestore containing said logs
- * @treeview:  The treeview representing said treestore
- * @log_view:  The webkit web view to display said logs
- * @entry:     The search entry, in which search terms are entered
- * @search:    The string currently being searched for
- * @label:     The label at the top of the log viewer
+ * @logs:          The list of logs viewed in this viewer
+ * @browse_button: The button for opening a log folder externally
+ * @treestore:     The treestore containing said logs
+ * @treeview:      The treeview representing said treestore
+ * @log_view:      The talkatu view to display said logs
+ * @log_buffer:    The talkatu buffer to hold said logs
+ * @title_box:     The box containing the title (and optional icon)
+ * @label:         The label at the top of the log viewer
+ * @size_label:    The label to show the size of the logs
+ * @entry:         The search entry, in which search terms are entered
+ * @search:        The string currently being searched for
  *
  * A Pidgin Log Viewer.  You can look at logs with it.
  */
@@ -56,13 +61,20 @@
 
 	GList *logs;
 
+	GtkWidget *browse_button;
+
 	GtkTreeStore     *treestore;
 	GtkWidget        *treeview;
 	GtkWidget        *log_view;
-	GtkWidget        *entry;
+	TalkatuHtmlBuffer *log_buffer;
+
+	GtkWidget *title_box;
+	GtkLabel         *label;
 
-	char             *search;
-	GtkLabel         *label;
+	GtkWidget *size_label;
+
+	GtkWidget *entry;
+	char *search;
 };
 
 G_DEFINE_TYPE(PidginLogViewer, pidgin_log_viewer, GTK_TYPE_DIALOG)
@@ -149,26 +161,31 @@
 	return ret;
 }
 
-static void search_cb(GtkWidget *button, PidginLogViewer *lv)
+static void
+entry_stop_search_cb(GtkWidget *entry, PidginLogViewer *lv)
+{
+	/* reset the tree */
+	gtk_tree_store_clear(lv->treestore);
+	populate_log_tree(lv);
+	g_clear_pointer(&lv->search, g_free);
+#if 0
+	webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(lv->log_view));
+#endif
+	select_first_log(lv);
+}
+
+static void
+entry_search_changed_cb(GtkWidget *button, PidginLogViewer *lv)
 {
 	const char *search_term = gtk_entry_get_text(GTK_ENTRY(lv->entry));
 	GList *logs;
 
-	if (!(*search_term)) {
-		/* reset the tree */
-		gtk_tree_store_clear(lv->treestore);
-		populate_log_tree(lv);
-		g_free(lv->search);
-		lv->search = NULL;
-		webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(lv->log_view));
-		select_first_log(lv);
-		return;
-	}
-
 	if (lv->search != NULL && purple_strequal(lv->search, search_term))
 	{
+#if 0
 		/* Searching for the same term acts as "Find Next" */
 		webkit_web_view_search_text(WEBKIT_WEB_VIEW(lv->log_view), lv->search, FALSE, TRUE, TRUE);
+#endif
 		return;
 	}
 
@@ -178,7 +195,7 @@
 	lv->search = g_strdup(search_term);
 
 	gtk_tree_store_clear(lv->treestore);
-	webkit_web_view_open(WEBKIT_WEB_VIEW(lv->log_view), "about:blank"); /* clear the view */
+	talkatu_buffer_clear(TALKATU_BUFFER(lv->log_buffer));
 
 	for (logs = lv->logs; logs != NULL; logs = logs->next) {
 		char *read = purple_log_read((PurpleLog*)logs->data, NULL);
@@ -444,6 +461,7 @@
 	}
 }
 
+#if 0 /* FIXME: Add support in Talkatu for highlighting search terms. */
 static gboolean search_find_cb(gpointer data)
 {
 	PidginLogViewer *viewer = data;
@@ -452,6 +470,7 @@
 	webkit_web_view_search_text(WEBKIT_WEB_VIEW(viewer->log_view), viewer->search, FALSE, TRUE, TRUE);
 	return FALSE;
 }
+#endif
 
 static void log_select_cb(GtkTreeSelection *sel, PidginLogViewer *viewer) {
 	GtkTreeIter iter;
@@ -476,13 +495,14 @@
 
 	if (log->type != PURPLE_LOG_SYSTEM) {
 		gchar *log_date = log_get_date(log);
-		char *title;
-		if (log->type == PURPLE_LOG_CHAT)
-			title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation in %s on %s</span>"),
-									log->name, log_date);
-		else
-			title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"),
-									log->name, log_date);
+		gchar *title;
+		if (log->type == PURPLE_LOG_CHAT) {
+			title = g_strdup_printf(_("Conversation in %s on %s"),
+			                        log->name, log_date);
+		} else {
+			title = g_strdup_printf(_("Conversation with %s on %s"),
+			                        log->name, log_date);
+		}
 
 		gtk_label_set_markup(viewer->label, title);
 		g_free(log_date);
@@ -491,7 +511,7 @@
 
 	read = purple_log_read(log, &flags);
 
-	webkit_web_view_open(WEBKIT_WEB_VIEW(viewer->log_view), "about:blank");
+	talkatu_buffer_clear(TALKATU_BUFFER(viewer->log_buffer));
 
 	purple_signal_emit(pidgin_log_get_handle(), "log-displaying", viewer, log);
 	
@@ -503,12 +523,14 @@
 		read = newRead;
 	}
 
-	webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(viewer->log_view), read, "");
+	talkatu_markup_set_html(TALKATU_BUFFER(viewer->log_buffer), read, -1);
 	g_free(read);
 
 	if (viewer->search != NULL) {
+#if 0 /* FIXME: Add support in Talkatu for highlighting search terms. */
 		webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(viewer->log_view));
 		g_idle_add(search_find_cb, viewer);
+#endif
 	}
 
 	pidgin_clear_cursor(GTK_WIDGET(viewer));
@@ -564,17 +586,6 @@
 						const char *title, GtkWidget *icon, int log_size)
 {
 	PidginLogViewer *lv;
-	GtkWidget *title_box;
-	char *text;
-	GtkWidget *pane;
-	GtkCellRenderer *rend;
-	GtkTreeViewColumn *col;
-	GtkTreeSelection *sel;
-	GtkWidget *vbox;
-	GtkWidget *frame;
-	GtkWidget *hbox;
-	GtkWidget *find_button;
-	GtkWidget *size_label;
 
 	if (logs == NULL)
 	{
@@ -606,115 +617,45 @@
 	/* Window ***********/
 	lv = g_object_new(PIDGIN_TYPE_LOG_VIEWER, NULL);
 	gtk_window_set_title(GTK_WINDOW(lv), title);
-	gtk_dialog_add_buttons(GTK_DIALOG(lv), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
 
 	lv->logs = logs;
 
 	if (ht != NULL)
 		g_hash_table_insert(log_viewers, ht, lv);
 
-#ifdef _WIN32
-	/* Steal the "HELP" response and use it to trigger browsing to the logs folder */
-	gtk_dialog_add_button(GTK_DIALOG(lv), _("_Browse logs folder"), GTK_RESPONSE_HELP);
+#ifndef _WIN32
+	gtk_widget_hide(lv->browse_button);
 #endif
-	gtk_container_set_border_width(GTK_CONTAINER(lv), PIDGIN_HIG_BOX_SPACE);
-	gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))), 0);
-	g_signal_connect(G_OBJECT(lv), "response",
-					 G_CALLBACK(destroy_cb), ht);
-	gtk_window_set_role(GTK_WINDOW(lv), "log_viewer");
+
+	g_signal_connect(G_OBJECT(lv), "response", G_CALLBACK(destroy_cb), ht);
 
 	/* Icon *************/
 	if (icon != NULL) {
-		title_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PIDGIN_HIG_BOX_SPACE);
-		gtk_container_set_border_width(GTK_CONTAINER(title_box), PIDGIN_HIG_BOX_SPACE);
-		gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))),
-		                   title_box, FALSE, FALSE, 0);
-
-		gtk_box_pack_start(GTK_BOX(title_box), icon, FALSE, FALSE, 0);
-	} else
-		title_box = gtk_dialog_get_content_area(GTK_DIALOG(lv));
+		gtk_box_pack_start(GTK_BOX(lv->title_box), icon, FALSE, FALSE,
+		                   0);
+	}
 
 	/* Label ************/
-	lv->label = GTK_LABEL(gtk_label_new(NULL));
-
-	text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>", title);
-
-	gtk_label_set_markup(lv->label, text);
-	gtk_label_set_xalign(GTK_LABEL(lv->label), 0);
-	gtk_label_set_yalign(GTK_LABEL(lv->label), 0);
-	gtk_box_pack_start(GTK_BOX(title_box), GTK_WIDGET(lv->label), FALSE, FALSE, 0);
-	g_free(text);
-
-	/* Pane *************/
-	pane = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
-	gtk_container_set_border_width(GTK_CONTAINER(pane), PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))),
-	                   pane, TRUE, TRUE, 0);
+	gtk_label_set_markup(lv->label, title);
 
 	/* List *************/
-	lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
-	lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore));
-	g_object_unref(G_OBJECT(lv->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(lv->treeview), col);
-	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE);
-	gtk_paned_add1(GTK_PANED(pane),
-		pidgin_make_scrollable(lv->treeview, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1));
-
 	populate_log_tree(lv);
 
-	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (lv->treeview));
-	g_signal_connect (G_OBJECT (sel), "changed",
-			G_CALLBACK (log_select_cb),
-			lv);
-	g_signal_connect (G_OBJECT(lv->treeview), "row-activated",
-			G_CALLBACK(log_row_activated_cb),
-			lv);
-	pidgin_set_accessible_label(lv->treeview, lv->label);
-
-	g_signal_connect(lv->treeview, "button-press-event", G_CALLBACK(log_button_press_cb), lv);
-	g_signal_connect(lv->treeview, "popup-menu", G_CALLBACK(log_popup_menu_cb), lv);
-
 	/* Log size ************/
 	if(log_size) {
 		char *sz_txt = purple_str_size_to_units(log_size);
-		text = g_strdup_printf("<span weight='bold'>%s</span> %s", _("Total log size:"), sz_txt);
-		size_label = gtk_label_new(NULL);
-		gtk_label_set_markup(GTK_LABEL(size_label), text);
-		/*		gtk_paned_add1(GTK_PANED(pane), size_label); */
-		gtk_label_set_xalign(GTK_LABEL(size_label), 0);
-		gtk_label_set_yalign(GTK_LABEL(size_label), 0);
-		gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))),
-		                 size_label, FALSE, FALSE, 0);
+		char *text = g_strdup_printf("<span weight='bold'>%s</span> %s",
+		                             _("Total log size:"), sz_txt);
+		gtk_label_set_markup(GTK_LABEL(lv->size_label), text);
 		g_free(sz_txt);
 		g_free(text);
+	} else {
+		gtk_widget_hide(lv->size_label);
 	}
 
-	/* A fancy little box ************/
-	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PIDGIN_HIG_BOX_SPACE);
-	gtk_paned_add2(GTK_PANED(pane), vbox);
-
-	/* Viewer ************/
-	frame = pidgin_create_webview(FALSE, &lv->log_view, NULL);
-	gtk_widget_set_name(lv->log_view, "pidgin_log_log_view");
-	gtk_widget_set_size_request(lv->log_view, 320, 200);
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-	gtk_widget_show(frame);
-
-	/* Search box **********/
-	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-	lv->entry = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(hbox), lv->entry, TRUE, TRUE, 0);
-	find_button = gtk_button_new_from_stock(GTK_STOCK_FIND);
-	gtk_box_pack_start(GTK_BOX(hbox), find_button, FALSE, FALSE, 0);
-	g_signal_connect(GTK_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv);
-	g_signal_connect(GTK_BUTTON(find_button), "clicked", G_CALLBACK(search_cb), lv);
-
 	select_first_log(lv);
 
-	gtk_widget_show_all(GTK_WIDGET(lv));
+	gtk_widget_show(GTK_WIDGET(lv));
 
 	return lv;
 }
@@ -725,11 +666,51 @@
 static void
 pidgin_log_viewer_class_init(PidginLogViewerClass *klass)
 {
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+	gtk_widget_class_set_template_from_resource(
+	        widget_class, "/im/pidgin/Pidgin/Log/log-viewer.ui");
+
+	gtk_widget_class_bind_template_child_internal(
+	        widget_class, PidginLogViewer, browse_button);
+
+	gtk_widget_class_bind_template_child_internal(
+	        widget_class, PidginLogViewer, title_box);
+	gtk_widget_class_bind_template_child_internal(widget_class,
+	                                              PidginLogViewer, label);
+
+	gtk_widget_class_bind_template_child_internal(
+	        widget_class, PidginLogViewer, treeview);
+	gtk_widget_class_bind_template_child_internal(
+	        widget_class, PidginLogViewer, treestore);
+	gtk_widget_class_bind_template_callback(widget_class, log_select_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        log_row_activated_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        log_button_press_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        log_popup_menu_cb);
+
+	gtk_widget_class_bind_template_child_internal(widget_class,
+	                                              PidginLogViewer, entry);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        entry_search_changed_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        entry_stop_search_cb);
+
+	gtk_widget_class_bind_template_child_internal(
+	        widget_class, PidginLogViewer, log_view);
+	gtk_widget_class_bind_template_child_internal(
+	        widget_class, PidginLogViewer, log_buffer);
+
+	gtk_widget_class_bind_template_child_internal(
+	        widget_class, PidginLogViewer, size_label);
 }
 
 static void
 pidgin_log_viewer_init(PidginLogViewer *self)
 {
+	gtk_widget_init_template(GTK_WIDGET(self));
 }
 
 /****************************************************************************
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/resources/Log/log-viewer.ui	Fri May 24 03:21:48 2019 -0400
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="Talkatu" version="0.0"/>
+  <requires lib="gtk+" version="3.10"/>
+  <object class="TalkatuHtmlBuffer" id="log_buffer"/>
+  <object class="GtkTreeStore" id="treestore">
+    <columns>
+      <!-- column-name markup -->
+      <column type="gchararray"/>
+      <!-- column-name log -->
+      <column type="gpointer"/>
+    </columns>
+  </object>
+  <template class="PidginLogViewer" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="role">log_viewer</property>
+    <property name="type_hint">dialog</property>
+    <child>
+      <placeholder/>
+    </child>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="can_focus">False</property>
+        <property name="margin_top">6</property>
+        <property name="margin_bottom">6</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="browse_button">
+                <property name="label" translatable="yes">_Browse logs folder</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="close_button">
+                <property name="label" translatable="yes">_Close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="title_box">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Conversations with buddy</property>
+                <property name="track_visited_links">False</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                  <attribute name="scale" value="1.2"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="PidginLogViewer"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkPaned">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">0</property>
+            <child>
+              <object class="GtkScrolledWindow">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">always</property>
+                <property name="shadow_type">in</property>
+                <child>
+                  <object class="GtkTreeView" id="treeview">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="model">treestore</property>
+                    <property name="headers_visible">False</property>
+                    <signal name="button-press-event" handler="log_button_press_cb" object="PidginLogViewer" swapped="no"/>
+                    <signal name="popup-menu" handler="log_popup_menu_cb" object="PidginLogViewer" swapped="no"/>
+                    <signal name="row-activated" handler="log_row_activated_cb" object="PidginLogViewer" swapped="no"/>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection">
+                        <signal name="changed" handler="log_select_cb" object="PidginLogViewer" swapped="no"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkTreeViewColumn" id="time">
+                        <child>
+                          <object class="GtkCellRendererText"/>
+                          <attributes>
+                            <attribute name="markup">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">False</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkSearchBar">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkSearchEntry" id="entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="primary_icon_name">edit-find-symbolic</property>
+                        <property name="primary_icon_activatable">False</property>
+                        <property name="primary_icon_sensitive">False</property>
+                        <signal name="search-changed" handler="entry_search_changed_cb" object="PidginLogViewer" swapped="no"/>
+                        <signal name="stop-search" handler="entry_stop_search_cb" object="PidginLogViewer" swapped="no"/>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow">
+                    <property name="width_request">320</property>
+                    <property name="height_request">200</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="TalkatuView" id="log_view">
+                        <property name="name">pidgin_log_view</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="hexpand_set">True</property>
+                        <property name="vexpand_set">True</property>
+                        <property name="editable">False</property>
+                        <property name="wrap_mode">word</property>
+                        <property name="buffer">log_buffer</property>
+                        <property name="send_binding"/>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="size_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">&lt;b&gt;Total log size:&lt;/b&gt; 123 KiB</property>
+            <property name="use_markup">True</property>
+            <property name="xalign">0</property>
+            <property name="yalign">0</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-11">browse_button</action-widget>
+      <action-widget response="-7">close_button</action-widget>
+    </action-widgets>
+    <accessibility>
+      <relation type="labelled-by" target="label"/>
+    </accessibility>
+  </template>
+</interface>
--- a/pidgin/resources/pidgin.gresource.xml	Wed Jun 05 02:25:52 2019 -0400
+++ b/pidgin/resources/pidgin.gresource.xml	Fri May 24 03:21:48 2019 -0400
@@ -9,6 +9,7 @@
     <file compressed="true">Debug/debug.ui</file>
     <file compressed="true">Debug/filter-popover.ui</file>
     <file compressed="true">Debug/plugininfo.ui</file>
+    <file compressed="true">Log/log-viewer.ui</file>
     <file compressed="true">Prefs/prefs.ui</file>
   </gresource>
 </gresources>

mercurial