6

They are located under:

share\gtk-2.0\demo

But none of them contains a main function, how can I make the following textscroll.c actually work:

/* 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;

  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 (GTK_BOX (hbox), swindow, TRUE, TRUE, 0);
  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;

      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_get_visible (window))
      gtk_widget_show_all (window);
  else
      gtk_widget_destroy (window);

  return window;
}
Gtker
  • 2,237
  • 9
  • 29
  • 37

4 Answers4

10

You can also browse the source code online: http://git.gnome.org/browse/gtk+/tree/demos/gtk-demo

The main() function is at the very end of main.c.

EDIT:

Here is a simple main() function that you can add to the end of the file. You also have to delete the #include "demo-common.h" line from the beginning.

int
main(int argc, char **argv)
{
    GtkWidget *window;

    gtk_init(&argc, &argv);
    window = do_textscroll(NULL);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_main();
    return 0;
}
ptomato
  • 56,175
  • 13
  • 112
  • 165
  • It's too complicated,can you ellaborate how I can write a `main` function that uses `textscroll.c` ? – Gtker May 01 '10 at 09:23
  • 1
    You look at it for 5 minutes and say "too complicated"?? Sheesh. How do you expect to get good at programming with _that_ attitude? Nevertheless, I'm in a good mood today, so see my edit. – ptomato May 01 '10 at 10:01
  • Thanks @ptomato,sorry, I'm really new to gtk,even `c`,thanks again! – Gtker May 01 '10 at 10:04
  • Still useful 2019 ... to test a single demo program. The normal distributions (mine is Fedora) should have gtk3-demo available from the command line, so you can easily copy the source code you wish to use. – Erich Kuester Mar 13 '19 at 15:58
4

You should run

gtk-demo

from command line. A window with all demos will show up. You can browse source code, and run demos by double-clicking on them.

0

Update 2015: Run %gtkdir%/bin/gtk3-demo.exe

Bernd Elkemann
  • 23,242
  • 4
  • 37
  • 66
0

For gtk-4 the following works: This is a basic example of hello triangle. The shaders are added using variables. Make sure you have all the required libs. run the code using:

gcc -o main.o main.c pkg-config --cflags --libs gtk4 -lepoxy

#include <gtk/gtk.h>
#include <epoxy/gl.h>

static GtkWidget *gl_area = NULL;
static GLuint program_vbo;
static GLuint program;
GLint err;

static const GLfloat vertices[] = {
    -0.5f, -0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    0.0f, 0.5f, 0.0f};

static const char *vertex_shader =
"#version 330\n"
"layout(location = 0) in vec4 position;\n"
"void main() {\n"
"gl_Position = position;\n"
"}";

static const char *fragment_shader =
"#version 330\n"
"out vec4 outputColor;\n"
"void main() {\n"
"float lerpVal = gl_FragCoord.y / 500.0f;\n"
"outputColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpVal);\n"
"}";

static gboolean
render(GtkGLArea *area,
       GdkGLContext *context)
{
    if (gtk_gl_area_get_error(area) != NULL)
        return FALSE;

    /* Clear the viewport */
    glClearColor(0.9, 0.9, 0.9, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(program);
    glBindBuffer(GL_ARRAY_BUFFER, program_vbo);
    
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    // glBufferSubData(GL_ARRAY_BUFFER, 0, 2*sizeof(vertices), vertices);

    err = glGetError();
    printf("%d\n", err);
    /* Draw our object */
    glDrawArrays(GL_TRIANGLES, 0, 3);

    err = glGetError();
    printf("%d\n", err);

    /* We finished using the buffers and program */
    glDisableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glUseProgram(0);
    /* Flush the contents of the pipeline */
    glFlush();

    return TRUE;
}

void unrealize(GtkWidget *widget)
{
    gtk_gl_area_make_current(GTK_GL_AREA(widget));

    if (gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL)
        return;
}

void realize(GtkWidget *widget)
{
    gtk_gl_area_make_current(GTK_GL_AREA(widget));
    if (gtk_gl_area_get_error (GTK_GL_AREA (widget)) != NULL)
        return;
    GLuint vbo, vao;
    int status;
    glGenVertexArrays (1, &vao);
    glBindVertexArray (vao);
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    program_vbo = vbo;

    GLuint v_shader, f_shader;

    v_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(v_shader, 1, &vertex_shader, NULL);
    glCompileShader(v_shader);

    f_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(f_shader, 1, &fragment_shader, NULL);
    glCompileShader(f_shader);

    program = glCreateProgram();
    glAttachShader(program, f_shader);
    glAttachShader(program, v_shader);
    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &status);
    if (status == GL_FALSE)
    {
        int log_len;
        char *buffer;

        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);

        buffer = g_malloc(log_len + 1);
        glGetProgramInfoLog(program, log_len, NULL, buffer);

        g_warning("Linking failure:\n%s", buffer);

        g_free(buffer);

        glDeleteProgram(program);
        program = 0;

        goto out;
    }

    glDetachShader(program, v_shader);
    glDetachShader(program, f_shader);

out:
    glDeleteShader(v_shader);
    glDeleteShader(f_shader);
}

void activate(GtkApplication *app)
{
    GtkWidget *window, *box;
    window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "OpenGL Area");
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_window_destroy), NULL);

    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, FALSE);
    gtk_widget_set_margin_start(box, 0);
    gtk_widget_set_margin_end(box, 0);
    gtk_widget_set_margin_top(box, 0);
    gtk_widget_set_margin_bottom(box, 0);
    gtk_box_set_spacing(GTK_BOX(box), 0);
    gtk_window_set_child(GTK_WINDOW(window), box);

    gl_area = gtk_gl_area_new();
    gtk_widget_set_hexpand(gl_area, TRUE);
    gtk_widget_set_vexpand(gl_area, TRUE);
    gtk_widget_set_size_request(gl_area, 100, 200);
    gtk_box_append(GTK_BOX(box), gl_area);

    /* We need to initialize and free GL resources, so we use
     * the realize and unrealize signals on the widget
     */
    g_signal_connect(gl_area, "realize", G_CALLBACK(realize), NULL);
    g_signal_connect(gl_area, "unrealize", G_CALLBACK(unrealize), NULL);

    /* The main "draw" call for GtkGLArea */
    g_signal_connect(gl_area, "render", G_CALLBACK(render), NULL);

    gtk_widget_show(window);
}

int main(int argc,
         char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}