1/* simple.c
2 * Copyright (C) 2017 Red Hat, Inc
3 * Author: Benjamin Otte
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "config.h"
19#include <gtk/gtk.h>
20
21
22const char text[] =
23"This library is free software; you can redistribute it and/or\n"
24"modify it under the terms of the GNU Library General Public\n"
25"License as published by the Free Software Foundation; either\n"
26"version 2 of the License, or (at your option) any later version.\n"
27"\n"
28"This library is distributed in the hope that it will be useful,\n"
29"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
30"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
31"Library General Public License for more details.\n"
32"\n"
33"You should have received a copy of the GNU Library General Public\n"
34"License along with this library. If not, see <http://www.gnu.org/licenses/>.\n";
35
36static GtkWidget *tv;
37static GtkTextBuffer *buffer;
38static int len;
39
40static GtkTextMark **marks;
41static guint marks_timeout;
42
43static gboolean toggle_mark (gpointer data)
44{
45 int pos;
46 GtkTextMark *mark;
47
48 pos = g_random_int_range (begin: 0, end: len);
49 mark = marks[pos];
50
51 gtk_text_mark_set_visible (mark, setting: !gtk_text_mark_get_visible (mark));
52
53 return G_SOURCE_CONTINUE;
54}
55
56static void
57toggle_marks (GtkToggleButton *button)
58{
59 int i;
60 gboolean enable;
61
62 enable = gtk_toggle_button_get_active (toggle_button: button);
63
64 if (!marks)
65 {
66 marks = g_new (GtkTextMark*, len);
67
68 for (i = 0; i < len; i++)
69 {
70 marks[i] = gtk_text_mark_new (NULL, TRUE);
71 gtk_text_mark_set_visible (mark: marks[i], setting: i % 2);
72 }
73 }
74
75 if (enable)
76 {
77 for (i = 0; i < len; i++)
78 {
79 GtkTextIter iter;
80
81 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: i);
82 gtk_text_buffer_add_mark (buffer, mark: marks[i], where: &iter);
83 }
84
85 marks_timeout = g_timeout_add (interval: 16, function: toggle_mark, NULL);
86 }
87 else
88 {
89 for (i = 0; i < len; i++)
90 gtk_text_buffer_delete_mark (buffer, mark: marks[i]);
91
92 if (marks_timeout)
93 g_source_remove (tag: marks_timeout);
94 marks_timeout = 0;
95 }
96}
97
98static gboolean
99move_insert (gpointer data)
100{
101 GtkTextMark *mark;
102 GtkTextIter iter, start, end;
103
104 mark = gtk_text_buffer_get_insert (buffer);
105 gtk_text_buffer_get_iter_at_mark (buffer, iter: &iter, mark);
106 gtk_text_buffer_get_bounds (buffer, start: &start, end: &end);
107
108 if (gtk_text_iter_equal (lhs: &iter, rhs: &end))
109 gtk_text_iter_assign (iter: &iter, other: &start);
110 else
111 gtk_text_iter_forward_cursor_position (iter: &iter);
112
113 gtk_text_buffer_place_cursor (buffer, where: &iter);
114
115 return G_SOURCE_CONTINUE;
116}
117
118static guint cursor_timeout;
119
120static void
121toggle_cursor (GtkToggleButton *button)
122{
123 gboolean enable;
124
125 enable = gtk_toggle_button_get_active (toggle_button: button);
126 if (enable)
127 cursor_timeout = g_timeout_add (interval: 16, function: move_insert, NULL);
128 else
129 {
130 if (cursor_timeout)
131 g_source_remove (tag: cursor_timeout);
132 cursor_timeout = 0;
133 }
134}
135
136static GtkTextMark *the_mark;
137static GtkWidget *mark_check;
138static GtkWidget *mark_visible;
139static GtkWidget *position_spin;
140
141static void
142update_mark_exists (void)
143{
144 int pos;
145 GtkTextIter iter;
146
147 pos = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (position_spin));
148 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: pos);
149
150 if (gtk_check_button_get_active (GTK_CHECK_BUTTON (mark_check)))
151 gtk_text_buffer_add_mark (buffer, mark: the_mark, where: &iter);
152 else
153 gtk_text_buffer_delete_mark (buffer, mark: the_mark);
154}
155
156static void
157update_mark_visible (void)
158{
159 gtk_text_mark_set_visible (mark: the_mark, setting: gtk_check_button_get_active (GTK_CHECK_BUTTON (mark_visible)));
160}
161
162static void
163update_mark_position (void)
164{
165 int pos;
166 GtkTextIter iter;
167
168 pos = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (position_spin));
169 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: pos);
170
171 gtk_text_buffer_move_mark (buffer, mark: the_mark, where: &iter);
172}
173
174static void
175quit_cb (GtkWidget *widget,
176 gpointer data)
177{
178 gboolean *done = data;
179
180 *done = TRUE;
181
182 g_main_context_wakeup (NULL);
183}
184
185int
186main (int argc, char *argv[])
187{
188 GtkWidget *window, *sw, *box, *box2, *button;
189 gboolean done = FALSE;
190
191 gtk_init ();
192
193 window = gtk_window_new ();
194 gtk_window_set_default_size (GTK_WINDOW (window), width: 600, height: 400);
195 g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
196
197 box = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 10);
198
199 sw = gtk_scrolled_window_new ();
200 gtk_widget_set_hexpand (widget: sw, TRUE);
201 gtk_widget_set_vexpand (widget: sw, TRUE);
202 gtk_window_set_child (GTK_WINDOW (window), child: box);
203 gtk_box_append (GTK_BOX (box), child: sw);
204
205 tv = gtk_text_view_new ();
206 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: tv);
207
208 buffer = gtk_text_buffer_new (NULL);
209 gtk_text_view_set_buffer (GTK_TEXT_VIEW (tv), buffer);
210
211 gtk_text_buffer_set_text (buffer, text, len: -1);
212
213 len = strlen (s: text);
214
215 box2 = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10);
216 g_object_set (object: box, first_property_name: "margin-start", 10, "margin-end", 10, NULL);
217 gtk_box_append (GTK_BOX (box), child: box2);
218
219 the_mark = gtk_text_mark_new (name: "my mark", TRUE);
220 box2 = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10);
221 gtk_box_append (GTK_BOX (box), child: box2);
222 mark_check = gtk_check_button_new_with_label (label: "Mark");
223 g_signal_connect (mark_check, "notify::active", G_CALLBACK (update_mark_exists), NULL);
224 gtk_box_append (GTK_BOX (box2), child: mark_check);
225 mark_visible = gtk_check_button_new_with_label (label: "Visible");
226 g_signal_connect (mark_visible, "notify::active", G_CALLBACK (update_mark_visible), NULL);
227 gtk_box_append (GTK_BOX (box2), child: mark_visible);
228 gtk_box_append (GTK_BOX (box2), child: gtk_label_new (str: "Position:"));
229 position_spin = gtk_spin_button_new_with_range (min: 0, max: len, step: 1);
230 g_signal_connect (position_spin, "value-changed", G_CALLBACK (update_mark_position), NULL);
231 gtk_box_append (GTK_BOX (box2), child: position_spin);
232
233 box2 = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10);
234 g_object_set (object: box, first_property_name: "margin-start", 10, "margin-end", 10, NULL);
235 gtk_box_append (GTK_BOX (box), child: box2);
236
237 button = gtk_toggle_button_new_with_label (label: "Random marks");
238 g_signal_connect (button, "notify::active", G_CALLBACK (toggle_marks), NULL);
239 gtk_box_append (GTK_BOX (box2), child: button);
240
241 button = gtk_toggle_button_new_with_label (label: "Wandering cursor");
242 g_signal_connect (button, "notify::active", G_CALLBACK (toggle_cursor), NULL);
243 gtk_box_append (GTK_BOX (box2), child: button);
244
245 gtk_widget_show (widget: window);
246
247 while (!done)
248 g_main_context_iteration (NULL, TRUE);
249
250 return 0;
251}
252

source code of gtk/tests/testtextview2.c