# HG changeset patch
# Node ID f844ad62e763
# Parent  b19ffc40278d
diff --git a/pidgin/meson.build b/pidgin/meson.build
--- a/pidgin/meson.build
+++ b/pidgin/meson.build
@@ -31,6 +31,7 @@
 	'pidginaddbuddydialog.c',
 	'pidginaddchatdialog.c',
 	'pidginapplication.c',
+	'pidginautoadjustment.c',
 	'pidginavatar.c',
 	'pidginchanneljoindialog.c',
 	'pidgincolor.c',
@@ -99,6 +100,7 @@
 	'pidginaddbuddydialog.h',
 	'pidginaddchatdialog.h',
 	'pidginapplication.h',
+	'pidginautoadjustment.h',
 	'pidginavatar.h',
 	'pidginchanneljoindialog.h',
 	'pidgincolor.h',
diff --git a/pidgin/pidginautoadjustment.h b/pidgin/pidginautoadjustment.h
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginautoadjustment.h
@@ -0,0 +1,85 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION)
+# error "only <pidgin.h> may be included directly"
+#endif
+
+#ifndef PIDGIN_AUTO_ADJUSTMENT_H
+#define PIDGIN_AUTO_ADJUSTMENT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/**
+ * PidginAutoAdjustment:
+ *
+ * This is a simple subclass of [class@Gtk.Adjustment] that has helpers for
+ * keyboard navigation as well as the ability to automatically scroll to the
+ * max when new items are added if the widget was already scrolled all the
+ * way to the bottom.
+ *
+ * Since: 3.0.0
+ */
+
+#define PIDGIN_TYPE_AUTO_ADJUSTMENT (pidgin_auto_adjustment_get_type())
+G_DECLARE_FINAL_TYPE(PidginAutoAdjustment, pidgin_auto_adjustment, PIDGIN,
+                     AUTO_ADJUSTMENT, GtkAdjustment)
+
+/**
+ * pidgin_auto_adjustment_new:
+ *
+ * Creates a new #PidginAutoAdjustment.
+ *
+ * Returns: (transfer full): The new #PidginAutoAdjustment instance.
+ *
+ * Since: 3.0.0
+ */
+GtkAdjustment *pidgin_auto_adjustment_new(void);
+
+/**
+ * pidgin_auto_adjustment_decrement:
+ * @auto_scroller: The #PidginAutoAdjustment instance.
+ *
+ * Decrements the value of @auto_scroller by a page increment.
+ *
+ * Since: 3.0.0
+ */
+void pidgin_auto_adjustment_decrement(PidginAutoAdjustment *auto_scroller);
+
+/**
+ * pidgin_auto_adjustment_increment:
+ * @auto_scroller: The #PidginAutoAdjustment instance.
+ *
+ * Increments the value of @auto_scroller by a page increment.
+ *
+ * Since: 3.0.0
+ */
+void pidgin_auto_adjustment_increment(PidginAutoAdjustment *auto_scroller);
+
+G_END_DECLS
+
+#endif /* PIDGIN_AUTO_ADJUSTMENT_H */
diff --git a/pidgin/pidginautoadjustment.c b/pidgin/pidginautoadjustment.c
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginautoadjustment.c
@@ -0,0 +1,133 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+
+#include "pidginautoadjustment.h"
+
+struct _PidginAutoAdjustment {
+	GtkAdjustment parent;
+
+	gboolean auto_scroll;
+};
+
+G_DEFINE_TYPE(PidginAutoAdjustment, pidgin_auto_adjustment,
+              GTK_TYPE_ADJUSTMENT)
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static gboolean
+pidgin_auto_adjustment_scroll(gpointer data) {
+	GtkAdjustment *adjustment = data;
+	gdouble upper = 0.0;
+	gdouble pagesize = 0.0;
+
+	upper = gtk_adjustment_get_upper(adjustment);
+	pagesize = gtk_adjustment_get_page_size(adjustment);
+
+	gtk_adjustment_set_value(adjustment, upper - pagesize);
+
+	return G_SOURCE_REMOVE;
+}
+
+static void
+pidgin_auto_adjustment_changed(GtkAdjustment *gtk_adjustment) {
+	PidginAutoAdjustment *adjustment = PIDGIN_AUTO_ADJUSTMENT(gtk_adjustment);
+
+	if(adjustment->auto_scroll) {
+		/* If we set the value here, we interrupt the updates to the other
+		 * values of the adjustment which breaks the adjustment.
+		 *
+		 * The specific behavior we've seen is that the upper property doesn't
+		 * get updated when we call set value here. Which means you can't even
+		 * scroll down anymore in a scrolled window because you're already at
+		 * the upper bound. However, if you scroll up, even if there's no where
+		 * to scroll, it will update the adjustment's properties and you can
+		 * then scroll down.
+		 *
+		 * By using a timeout to set the value during the next main loop
+		 * iteration we avoid this problem.
+		 */
+		g_timeout_add(0, pidgin_auto_adjustment_scroll, adjustment);
+	}
+}
+
+static void
+pidgin_auto_adjustment_value_changed(GtkAdjustment *gtk_adjustment) {
+	PidginAutoAdjustment *adjustment = PIDGIN_AUTO_ADJUSTMENT(gtk_adjustment);
+	gdouble current = 0.0;
+	gdouble upper = 0.0;
+	gdouble pagesize = 0.0;
+
+	current = gtk_adjustment_get_value(gtk_adjustment);
+	upper = gtk_adjustment_get_upper(gtk_adjustment);
+	pagesize = gtk_adjustment_get_page_size(gtk_adjustment);
+
+	adjustment->auto_scroll = (current + pagesize >= upper);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+pidgin_auto_adjustment_init(PidginAutoAdjustment *adjustment) {
+	adjustment->auto_scroll = TRUE;
+}
+
+static void
+pidgin_auto_adjustment_class_init(PidginAutoAdjustmentClass *klass) {
+	GtkAdjustmentClass *adjustment_class = GTK_ADJUSTMENT_CLASS(klass);
+
+	adjustment_class->changed = pidgin_auto_adjustment_changed;
+	adjustment_class->value_changed = pidgin_auto_adjustment_value_changed;
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+GtkAdjustment *
+pidgin_auto_adjustment_new(void) {
+	return g_object_new(PIDGIN_TYPE_AUTO_ADJUSTMENT, NULL);
+}
+
+void
+pidgin_auto_adjustment_decrement(PidginAutoAdjustment *adjustment) {
+	gdouble value = 0.0;
+
+	g_return_if_fail(PIDGIN_IS_AUTO_ADJUSTMENT(adjustment));
+
+	value = gtk_adjustment_get_value(GTK_ADJUSTMENT(adjustment));
+	value -= gtk_adjustment_get_page_increment(GTK_ADJUSTMENT(adjustment));
+	gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustment), value);
+}
+
+void
+pidgin_auto_adjustment_increment(PidginAutoAdjustment *adjustment) {
+	gdouble value = 0.0;
+
+	g_return_if_fail(PIDGIN_IS_AUTO_ADJUSTMENT(adjustment));
+
+	value = gtk_adjustment_get_value(GTK_ADJUSTMENT(adjustment));
+	value += gtk_adjustment_get_page_increment(GTK_ADJUSTMENT(adjustment));
+	gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustment), value);
+}
diff --git a/pidgin/resources/Conversations/conversation.ui b/pidgin/resources/Conversations/conversation.ui
--- a/pidgin/resources/Conversations/conversation.ui
+++ b/pidgin/resources/Conversations/conversation.ui
@@ -54,7 +54,7 @@
           <object class="GtkScrolledWindow">
             <property name="hexpand">1</property>
             <property name="vadjustment">
-              <object class="TalkatuAutoScroller"/>
+              <object class="PidginAutoAdjustment"/>
             </property>
             <property name="vexpand">1</property>
             <child>
