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 | |
22 | const 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 | |
36 | static GtkWidget *tv; |
37 | static GtkTextBuffer *buffer; |
38 | static int len; |
39 | |
40 | static GtkTextMark **marks; |
41 | static guint marks_timeout; |
42 | |
43 | static 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 | |
56 | static void |
57 | toggle_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 | |
98 | static gboolean |
99 | move_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 | |
118 | static guint cursor_timeout; |
119 | |
120 | static void |
121 | toggle_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 | |
136 | static GtkTextMark *the_mark; |
137 | static GtkWidget *mark_check; |
138 | static GtkWidget *mark_visible; |
139 | static GtkWidget *position_spin; |
140 | |
141 | static void |
142 | update_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 | |
156 | static void |
157 | update_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 | |
162 | static void |
163 | update_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 | |
174 | static void |
175 | quit_cb (GtkWidget *widget, |
176 | gpointer data) |
177 | { |
178 | gboolean *done = data; |
179 | |
180 | *done = TRUE; |
181 | |
182 | g_main_context_wakeup (NULL); |
183 | } |
184 | |
185 | int |
186 | main (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 | |