1 /*
2 * Copyright 2019 Vincent Sanders <vince@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 /**
21 * \file
22 * find in page gtk frontend implementation
23 *
24 * \todo this whole thing should be named find rather than search as
25 * that generally means web search and is confusing.
26 */
27
28 #include <stdbool.h>
29 #include <gtk/gtk.h>
30
31 #include "utils/nsoption.h"
32 #include "netsurf/search.h"
33 #include "desktop/search.h"
34
35 #include "gtk/compat.h"
36 #include "gtk/toolbar_items.h"
37 #include "gtk/window.h"
38 #include "gtk/search.h"
39
40
41 struct gtk_search {
42 GtkToolbar *bar;
43 GtkEntry *entry;
44 GtkToolButton *back;
45 GtkToolButton *forward;
46 GtkToolButton *close;
47 GtkCheckButton *checkAll;
48 GtkCheckButton *caseSens;
49
50 struct browser_window *bw;
51 };
52
53 /**
54 * activate search forwards button in gui.
55 *
56 * \param active activate/inactivate
57 * \param search the gtk search context
58 */
nsgtk_search_set_forward_state(bool active,struct gtk_search * search)59 static void nsgtk_search_set_forward_state(bool active, struct gtk_search *search)
60 {
61 gtk_widget_set_sensitive(GTK_WIDGET(search->forward), active);
62 }
63
64
65 /**
66 * activate search back button in gui.
67 *
68 * \param active activate/inactivate
69 * \param search the gtk search context
70 */
nsgtk_search_set_back_state(bool active,struct gtk_search * search)71 static void nsgtk_search_set_back_state(bool active, struct gtk_search *search)
72 {
73 gtk_widget_set_sensitive(GTK_WIDGET(search->back), active);
74 }
75
76
77 /**
78 * connected to the search forward button
79 */
80 static gboolean
nsgtk_search_forward_button_clicked(GtkWidget * widget,gpointer data)81 nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data)
82 {
83 struct gtk_search *search;
84 search_flags_t flags;
85
86 search = (struct gtk_search *)data;
87
88 flags = SEARCH_FLAG_FORWARDS;
89
90 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) {
91 flags |= SEARCH_FLAG_CASE_SENSITIVE;
92 }
93
94 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) {
95 flags |= SEARCH_FLAG_SHOWALL;
96 }
97
98 browser_window_search(search->bw, search, flags,
99 gtk_entry_get_text(search->entry));
100
101 return TRUE;
102 }
103
104 /**
105 * connected to the search back button
106 */
107 static gboolean
nsgtk_search_back_button_clicked(GtkWidget * widget,gpointer data)108 nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data)
109 {
110 struct gtk_search *search;
111 search_flags_t flags;
112
113 search = (struct gtk_search *)data;
114
115 flags = 0;
116
117 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) {
118 flags |= SEARCH_FLAG_CASE_SENSITIVE;
119 }
120
121 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) {
122 flags |= SEARCH_FLAG_SHOWALL;
123 }
124
125 browser_window_search(search->bw, search, flags,
126 gtk_entry_get_text(search->entry));
127
128 return TRUE;
129 }
130
131 /**
132 * connected to the search close button
133 */
134 static gboolean
nsgtk_search_close_button_clicked(GtkWidget * widget,gpointer data)135 nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data)
136 {
137 struct gtk_search *search;
138
139 search = (struct gtk_search *)data;
140
141 nsgtk_search_toggle_visibility(search);
142
143 return TRUE;
144 }
145
146
147 /**
148 * connected to the search entry [typing]
149 */
nsgtk_search_entry_changed(GtkWidget * widget,gpointer data)150 static gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data)
151 {
152 struct gtk_search *search;
153 search_flags_t flags;
154
155 search = (struct gtk_search *)data;
156
157 flags = 0;
158
159 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) {
160 flags |= SEARCH_FLAG_CASE_SENSITIVE;
161 }
162
163 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) {
164 flags |= SEARCH_FLAG_SHOWALL;
165 }
166
167 browser_window_search(search->bw, search, flags,
168 gtk_entry_get_text(search->entry));
169
170 return TRUE;
171 }
172
173 /**
174 * connected to the search entry [return key]
175 */
nsgtk_search_entry_activate(GtkWidget * widget,gpointer data)176 static gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data)
177 {
178 struct gtk_search *search;
179 search_flags_t flags;
180
181 search = (struct gtk_search *)data;
182
183 flags = SEARCH_FLAG_FORWARDS;
184
185 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) {
186 flags |= SEARCH_FLAG_CASE_SENSITIVE;
187 }
188
189 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) {
190 flags |= SEARCH_FLAG_SHOWALL;
191 }
192
193 browser_window_search(search->bw, search, flags,
194 gtk_entry_get_text(search->entry));
195
196 return FALSE;
197 }
198
199 /**
200 * allows escape key to close search bar too
201 */
202 static gboolean
nsgtk_search_entry_key(GtkWidget * widget,GdkEventKey * event,gpointer data)203 nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event, gpointer data)
204 {
205 if (event->keyval == GDK_KEY(Escape)) {
206 struct gtk_search *search;
207 search = (struct gtk_search *)data;
208
209 nsgtk_search_toggle_visibility(search);
210 }
211 return FALSE;
212 }
213
214
215 static struct gui_search_table search_table = {
216 .forward_state = (void *)nsgtk_search_set_forward_state,
217 .back_state = (void *)nsgtk_search_set_back_state,
218 };
219
220 struct gui_search_table *nsgtk_search_table = &search_table;
221
222
223 /* exported interface documented in gtk/scaffolding.h */
nsgtk_search_toggle_visibility(struct gtk_search * search)224 nserror nsgtk_search_toggle_visibility(struct gtk_search *search)
225 {
226 gboolean vis;
227
228 browser_window_search_clear(search->bw);
229
230 g_object_get(G_OBJECT(search->bar), "visible", &vis, NULL);
231 if (vis) {
232 gtk_widget_hide(GTK_WIDGET(search->bar));
233 } else {
234 gtk_widget_show(GTK_WIDGET(search->bar));
235 gtk_widget_grab_focus(GTK_WIDGET(search->entry));
236 nsgtk_search_entry_changed(GTK_WIDGET(search->entry), search);
237 }
238
239 return NSERROR_OK;
240 }
241
242
243 /* exported interface documented in gtk/search.h */
nsgtk_search_restyle(struct gtk_search * search)244 nserror nsgtk_search_restyle(struct gtk_search *search)
245 {
246 switch (nsoption_int(button_type)) {
247
248 case 1: /* Small icons */
249 gtk_toolbar_set_style(GTK_TOOLBAR(search->bar),
250 GTK_TOOLBAR_ICONS);
251 gtk_toolbar_set_icon_size(GTK_TOOLBAR(search->bar),
252 GTK_ICON_SIZE_SMALL_TOOLBAR);
253 break;
254
255 case 2: /* Large icons */
256 gtk_toolbar_set_style(GTK_TOOLBAR(search->bar),
257 GTK_TOOLBAR_ICONS);
258 gtk_toolbar_set_icon_size(GTK_TOOLBAR(search->bar),
259 GTK_ICON_SIZE_LARGE_TOOLBAR);
260 break;
261
262 case 3: /* Large icons with text */
263 gtk_toolbar_set_style(GTK_TOOLBAR(search->bar),
264 GTK_TOOLBAR_BOTH);
265 gtk_toolbar_set_icon_size(GTK_TOOLBAR(search->bar),
266 GTK_ICON_SIZE_LARGE_TOOLBAR);
267 break;
268
269 case 4: /* Text icons only */
270 gtk_toolbar_set_style(GTK_TOOLBAR(search->bar),
271 GTK_TOOLBAR_TEXT);
272 default:
273 break;
274 }
275 return NSERROR_OK;
276 }
277
278
279 /* exported interface documented in gtk/search.h */
280 nserror
nsgtk_search_create(GtkBuilder * builder,struct browser_window * bw,struct gtk_search ** search_out)281 nsgtk_search_create(GtkBuilder *builder,
282 struct browser_window *bw,
283 struct gtk_search **search_out)
284 {
285 struct gtk_search *search;
286
287 search = malloc(sizeof(struct gtk_search));
288 if (search == NULL) {
289 return NSERROR_NOMEM;
290 }
291
292 search->bw = bw;
293
294 search->bar = GTK_TOOLBAR(gtk_builder_get_object(builder, "findbar"));
295 search->entry = GTK_ENTRY(gtk_builder_get_object(builder, "Find"));
296 search->back = GTK_TOOL_BUTTON(gtk_builder_get_object(builder,
297 "FindBack"));
298 search->forward = GTK_TOOL_BUTTON(gtk_builder_get_object(builder,
299 "FindForward"));
300 search->close = GTK_TOOL_BUTTON(gtk_builder_get_object(builder,
301 "FindClose"));
302 search->checkAll = GTK_CHECK_BUTTON(gtk_builder_get_object(builder,
303 "FindHighlightAll"));
304 search->caseSens = GTK_CHECK_BUTTON(gtk_builder_get_object(builder,
305 "FindMatchCase"));
306
307 g_signal_connect(search->forward,
308 "clicked",
309 G_CALLBACK(nsgtk_search_forward_button_clicked),
310 search);
311
312 g_signal_connect(search->back,
313 "clicked",
314 G_CALLBACK(nsgtk_search_back_button_clicked),
315 search);
316
317 g_signal_connect(search->entry,
318 "changed",
319 G_CALLBACK(nsgtk_search_entry_changed),
320 search);
321
322 g_signal_connect(search->entry,
323 "activate",
324 G_CALLBACK(nsgtk_search_entry_activate),
325 search);
326
327 g_signal_connect(search->entry,
328 "key-press-event",
329 G_CALLBACK(nsgtk_search_entry_key),
330 search);
331
332 g_signal_connect(search->close,
333 "clicked",
334 G_CALLBACK(nsgtk_search_close_button_clicked),
335 search);
336
337 g_signal_connect(search->caseSens,
338 "toggled",
339 G_CALLBACK(nsgtk_search_entry_changed),
340 search);
341
342 g_signal_connect(search->checkAll,
343 "toggled",
344 G_CALLBACK(nsgtk_search_entry_changed),
345 search);
346
347 nsgtk_search_restyle(search);
348
349
350 *search_out = search;
351
352 return NSERROR_OK;
353 }
354