From 96d2bf10b9f985ce00aeeeaacb29c1e8c2d4f393 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 3 Jan 2020 10:14:19 -0500 Subject: Add a text view mark/cursor test This has testcases for some issues around invalidation of marks. --- tests/meson.build | 1 + tests/testtextview2.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 tests/testtextview2.c diff --git a/tests/meson.build b/tests/meson.build index aa16f4fde7..e6041c3627 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -101,6 +101,7 @@ gtk_tests = [ ['testtreepos'], ['testsensitive'], ['testtextview'], + ['testtextview2'], ['testpixbuf-scale'], ['testgmenu'], ['testlogout'], diff --git a/tests/testtextview2.c b/tests/testtextview2.c new file mode 100644 index 0000000000..83431bfc31 --- /dev/null +++ b/tests/testtextview2.c @@ -0,0 +1,238 @@ +/* simple.c + * Copyright (C) 2017 Red Hat, Inc + * Author: Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + */ +#include "config.h" +#include + + +const char text[] = +"This library is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU Library General Public\n" +"License as published by the Free Software Foundation; either\n" +"version 2 of the License, or (at your option) any later version.\n" +"\n" +"This library is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" +"Library General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU Library General Public\n" +"License along with this library. If not, see .\n"; + +static GtkWidget *tv; +static GtkTextBuffer *buffer; +static int len; + +static GtkTextMark **marks; +static guint marks_timeout; + +static gboolean toggle_mark (gpointer data) +{ + int pos; + GtkTextMark *mark; + + pos = g_random_int_range (0, len); + mark = marks[pos]; + + gtk_text_mark_set_visible (mark, !gtk_text_mark_get_visible (mark)); + + return G_SOURCE_CONTINUE; +} + +static void +toggle_marks (GtkToggleButton *button) +{ + int i; + gboolean enable; + + enable = gtk_toggle_button_get_active (button); + + if (!marks) + { + marks = g_new (GtkTextMark*, len); + + for (i = 0; i < len; i++) + { + marks[i] = gtk_text_mark_new (NULL, TRUE); + gtk_text_mark_set_visible (marks[i], i % 2); + } + } + + if (enable) + { + for (i = 0; i < len; i++) + { + GtkTextIter iter; + + gtk_text_buffer_get_iter_at_offset (buffer, &iter, i); + gtk_text_buffer_add_mark (buffer, marks[i], &iter); + } + + marks_timeout = g_timeout_add (16, toggle_mark, NULL); + } + else + { + for (i = 0; i < len; i++) + gtk_text_buffer_delete_mark (buffer, marks[i]); + + if (marks_timeout) + g_source_remove (marks_timeout); + marks_timeout = 0; + } +} + +static gboolean +move_insert (gpointer data) +{ + GtkTextMark *mark; + GtkTextIter iter, start, end; + + mark = gtk_text_buffer_get_insert (buffer); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark); + gtk_text_buffer_get_bounds (buffer, &start, &end); + + if (gtk_text_iter_equal (&iter, &end)) + gtk_text_iter_assign (&iter, &start); + else + gtk_text_iter_forward_cursor_position (&iter); + + gtk_text_buffer_place_cursor (buffer, &iter); + + return G_SOURCE_CONTINUE; +} + +static guint cursor_timeout; + +static void +toggle_cursor (GtkToggleButton *button) +{ + gboolean enable; + + enable = gtk_toggle_button_get_active (button); + if (enable) + cursor_timeout = g_timeout_add (16, move_insert, NULL); + else + { + if (cursor_timeout) + g_source_remove (cursor_timeout); + cursor_timeout = 0; + } +} + +static GtkTextMark *the_mark; +static GtkWidget *mark_check; +static GtkWidget *mark_visible; +static GtkWidget *position_spin; + +static void +update_mark_exists (void) +{ + int pos; + GtkTextIter iter; + + pos = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (position_spin)); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (mark_check))) + gtk_text_buffer_add_mark (buffer, the_mark, &iter); + else + gtk_text_buffer_delete_mark (buffer, the_mark); +} + +static void +update_mark_visible (void) +{ + gtk_text_mark_set_visible (the_mark, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (mark_visible))); +} + +static void +update_mark_position (void) +{ + int pos; + GtkTextIter iter; + + pos = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (position_spin)); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos); + + gtk_text_buffer_move_mark (buffer, the_mark, &iter); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window, *sw, *box, *box2, *button; + + gtk_init (); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 600, 400); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_hexpand (sw, TRUE); + gtk_widget_set_vexpand (sw, TRUE); + gtk_container_add (GTK_CONTAINER (window), box); + gtk_container_add (GTK_CONTAINER (box), sw); + + tv = gtk_text_view_new (); + gtk_container_add (GTK_CONTAINER (sw), tv); + + buffer = gtk_text_buffer_new (NULL); + gtk_text_view_set_buffer (GTK_TEXT_VIEW (tv), buffer); + + gtk_text_buffer_set_text (buffer, text, -1); + + len = strlen (text); + + box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + g_object_set (box, "margin-start", 10, "margin-end", 10, NULL); + gtk_container_add (GTK_CONTAINER (box), box2); + + the_mark = gtk_text_mark_new ("my mark", TRUE); + box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + gtk_container_add (GTK_CONTAINER (box), box2); + mark_check = gtk_check_button_new_with_label ("Mark"); + g_signal_connect (mark_check, "notify::active", G_CALLBACK (update_mark_exists), NULL); + gtk_container_add (GTK_CONTAINER (box2), mark_check); + mark_visible = gtk_check_button_new_with_label ("Visible"); + g_signal_connect (mark_visible, "notify::active", G_CALLBACK (update_mark_visible), NULL); + gtk_container_add (GTK_CONTAINER (box2), mark_visible); + gtk_container_add (GTK_CONTAINER (box2), gtk_label_new ("Position:")); + position_spin = gtk_spin_button_new_with_range (0, len, 1); + g_signal_connect (position_spin, "value-changed", G_CALLBACK (update_mark_position), NULL); + gtk_container_add (GTK_CONTAINER (box2), position_spin); + + box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + g_object_set (box, "margin-start", 10, "margin-end", 10, NULL); + gtk_container_add (GTK_CONTAINER (box), box2); + + button = gtk_toggle_button_new_with_label ("Random marks"); + g_signal_connect (button, "notify::active", G_CALLBACK (toggle_marks), NULL); + gtk_container_add (GTK_CONTAINER (box2), button); + + button = gtk_toggle_button_new_with_label ("Wandering cursor"); + g_signal_connect (button, "notify::active", G_CALLBACK (toggle_cursor), NULL); + gtk_container_add (GTK_CONTAINER (box2), button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} -- cgit v1.2.1