Blame demos/gtk-demo/textscroll.c

Packit Service fb6fa5
/* Text Widget/Automatic scrolling
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This example demonstrates how to use the gravity of 
Packit Service fb6fa5
 * GtkTextMarks to keep a text view scrolled to the bottom
Packit Service fb6fa5
 * while appending text.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
#include <gtk/gtk.h>
Packit Service fb6fa5
#include "demo-common.h"
Packit Service fb6fa5
Packit Service fb6fa5
/* Scroll to the end of the buffer.
Packit Service fb6fa5
 */
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
scroll_to_end (GtkTextView *textview)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBuffer *buffer;
Packit Service fb6fa5
  GtkTextIter iter;
Packit Service fb6fa5
  GtkTextMark *mark;
Packit Service fb6fa5
  char *spaces;
Packit Service fb6fa5
  static int count;
Packit Service fb6fa5
Packit Service fb6fa5
  buffer = gtk_text_view_get_buffer (textview);
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* Get "end" mark. It's located at the end of buffer because 
Packit Service fb6fa5
   * of right gravity
Packit Service fb6fa5
   */
Packit Service fb6fa5
  mark = gtk_text_buffer_get_mark (buffer, "end");
Packit Service fb6fa5
  gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
Packit Service fb6fa5
Packit Service fb6fa5
  /* and insert some text at its position, the iter will be 
Packit Service fb6fa5
   * revalidated after insertion to point to the end of inserted text
Packit Service fb6fa5
   */
Packit Service fb6fa5
  spaces = g_strnfill (count++, ' ');
Packit Service fb6fa5
  gtk_text_buffer_insert (buffer, &iter, "\n", -1);
Packit Service fb6fa5
  gtk_text_buffer_insert (buffer, &iter, spaces, -1);
Packit Service fb6fa5
  gtk_text_buffer_insert (buffer, &iter,
Packit Service fb6fa5
                          "Scroll to end scroll to end scroll "
Packit Service fb6fa5
                          "to end scroll to end ",
Packit Service fb6fa5
                          -1);
Packit Service fb6fa5
  g_free (spaces);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Now scroll the end mark onscreen.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  gtk_text_view_scroll_mark_onscreen (textview, mark);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Emulate typewriter behavior, shift to the left if we 
Packit Service fb6fa5
   * are far enough to the right.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  if (count > 150)
Packit Service fb6fa5
    count = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/* Scroll to the bottom of the buffer.
Packit Service fb6fa5
 */
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
scroll_to_bottom (GtkTextView *textview)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBuffer *buffer;
Packit Service fb6fa5
  GtkTextIter iter;
Packit Service fb6fa5
  GtkTextMark *mark;
Packit Service fb6fa5
  char *spaces;
Packit Service fb6fa5
  static int count;
Packit Service fb6fa5
Packit Service fb6fa5
  buffer = gtk_text_view_get_buffer (textview);
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* Get end iterator */
Packit Service fb6fa5
  gtk_text_buffer_get_end_iter (buffer, &iter);
Packit Service fb6fa5
Packit Service fb6fa5
  /* and insert some text at it, the iter will be revalidated
Packit Service fb6fa5
   * after insertion to point to the end of inserted text
Packit Service fb6fa5
   */
Packit Service fb6fa5
  spaces = g_strnfill (count++, ' ');
Packit Service fb6fa5
  gtk_text_buffer_insert (buffer, &iter, "\n", -1);
Packit Service fb6fa5
  gtk_text_buffer_insert (buffer, &iter, spaces, -1);
Packit Service fb6fa5
  gtk_text_buffer_insert (buffer, &iter,
Packit Service fb6fa5
                          "Scroll to bottom scroll to bottom scroll "
Packit Service fb6fa5
                          "to bottom scroll to bottom",
Packit Service fb6fa5
                          -1);
Packit Service fb6fa5
  g_free (spaces);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Move the iterator to the beginning of line, so we don't scroll 
Packit Service fb6fa5
   * in horizontal direction 
Packit Service fb6fa5
   */
Packit Service fb6fa5
  gtk_text_iter_set_line_offset (&iter, 0);
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* and place the mark at iter. the mark will stay there after we
Packit Service fb6fa5
   * insert some text at the end because it has right gravity.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  mark = gtk_text_buffer_get_mark (buffer, "scroll");
Packit Service fb6fa5
  gtk_text_buffer_move_mark (buffer, mark, &iter);
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* Scroll the mark onscreen.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  gtk_text_view_scroll_mark_onscreen (textview, mark);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Shift text back if we got enough to the right.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  if (count > 40)
Packit Service fb6fa5
    count = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static guint
Packit Service fb6fa5
setup_scroll (GtkTextView *textview,
Packit Service fb6fa5
              gboolean     to_end)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBuffer *buffer;
Packit Service fb6fa5
  GtkTextIter iter;
Packit Service fb6fa5
Packit Service fb6fa5
  buffer = gtk_text_view_get_buffer (textview);
Packit Service fb6fa5
  gtk_text_buffer_get_end_iter (buffer, &iter);
Packit Service fb6fa5
Packit Service fb6fa5
  if (to_end)
Packit Service fb6fa5
  {
Packit Service fb6fa5
    /* If we want to scroll to the end, including horizontal scrolling,
Packit Service fb6fa5
     * then we just create a mark with right gravity at the end of the 
Packit Service fb6fa5
     * buffer. It will stay at the end unless explicitely moved with 
Packit Service fb6fa5
     * gtk_text_buffer_move_mark.
Packit Service fb6fa5
     */
Packit Service fb6fa5
    gtk_text_buffer_create_mark (buffer, "end", &iter, FALSE);
Packit Service fb6fa5
    
Packit Service fb6fa5
    /* Add scrolling timeout. */
Packit Service fb6fa5
    return g_timeout_add (50, (GSourceFunc) scroll_to_end, textview);
Packit Service fb6fa5
  }
Packit Service fb6fa5
  else
Packit Service fb6fa5
  {
Packit Service fb6fa5
    /* If we want to scroll to the bottom, but not scroll horizontally, 
Packit Service fb6fa5
     * then an end mark won't do the job. Just create a mark so we can 
Packit Service fb6fa5
     * use it with gtk_text_view_scroll_mark_onscreen, we'll position it
Packit Service fb6fa5
     * explicitely when needed. Use left gravity so the mark stays where 
Packit Service fb6fa5
     * we put it after inserting new text.
Packit Service fb6fa5
     */
Packit Service fb6fa5
    gtk_text_buffer_create_mark (buffer, "scroll", &iter, TRUE);
Packit Service fb6fa5
    
Packit Service fb6fa5
    /* Add scrolling timeout. */
Packit Service fb6fa5
    return g_timeout_add (100, (GSourceFunc) scroll_to_bottom, textview);
Packit Service fb6fa5
  }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
remove_timeout (GtkWidget *window,
Packit Service fb6fa5
                gpointer   timeout)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_source_remove (GPOINTER_TO_UINT (timeout));
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
create_text_view (GtkWidget *hbox,
Packit Service fb6fa5
                  gboolean   to_end)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkWidget *swindow;
Packit Service fb6fa5
  GtkWidget *textview;
Packit Service fb6fa5
  guint timeout;
Packit Service fb6fa5
Packit Service fb6fa5
  swindow = gtk_scrolled_window_new (NULL, NULL);
Packit Service fb6fa5
  gtk_box_pack_start (GTK_BOX (hbox), swindow, TRUE, TRUE, 0);
Packit Service fb6fa5
  textview = gtk_text_view_new ();
Packit Service fb6fa5
  gtk_container_add (GTK_CONTAINER (swindow), textview);
Packit Service fb6fa5
Packit Service fb6fa5
  timeout = setup_scroll (GTK_TEXT_VIEW (textview), to_end);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Remove the timeout in destroy handler, so we don't try to
Packit Service fb6fa5
   * scroll destroyed widget. 
Packit Service fb6fa5
   */
Packit Service fb6fa5
  g_signal_connect (textview, "destroy",
Packit Service fb6fa5
                    G_CALLBACK (remove_timeout),
Packit Service fb6fa5
                    GUINT_TO_POINTER (timeout));
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkWidget *
Packit Service fb6fa5
do_textscroll (GtkWidget *do_widget)
Packit Service fb6fa5
{
Packit Service fb6fa5
  static GtkWidget *window = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!window)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkWidget *hbox;
Packit Service fb6fa5
Packit Service fb6fa5
      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit Service fb6fa5
      g_signal_connect (window, "destroy",
Packit Service fb6fa5
			G_CALLBACK (gtk_widget_destroyed), &window);
Packit Service fb6fa5
      gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
Packit Service fb6fa5
      
Packit Service fb6fa5
      hbox = gtk_hbox_new (TRUE, 6);
Packit Service fb6fa5
      gtk_container_add (GTK_CONTAINER (window), hbox);
Packit Service fb6fa5
Packit Service fb6fa5
      create_text_view (hbox, TRUE);
Packit Service fb6fa5
      create_text_view (hbox, FALSE);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (!gtk_widget_get_visible (window))
Packit Service fb6fa5
      gtk_widget_show_all (window);
Packit Service fb6fa5
  else
Packit Service fb6fa5
      gtk_widget_destroy (window);
Packit Service fb6fa5
Packit Service fb6fa5
  return window;
Packit Service fb6fa5
}