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