1#include <gtk/gtk.h>
2
3#include "exampleapp.h"
4#include "exampleappwin.h"
5
6struct _ExampleAppWindow
7{
8 GtkApplicationWindow parent;
9
10 GSettings *settings;
11 GtkWidget *stack;
12 GtkWidget *gears;
13 GtkWidget *search;
14 GtkWidget *searchbar;
15 GtkWidget *searchentry;
16 GtkWidget *sidebar;
17 GtkWidget *words;
18};
19
20G_DEFINE_TYPE (ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW)
21
22static void
23search_text_changed (GtkEntry *entry,
24 ExampleAppWindow *win)
25{
26 const char *text;
27 GtkWidget *tab;
28 GtkWidget *view;
29 GtkTextBuffer *buffer;
30 GtkTextIter start, match_start, match_end;
31
32 text = gtk_editable_get_text (GTK_EDITABLE (entry));
33
34 if (text[0] == '\0')
35 return;
36
37 tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
38 view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
39 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
40
41 /* Very simple-minded search implementation */
42 gtk_text_buffer_get_start_iter (buffer, iter: &start);
43 if (gtk_text_iter_forward_search (iter: &start, str: text, flags: GTK_TEXT_SEARCH_CASE_INSENSITIVE,
44 match_start: &match_start, match_end: &match_end, NULL))
45 {
46 gtk_text_buffer_select_range (buffer, ins: &match_start, bound: &match_end);
47 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (view), iter: &match_start,
48 within_margin: 0.0, FALSE, xalign: 0.0, yalign: 0.0);
49 }
50}
51
52static void
53find_word (GtkButton *button,
54 ExampleAppWindow *win)
55{
56 const char *word;
57
58 word = gtk_button_get_label (button);
59 gtk_editable_set_text (GTK_EDITABLE (win->searchentry), text: word);
60}
61
62static void
63update_words (ExampleAppWindow *win)
64{
65 GHashTable *strings;
66 GHashTableIter iter;
67 GtkWidget *tab, *view, *row;
68 GtkTextBuffer *buffer;
69 GtkTextIter start, end;
70 char *word, *key;
71 GtkWidget *child;
72
73 tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
74
75 if (tab == NULL)
76 return;
77
78 view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
79 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
80
81 strings = g_hash_table_new_full (hash_func: g_str_hash, key_equal_func: g_str_equal, key_destroy_func: g_free, NULL);
82
83 gtk_text_buffer_get_start_iter (buffer, iter: &start);
84 while (!gtk_text_iter_is_end (iter: &start))
85 {
86 while (!gtk_text_iter_starts_word (iter: &start))
87 {
88 if (!gtk_text_iter_forward_char (iter: &start))
89 goto done;
90 }
91 end = start;
92 if (!gtk_text_iter_forward_word_end (iter: &end))
93 goto done;
94 word = gtk_text_buffer_get_text (buffer, start: &start, end: &end, FALSE);
95 g_hash_table_add (hash_table: strings, key: g_utf8_strdown (str: word, len: -1));
96 g_free (mem: word);
97 start = end;
98 }
99
100done:
101 while ((child = gtk_widget_get_first_child (widget: win->words)))
102 gtk_list_box_remove (GTK_LIST_BOX (win->words), child);
103
104 g_hash_table_iter_init (iter: &iter, hash_table: strings);
105 while (g_hash_table_iter_next (iter: &iter, key: (gpointer *)&key, NULL))
106 {
107 row = gtk_button_new_with_label (label: key);
108 g_signal_connect (row, "clicked",
109 G_CALLBACK (find_word), win);
110 gtk_list_box_insert (GTK_LIST_BOX (win->words), child: row, position: -1);
111 }
112
113 g_hash_table_unref (hash_table: strings);
114}
115
116static void
117visible_child_changed (GObject *stack,
118 GParamSpec *pspec,
119 ExampleAppWindow *win)
120{
121 if (gtk_widget_in_destruction (GTK_WIDGET (stack)))
122 return;
123
124 gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (win->searchbar), FALSE);
125 update_words (win);
126}
127
128static void
129words_changed (GObject *sidebar,
130 GParamSpec *pspec,
131 ExampleAppWindow *win)
132{
133 update_words (win);
134}
135
136static void
137example_app_window_init (ExampleAppWindow *win)
138{
139 GtkBuilder *builder;
140 GMenuModel *menu;
141 GAction *action;
142
143 gtk_widget_init_template (GTK_WIDGET (win));
144
145 builder = gtk_builder_new_from_resource (resource_path: "/org/gtk/exampleapp/gears-menu.ui");
146 menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
147 gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (win->gears), menu_model: menu);
148 g_object_unref (object: builder);
149
150 win->settings = g_settings_new (schema_id: "org.gtk.exampleapp");
151
152 g_settings_bind (settings: win->settings, key: "transition",
153 object: win->stack, property: "transition-type",
154 flags: G_SETTINGS_BIND_DEFAULT);
155
156 g_settings_bind (settings: win->settings, key: "show-words",
157 object: win->sidebar, property: "reveal-child",
158 flags: G_SETTINGS_BIND_DEFAULT);
159
160 g_object_bind_property (source: win->search, source_property: "active",
161 target: win->searchbar, target_property: "search-mode-enabled",
162 flags: G_BINDING_BIDIRECTIONAL);
163
164 g_signal_connect (win->sidebar, "notify::reveal-child",
165 G_CALLBACK (words_changed), win);
166
167 action = g_settings_create_action (settings: win->settings, key: "show-words");
168 g_action_map_add_action (G_ACTION_MAP (win), action);
169 g_object_unref (object: action);
170}
171
172static void
173example_app_window_dispose (GObject *object)
174{
175 ExampleAppWindow *win;
176
177 win = EXAMPLE_APP_WINDOW (ptr: object);
178
179 g_clear_object (&win->settings);
180
181 G_OBJECT_CLASS (example_app_window_parent_class)->dispose (object);
182}
183
184static void
185example_app_window_class_init (ExampleAppWindowClass *class)
186{
187 G_OBJECT_CLASS (class)->dispose = example_app_window_dispose;
188
189 gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
190 resource_name: "/org/gtk/exampleapp/window.ui");
191
192 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
193 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, gears);
194 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, search);
195 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchbar);
196 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchentry);
197 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, words);
198 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, sidebar);
199
200 gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
201 gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), visible_child_changed);
202
203}
204
205ExampleAppWindow *
206example_app_window_new (ExampleApp *app)
207{
208 return g_object_new (EXAMPLE_APP_WINDOW_TYPE, first_property_name: "application", app, NULL);
209}
210
211void
212example_app_window_open (ExampleAppWindow *win,
213 GFile *file)
214{
215 char *basename;
216 GtkWidget *scrolled, *view;
217 char *contents;
218 gsize length;
219 GtkTextBuffer *buffer;
220 GtkTextTag *tag;
221 GtkTextIter start_iter, end_iter;
222
223 basename = g_file_get_basename (file);
224
225 scrolled = gtk_scrolled_window_new ();
226 gtk_widget_set_hexpand (widget: scrolled, TRUE);
227 gtk_widget_set_vexpand (widget: scrolled, TRUE);
228 view = gtk_text_view_new ();
229 gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
230 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
231 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), child: view);
232 gtk_stack_add_titled (GTK_STACK (win->stack), child: scrolled, name: basename, title: basename);
233
234 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
235
236 if (g_file_load_contents (file, NULL, contents: &contents, length: &length, NULL, NULL))
237 {
238 gtk_text_buffer_set_text (buffer, text: contents, len: length);
239 g_free (mem: contents);
240 }
241
242 tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
243 g_settings_bind (settings: win->settings, key: "font",
244 object: tag, property: "font",
245 flags: G_SETTINGS_BIND_DEFAULT);
246
247 gtk_text_buffer_get_start_iter (buffer, iter: &start_iter);
248 gtk_text_buffer_get_end_iter (buffer, iter: &end_iter);
249 gtk_text_buffer_apply_tag (buffer, tag, start: &start_iter, end: &end_iter);
250
251 g_free (mem: basename);
252
253 gtk_widget_set_sensitive (widget: win->search, TRUE);
254
255 update_words (win);
256}
257

source code of gtk/examples/application8/exampleappwin.c