]> Pileus Git - ~andy/gtk/commitdiff
demonstrate automatic scrolling
authorMatthias Clasen <matthiasc@src.gnome.org>
Sat, 26 Aug 2006 01:17:17 +0000 (01:17 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Sat, 26 Aug 2006 01:17:17 +0000 (01:17 +0000)
ChangeLog
demos/gtk-demo/Makefile.am
demos/gtk-demo/textscroll.c [new file with mode: 0644]
docs/reference/ChangeLog
docs/reference/gtk/question_index.sgml

index 9c8ca14d9e1578237539d6f667de0c150c3b6721..1a9572515060c7512766a4b690e44937385458fe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2006-08-25  Matthias Clasen  <mclasen@redhat.com>
 
+       * demos/gtk-demo/Makefile.am:
+       * demos/gtk-demo/textscroll.c: Add an example of automatic
+       scrolling, thanks to Yevgen Muntyan.  (#351206)
+       
        * gtk/gtkmodules.c (find_module): Use local binding when
        loading modules.  (#351868)
 
index e1adb57b631cd1e542ab9f9342bcb3bd68c8f6fb..f043ee0f4eabaedd1d2c8d15e301edcd9a30b8c9 100644 (file)
@@ -31,6 +31,7 @@ demos =                                               \
        sizegroup.c                             \
        stock_browser.c                         \
        textview.c                              \
+       textscroll.c                            \
        tree_store.c                            \
        ui_manager.c
 
diff --git a/demos/gtk-demo/textscroll.c b/demos/gtk-demo/textscroll.c
new file mode 100644 (file)
index 0000000..0633221
--- /dev/null
@@ -0,0 +1,202 @@
+/* Text Widget/Automatic scrolling
+ *
+ * This example demonstrates how to use the gravity of 
+ * GtkTextMarks to keep a text view scrolled to the bottom
+ * while appending text.
+ */
+
+#include <gtk/gtk.h>
+#include "demo-common.h"
+
+/* Scroll to the end of the buffer.
+ */
+static gboolean
+scroll_to_end (GtkTextView *textview)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter iter;
+  GtkTextMark *mark;
+  char *spaces;
+  static int count;
+
+  buffer = gtk_text_view_get_buffer (textview);
+  
+  /* Get "end" mark. It's located at the end of buffer because 
+   * of right gravity
+   */
+  mark = gtk_text_buffer_get_mark (buffer, "end");
+  gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+
+  /* and insert some text at its position, the iter will be 
+   * revalidated after insertion to point to the end of inserted text
+   */
+  spaces = g_strnfill (count++, ' ');
+  gtk_text_buffer_insert (buffer, &iter, "\n", -1);
+  gtk_text_buffer_insert (buffer, &iter, spaces, -1);
+  gtk_text_buffer_insert (buffer, &iter,
+                          "Scroll to end scroll to end scroll "
+                          "to end scroll to end ",
+                          -1);
+  g_free (spaces);
+
+  /* Now scroll the end mark onscreen.
+   */
+  gtk_text_view_scroll_mark_onscreen (textview, mark);
+
+  /* Emulate typewriter behavior, shift to the left if we 
+   * are far enough to the right.
+   */
+  if (count > 150)
+    count = 0;
+
+  return TRUE;
+}
+
+/* Scroll to the bottom of the buffer.
+ */
+static gboolean
+scroll_to_bottom (GtkTextView *textview)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter iter;
+  GtkTextMark *mark;
+  char *spaces;
+  static int count;
+
+  buffer = gtk_text_view_get_buffer (textview);
+  
+  /* Get end iterator */
+  gtk_text_buffer_get_end_iter (buffer, &iter);
+
+  /* and insert some text at it, the iter will be revalidated
+   * after insertion to point to the end of inserted text
+   */
+  spaces = g_strnfill (count++, ' ');
+  gtk_text_buffer_insert (buffer, &iter, "\n", -1);
+  gtk_text_buffer_insert (buffer, &iter, spaces, -1);
+  gtk_text_buffer_insert (buffer, &iter,
+                          "Scroll to bottom scroll to bottom scroll "
+                          "to bottom scroll to bottom",
+                          -1);
+  g_free (spaces);
+
+  /* Move the iterator to the beginning of line, so we don't scroll 
+   * in horizontal direction 
+   */
+  gtk_text_iter_set_line_offset (&iter, 0);
+  
+  /* and place the mark at iter. the mark will stay there after we
+   * insert some text at the end because it has right gravity.
+   */
+  mark = gtk_text_buffer_get_mark (buffer, "scroll");
+  gtk_text_buffer_move_mark (buffer, mark, &iter);
+  
+  /* Scroll the mark onscreen.
+   */
+  gtk_text_view_scroll_mark_onscreen (textview, mark);
+
+  /* Shift text back if we got enough to the right.
+   */
+  if (count > 40)
+    count = 0;
+
+  return TRUE;
+}
+
+static guint
+setup_scroll (GtkTextView *textview,
+              gboolean     to_end)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter iter;
+  GtkTextMark *mark;
+
+  buffer = gtk_text_view_get_buffer (textview);
+  gtk_text_buffer_get_end_iter (buffer, &iter);
+
+  if (to_end)
+  {
+    /* If we want to scroll to the end, including horizontal scrolling,
+     * then we just create a mark with right gravity at the end of the 
+     * buffer. It will stay at the end unless explicitely moved with 
+     * gtk_text_buffer_move_mark.
+     */
+    gtk_text_buffer_create_mark (buffer, "end", &iter, FALSE);
+    
+    /* Add scrolling timeout. */
+    return g_timeout_add (50, (GSourceFunc) scroll_to_end, textview);
+  }
+  else
+  {
+    /* If we want to scroll to the bottom, but not scroll horizontally, 
+     * then an end mark won't do the job. Just create a mark so we can 
+     * use it with gtk_text_view_scroll_mark_onscreen, we'll position it
+     * explicitely when needed. Use left gravity so the mark stays where 
+     * we put it after inserting new text.
+     */
+    gtk_text_buffer_create_mark (buffer, "scroll", &iter, TRUE);
+    
+    /* Add scrolling timeout. */
+    return g_timeout_add (100, (GSourceFunc) scroll_to_bottom, textview);
+  }
+}
+
+static void
+remove_timeout (GtkWidget *window,
+                gpointer   timeout)
+{
+  g_source_remove (GPOINTER_TO_UINT (timeout));
+}
+
+static void
+create_text_view (GtkWidget *hbox,
+                  gboolean   to_end)
+{
+  GtkWidget *swindow;
+  GtkWidget *textview;
+  guint timeout;
+
+  swindow = gtk_scrolled_window_new (NULL, NULL);
+  gtk_box_pack_start_defaults (GTK_BOX (hbox), swindow);
+  textview = gtk_text_view_new ();
+  gtk_container_add (GTK_CONTAINER (swindow), textview);
+
+  timeout = setup_scroll (GTK_TEXT_VIEW (textview), to_end);
+
+  /* Remove the timeout in destroy handler, so we don't try to
+   * scroll destroyed widget. 
+   */
+  g_signal_connect (textview, "destroy",
+                    G_CALLBACK (remove_timeout),
+                    GUINT_TO_POINTER (timeout));
+}
+
+GtkWidget *
+do_textscroll (GtkWidget *do_widget)
+{
+  static GtkWidget *window = NULL;
+
+  if (!window)
+    {
+      GtkWidget *hbox;
+      GtkWidget *swindow;
+
+      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+      g_signal_connect (window, "destroy",
+                       G_CALLBACK (gtk_widget_destroyed), &window);
+      gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
+      
+      hbox = gtk_hbox_new (TRUE, 6);
+      gtk_container_add (GTK_CONTAINER (window), hbox);
+
+      create_text_view (hbox, TRUE);
+      create_text_view (hbox, FALSE);
+    }
+
+  if (!GTK_WIDGET_VISIBLE (window))
+      gtk_widget_show_all (window);
+  else
+      gtk_widget_destroy (window);
+
+  return window;
+}
index 045b49170e9e9f61d3b7ba3bdf98bb3fd31544cc..0a9adf60756ded0bb540efca5bfc88ac94d69d9f 100644 (file)
@@ -1,3 +1,8 @@
+2006-08-25  Matthias Clasen  <mclasen@redhat.com>
+
+       * gtk/question_index.sgml: Rewrite the answer for
+       automatic scrolling.
+
 2006-08-17  Matthias Clasen  <mclasen@redhat.com>
 
        * === Released 2.10.2 ===
index 441def5a5a6b368f228fa879250085c7b8aecab6..6c1f32fff34ad05d71b7af1c088363ba75fc92e8 100644 (file)
@@ -757,18 +757,21 @@ How do I make a text view scroll to the end of the buffer automatically ?
 
 <answer>
 <para>
-The "insert" <link linkend="GtkTextMark">mark</link> marks the insertion point
-where gtk_text_buffer_insert() inserts new text into the buffer. The text is inserted 
-<emphasis>before</emphasis> the "insert" mark, so that it generally stays 
-at the end of the buffer. If it gets explicitly moved to some other position, 
-e.g. when the user selects some text, use gtk_text_buffer_move_mark() to set it to 
-the desired location before inserting more text. The "insert" mark of a buffer can be 
-obtained with gtk_text_buffer_get_insert().
+A good way to keep a text buffer scrolled to the end is to place a
+<link linkend="GtkTextMark">mark</link> at the end of the buffer, and
+give it right gravity. The gravity has the effect that text inserted
+at the mark gets inserted <emphasis>before</emphasis>, keeping the mark
+at the end. 
 </para>
 
 <para> 
 To ensure that the end of the buffer remains visible, use
-gtk_text_view_scroll_to_mark() to scroll to the "insert" mark after inserting new text.
+gtk_text_view_scroll_to_mark() to scroll to the mark after
+inserting new text.
+</para>
+
+<para>
+The gtk-demo application contains an example of this technique. 
 </para>
 </answer>
 </qandaentry>