changeset 32581:24c8a98a6acc

webkit: Scroll to end when appending html. Most of the code was taken from imhtml.
author masca@cpw.pidgin.im
date Sat, 06 Feb 2010 22:18:05 +0000
parents 23b16f51e15a
children b48718a7e3ff
files pidgin/gtkconv.c pidgin/gtkwebview.c pidgin/gtkwebview.h
diffstat 3 files changed, 85 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin/gtkconv.c	Sat Feb 06 22:08:41 2010 +0000
+++ b/pidgin/gtkconv.c	Sat Feb 06 22:18:05 2010 +0000
@@ -4915,6 +4915,8 @@
         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (webview_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
 	gtkconv->webview = gtk_webview_new ();
+	gtk_webview_set_vadjustment(GTK_WEBVIEW(gtkconv->webview),
+			gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(webview_sw)));
 	gtk_container_add (GTK_CONTAINER (webview_sw), gtkconv->webview);
 	
 	gtk_widget_set_size_request(gtkconv->webview, -1, 0);
--- a/pidgin/gtkwebview.c	Sat Feb 06 22:08:41 2010 +0000
+++ b/pidgin/gtkwebview.c	Sat Feb 06 22:18:05 2010 +0000
@@ -48,6 +48,9 @@
 	/* JS execute queue */
 	GQueue *js_queue;
 	gboolean is_loading;
+	GtkAdjustment *vadj;
+	guint scroll_src;
+	GTimer *scroll_time;
 };
 
 GtkWidget* gtk_webview_new (void)
@@ -290,6 +293,10 @@
 	return g_string_free (str, FALSE);
 }
 
+void gtk_webview_set_vadjustment(GtkWebView *webview, GtkAdjustment *vadj)
+{
+	webview->priv->vadj = vadj;
+}
 
 /* this is a "hack", my plan is to eventually handle this 
  * correctly using a signals and a plugin: the plugin will have
@@ -304,6 +311,7 @@
 	printf ("script: %s\n", script);
 	webkit_web_view_execute_script (WEBKIT_WEB_VIEW (view), script);
 	view->priv->empty = FALSE;
+	gtk_webview_scroll_to_end(view, TRUE);
 	g_free (script);
 	g_free (escaped);
 }
@@ -313,6 +321,65 @@
 	return view->priv->empty;
 }
 
+#define MAX_SCROLL_TIME 0.4 /* seconds */
+#define SCROLL_DELAY 33 /* milliseconds */
+
+/*
+ * Smoothly scroll a WebView.
+ *
+ * @return TRUE if the window needs to be scrolled further, FALSE if we're at the bottom.
+ */
+static gboolean smooth_scroll_cb(gpointer data)
+{
+	struct GtkWebViewPriv *priv = data;
+	GtkAdjustment *adj = priv->vadj;
+	gdouble max_val = adj->upper - adj->page_size;
+	gdouble scroll_val = gtk_adjustment_get_value(adj) + ((max_val - gtk_adjustment_get_value(adj)) / 3);
+
+	g_return_val_if_fail(priv->scroll_time != NULL, FALSE);
+
+	if (g_timer_elapsed(priv->scroll_time, NULL) > MAX_SCROLL_TIME || scroll_val >= max_val) {
+		/* time's up. jump to the end and kill the timer */
+		gtk_adjustment_set_value(adj, max_val);
+		g_timer_destroy(priv->scroll_time);
+		priv->scroll_time = NULL;
+		g_source_remove(priv->scroll_src);
+		priv->scroll_src = 0;
+		return FALSE;
+	}
+
+	/* scroll by 1/3rd the remaining distance */
+	gtk_adjustment_set_value(adj, scroll_val);
+	return TRUE;
+}
+
+static gboolean scroll_idle_cb(gpointer data)
+{
+	struct GtkWebViewPriv *priv = data;
+	GtkAdjustment *adj = priv->vadj;
+	if(adj) {
+		gtk_adjustment_set_value(adj, adj->upper - adj->page_size);
+	}
+	priv->scroll_src = 0;
+	return FALSE;
+}
+
+void gtk_webview_scroll_to_end(GtkWebView *webview, gboolean smooth)
+{
+	struct GtkWebViewPriv *priv = webview->priv;
+	if (priv->scroll_time)
+		g_timer_destroy(priv->scroll_time);
+	if (priv->scroll_src)
+		g_source_remove(priv->scroll_src);
+	if(smooth) {
+		priv->scroll_time = g_timer_new();
+		priv->scroll_src = g_timeout_add_full(G_PRIORITY_LOW, SCROLL_DELAY, smooth_scroll_cb, priv, NULL);
+	} else {
+		priv->scroll_time = NULL;
+		priv->scroll_src = g_idle_add_full(G_PRIORITY_LOW, scroll_idle_cb, priv, NULL);
+	}
+}
+
 GType gtk_webview_get_type (void)
 {
 	static GType mview_type = 0;
--- a/pidgin/gtkwebview.h	Sat Feb 06 22:08:41 2010 +0000
+++ b/pidgin/gtkwebview.h	Sat Feb 06 22:18:05 2010 +0000
@@ -73,6 +73,14 @@
 GtkWidget* gtk_webview_new (void);
 
 /**
+ * Set the vertical adjustment for the GtkWebView.
+ *
+ * @param webview  The GtkWebView.
+ * @param vadj     The GtkAdjustment that control the webview.
+ */
+void gtk_webview_set_vadjustment(GtkWebView *webview, GtkAdjustment *vadj);
+
+/**
  * A very basic routine to append html, which can be considered
  * equivalent to a "document.write" using JavaScript.
  *
@@ -124,4 +132,12 @@
  */
 char* gtk_webview_quote_js_string (const char* str);
 
+/**
+ * Scrolls the Webview to the end of its contents.
+ *
+ * @param webview The GtkWebView.
+ * @param smoth   A boolean indicating if smooth scrolling should be used.
+ */
+void gtk_webview_scroll_to_end(GtkWebView *webview, gboolean smooth);
+
 #endif /* _PIDGIN_WEBVIEW_H_ */