1 /*
2  * Copyright 2016 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  * \file
21  * Implementation of RISC OS cookie manager.
22  */
23 
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <oslib/wimp.h>
27 
28 #include "utils/log.h"
29 #include "utils/nsoption.h"
30 #include "utils/messages.h"
31 #include "netsurf/plotters.h"
32 #include "netsurf/keypress.h"
33 #include "desktop/cookie_manager.h"
34 
35 #include "riscos/gui.h"
36 #include "riscos/wimp.h"
37 #include "riscos/wimp_event.h"
38 #include "riscos/dialog.h"
39 #include "riscos/toolbar.h"
40 #include "riscos/corewindow.h"
41 #include "riscos/cookies.h"
42 
43 struct ro_cookie_window {
44 	struct ro_corewindow core;
45 	wimp_menu *menu;
46 };
47 
48 /** cookie window is a singleton */
49 static struct ro_cookie_window *cookie_window = NULL;
50 
51 /** riscos template for cookie window */
52 static wimp_window *dialog_cookie_template;
53 
54 
55 /**
56  * callback to draw on drawable area of ro cookie window
57  *
58  * \param ro_cw The riscos core window structure.
59  * \param r The rectangle of the window that needs updating.
60  * \param originx The risc os plotter x origin.
61  * \param originy The risc os plotter y origin.
62  * \return NSERROR_OK on success otherwise apropriate error code
63  */
64 static nserror
cookie_draw(struct ro_corewindow * ro_cw,int originx,int originy,struct rect * r)65 cookie_draw(struct ro_corewindow *ro_cw,
66 	       int originx,
67 	       int originy,
68 	       struct rect *r)
69 {
70 	struct redraw_context ctx = {
71 		.interactive = true,
72 		.background_images = true,
73 		.plot = &ro_plotters
74 	};
75 
76 	ro_plot_origin_x = originx;
77 	ro_plot_origin_y = originy;
78 	no_font_blending = true;
79 	cookie_manager_redraw(0, 0, r, &ctx);
80 	no_font_blending = false;
81 
82 	return NSERROR_OK;
83 }
84 
85 
86 /**
87  * callback for keypress on ro cookie window
88  *
89  * \param ro_cw The ro core window structure.
90  * \param nskey The netsurf key code.
91  * \return NSERROR_OK if key processed,
92  *         NSERROR_NOT_IMPLEMENTED if key not processed
93  *         otherwise apropriate error code
94  */
cookie_key(struct ro_corewindow * ro_cw,uint32_t nskey)95 static nserror cookie_key(struct ro_corewindow *ro_cw, uint32_t nskey)
96 {
97 	if (cookie_manager_keypress(nskey)) {
98 		return NSERROR_OK;
99 	}
100 	return NSERROR_NOT_IMPLEMENTED;
101 }
102 
103 
104 /**
105  * callback for mouse event on ro cookie window
106  *
107  * \param ro_cw The ro core window structure.
108  * \param mouse_state mouse state
109  * \param x location of event
110  * \param y location of event
111  * \return NSERROR_OK on sucess otherwise apropriate error code.
112  */
113 static nserror
cookie_mouse(struct ro_corewindow * ro_cw,browser_mouse_state mouse_state,int x,int y)114 cookie_mouse(struct ro_corewindow *ro_cw,
115 	     browser_mouse_state mouse_state,
116 	     int x, int y)
117 {
118 	cookie_manager_mouse_action(mouse_state, x, y);
119 
120 	return NSERROR_OK;
121 }
122 
123 
124 /**
125  * handle clicks in ro core window toolbar.
126  *
127  * \param ro_cw The ro core window structure.
128  * \param action The button bar action.
129  * \return NSERROR_OK if config saved, otherwise apropriate error code
130  */
131 static nserror
cookie_toolbar_click(struct ro_corewindow * ro_cw,button_bar_action action)132 cookie_toolbar_click(struct ro_corewindow *ro_cw, button_bar_action action)
133 {
134 	switch (action) {
135 	case TOOLBAR_BUTTON_DELETE:
136 		cookie_manager_keypress(NS_KEY_DELETE_LEFT);
137 		break;
138 
139 	case TOOLBAR_BUTTON_EXPAND:
140 		cookie_manager_expand(false);
141 		break;
142 
143 	case TOOLBAR_BUTTON_COLLAPSE:
144 		cookie_manager_contract(false);
145 		break;
146 
147 	case TOOLBAR_BUTTON_OPEN:
148 		cookie_manager_expand(true);
149 		break;
150 
151 	case TOOLBAR_BUTTON_CLOSE:
152 		cookie_manager_contract(true);
153 		break;
154 
155 	default:
156 		break;
157 	}
158 
159 	return NSERROR_OK;
160 }
161 
162 
163 /**
164  * Handle updating state of buttons in ro core window toolbar.
165  *
166  * \param ro_cw The ro core window structure.
167  * \return NSERROR_OK if config saved, otherwise apropriate error code
168  */
cookie_toolbar_update(struct ro_corewindow * ro_cw)169 static nserror cookie_toolbar_update(struct ro_corewindow *ro_cw)
170 {
171 	ro_toolbar_set_button_shaded_state(ro_cw->toolbar,
172 			TOOLBAR_BUTTON_DELETE,
173 			!cookie_manager_has_selection());
174 	return NSERROR_OK;
175 }
176 
177 
178 /**
179  * callback for saving of toolbar state in ro cookie window
180  *
181  * \param ro_cw The ro core window structure.
182  * \param config The new toolbar configuration.
183  * \return NSERROR_OK if config saved, otherwise apropriate error code
184  */
cookie_toolbar_save(struct ro_corewindow * ro_cw,char * config)185 static nserror cookie_toolbar_save(struct ro_corewindow *ro_cw, char *config)
186 {
187 	nsoption_set_charp(toolbar_cookies, config);
188 	ro_gui_save_options();
189 
190 	return NSERROR_OK;
191 }
192 
193 
194 /**
195  * Prepare the cookie meu for display
196  *
197  * \param w The window owning the menu.
198  * \param i The icon owning the menu.
199  * \param menu	The menu from which the selection was made.
200  * \param pointer The pointer shape
201  * \return true if action accepted; else false.
202  */
203 static bool
cookie_menu_prepare(wimp_w w,wimp_i i,wimp_menu * menu,wimp_pointer * pointer)204 cookie_menu_prepare(wimp_w w,
205 		    wimp_i i,
206 		    wimp_menu *menu,
207 		    wimp_pointer *pointer)
208 {
209 	bool selection;
210 	struct ro_cookie_window *cookiew;
211 
212 	cookiew = (struct ro_cookie_window *)ro_gui_wimp_event_get_user_data(w);
213 
214 	if ((cookiew == NULL) ||
215 	    (menu != cookiew->menu)) {
216 		return false;
217 	}
218 
219 	selection = cookie_manager_has_selection();
220 
221 	ro_gui_menu_set_entry_shaded(menu, TREE_SELECTION, !selection);
222 	ro_gui_menu_set_entry_shaded(menu, TREE_CLEAR_SELECTION, !selection);
223 
224 	ro_gui_menu_set_entry_shaded(menu, TOOLBAR_BUTTONS,
225 			ro_toolbar_menu_option_shade(cookiew->core.toolbar));
226 	ro_gui_menu_set_entry_ticked(menu, TOOLBAR_BUTTONS,
227 			ro_toolbar_menu_buttons_tick(cookiew->core.toolbar));
228 
229 	ro_gui_menu_set_entry_shaded(menu, TOOLBAR_EDIT,
230 			ro_toolbar_menu_edit_shade(cookiew->core.toolbar));
231 	ro_gui_menu_set_entry_ticked(menu, TOOLBAR_EDIT,
232 			ro_toolbar_menu_edit_tick(cookiew->core.toolbar));
233 
234 	return true;
235 }
236 
237 
238 /**
239  * Handle submenu warnings for the cookies menu
240  *
241  * \param w The window owning the menu.
242  * \param i The icon owning the menu.
243  * \param menu The menu to which the warning applies.
244  * \param selection The wimp menu selection data.
245  * \param action The selected menu action.
246  */
247 static void
cookie_menu_warning(wimp_w w,wimp_i i,wimp_menu * menu,wimp_selection * selection,menu_action action)248 cookie_menu_warning(wimp_w w,
249 		    wimp_i i,
250 		    wimp_menu *menu,
251 		    wimp_selection *selection,
252 		    menu_action action)
253 {
254 	/* Do nothing */
255 }
256 
257 
258 /**
259  * Handle selections from the cookies menu
260  *
261  * \param w The window owning the menu.
262  * \param i The icon owning the menu.
263  * \param menu The menu from which the selection was made.
264  * \param selection The wimp menu selection data.
265  * \param action The selected menu action.
266  * \return true if action accepted; else false.
267  */
268 static bool
cookie_menu_select(wimp_w w,wimp_i i,wimp_menu * menu,wimp_selection * selection,menu_action action)269 cookie_menu_select(wimp_w w,
270 		   wimp_i i,
271 		   wimp_menu *menu,
272 		   wimp_selection *selection,
273 		   menu_action action)
274 {
275 	struct ro_cookie_window *cookiew;
276 
277 	cookiew = (struct ro_cookie_window *)ro_gui_wimp_event_get_user_data(w);
278 
279 	if ((cookiew == NULL) ||
280 	    (menu != cookiew->menu)) {
281 		return false;
282 	}
283 
284 	switch (action) {
285 	case TREE_EXPAND_ALL:
286 		cookie_manager_expand(false);
287 		return true;
288 
289 	case TREE_EXPAND_FOLDERS:
290 		cookie_manager_expand(true);
291 		return true;
292 
293 	case TREE_EXPAND_LINKS:
294 		cookie_manager_expand(false);
295 		return true;
296 
297 	case TREE_COLLAPSE_ALL:
298 		cookie_manager_contract(true);
299 		return true;
300 
301 	case TREE_COLLAPSE_FOLDERS:
302 		cookie_manager_contract(true);
303 		return true;
304 
305 	case TREE_COLLAPSE_LINKS:
306 		cookie_manager_contract(false);
307 		return true;
308 
309 	case TREE_SELECTION_DELETE:
310 		cookie_manager_keypress(NS_KEY_DELETE_LEFT);
311 		return true;
312 
313 	case TREE_SELECT_ALL:
314 		cookie_manager_keypress(NS_KEY_SELECT_ALL);
315 		return true;
316 
317 	case TREE_CLEAR_SELECTION:
318 		cookie_manager_keypress(NS_KEY_CLEAR_SELECTION);
319 		return true;
320 
321 	case TOOLBAR_BUTTONS:
322 		ro_toolbar_set_display_buttons(cookiew->core.toolbar,
323 			!ro_toolbar_get_display_buttons(cookiew->core.toolbar));
324 		return true;
325 
326 	case TOOLBAR_EDIT:
327 		ro_toolbar_toggle_edit(cookiew->core.toolbar);
328 		return true;
329 
330 	default:
331 		return false;
332 	}
333 
334 	return false;
335 }
336 
337 
338 /**
339  * Creates the window for the cookie tree.
340  *
341  * \return NSERROR_OK on success else appropriate error code on faliure.
342  */
ro_cookie_init(void)343 static nserror ro_cookie_init(void)
344 {
345 	os_error *error;
346 	struct ro_cookie_window *ncwin;
347 	nserror res;
348 	static const struct ns_menu cookie_menu_def = {
349 		"Cookies", {
350 			{ "Cookies", NO_ACTION, 0 },
351 			{ "Cookies.Expand", TREE_EXPAND_ALL, 0 },
352 			{ "Cookies.Expand.All", TREE_EXPAND_ALL, 0 },
353 			{ "Cookies.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
354 			{ "Cookies.Expand.Links", TREE_EXPAND_LINKS, 0 },
355 			{ "Cookies.Collapse", TREE_COLLAPSE_ALL, 0 },
356 			{ "Cookies.Collapse.All", TREE_COLLAPSE_ALL, 0 },
357 			{ "Cookies.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
358 			{ "Cookies.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
359 			{ "Cookies.Toolbars", NO_ACTION, 0 },
360 			{ "_Cookies.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
361 			{ "Cookies.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 },
362 			{ "Selection", TREE_SELECTION, 0 },
363 			{ "Selection.Delete", TREE_SELECTION_DELETE, 0 },
364 			{ "SelectAll", TREE_SELECT_ALL, 0 },
365 			{ "Clear", TREE_CLEAR_SELECTION, 0 },
366 			{ NULL, 0, 0}
367 		}
368 	};
369 
370 	static const struct button_bar_buttons cookies_toolbar_buttons[] = {
371 		{ "delete", TOOLBAR_BUTTON_DELETE, TOOLBAR_BUTTON_NONE, '0', "0"},
372 		{ "expand", TOOLBAR_BUTTON_EXPAND, TOOLBAR_BUTTON_COLLAPSE, '1', "1"},
373 		{ "open", TOOLBAR_BUTTON_OPEN, TOOLBAR_BUTTON_CLOSE, '2', "2"},
374 		{ NULL, TOOLBAR_BUTTON_NONE, TOOLBAR_BUTTON_NONE, '\0', ""}
375 	};
376 
377 	if (cookie_window != NULL) {
378 		return NSERROR_OK;
379 	}
380 
381 	ncwin = calloc(1, sizeof(*ncwin));
382 	if (ncwin == NULL) {
383 		return NSERROR_NOMEM;
384 	}
385 
386 	/* create window from template */
387 	error = xwimp_create_window(dialog_cookie_template, &ncwin->core.wh);
388 	if (error) {
389 		NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
390 		      error->errnum, error->errmess);
391 		ro_warn_user("WimpError", error->errmess);
392 		free(ncwin);
393 		return NSERROR_NOMEM;
394 	}
395 
396 	ro_gui_set_window_title(ncwin->core.wh, messages_get("Cookies"));
397 
398 	ncwin->core.draw = cookie_draw;
399 	ncwin->core.key = cookie_key;
400 	ncwin->core.mouse = cookie_mouse;
401 	ncwin->core.toolbar_click = cookie_toolbar_click;
402 	ncwin->core.toolbar_save = cookie_toolbar_save;
403 	/* update is not valid untill cookie manager is initialised */
404 	ncwin->core.toolbar_update = NULL;
405 
406 	/* initialise core window */
407 	res = ro_corewindow_init(&ncwin->core,
408 				 cookies_toolbar_buttons,
409 				 nsoption_charp(toolbar_cookies),
410 				 THEME_STYLE_COOKIES_TOOLBAR,
411 				 "HelpCookiesToolbar");
412 	if (res != NSERROR_OK) {
413 		free(ncwin);
414 		return res;
415 	}
416 
417 	res = cookie_manager_init(ncwin->core.cb_table,
418 				  (struct core_window *)ncwin);
419 	if (res != NSERROR_OK) {
420 		free(ncwin);
421 		return res;
422 	}
423 
424 	/* setup toolbar update post cookie manager initialisation */
425 	ncwin->core.toolbar_update = cookie_toolbar_update;
426 	cookie_toolbar_update(&ncwin->core);
427 
428 	/* Build the cookies window menu. */
429 	ncwin->menu = ro_gui_menu_define_menu(&cookie_menu_def);
430 
431 	ro_gui_wimp_event_register_menu(ncwin->core.wh,
432 					ncwin->menu, false, false);
433 	ro_gui_wimp_event_register_menu_prepare(ncwin->core.wh,
434 						cookie_menu_prepare);
435 	ro_gui_wimp_event_register_menu_selection(ncwin->core.wh,
436 						  cookie_menu_select);
437 	ro_gui_wimp_event_register_menu_warning(ncwin->core.wh,
438 						cookie_menu_warning);
439 
440 	/* memoise window so it can be represented when necessary
441 	 * instead of recreating every time.
442 	 */
443 	cookie_window = ncwin;
444 
445 	return NSERROR_OK;
446 }
447 
448 
449 /* exported interface documented in riscos/cookies.h */
ro_gui_cookies_present(const char * search_term)450 nserror ro_gui_cookies_present(const char *search_term)
451 {
452 	nserror res;
453 
454 	res = ro_cookie_init();
455 	if (res == NSERROR_OK) {
456 		NSLOG(netsurf, INFO, "Presenting");
457 		ro_gui_dialog_open_top(cookie_window->core.wh,
458 				       cookie_window->core.toolbar,
459 				       600, 800);
460 		if (search_term != NULL) {
461 			res = cookie_manager_set_search_string(search_term);
462 		}
463 	} else {
464 		NSLOG(netsurf, INFO, "Failed presenting code %d", res);
465 	}
466 
467 	return res;
468 }
469 
470 
471 /* exported interface documented in riscos/cookies.h */
ro_gui_cookies_initialise(void)472 void ro_gui_cookies_initialise(void)
473 {
474 	dialog_cookie_template = ro_gui_dialog_load_template("tree");
475 }
476 
477 
478 /* exported interface documented in riscos/cookies.h */
ro_gui_cookies_finalise(void)479 nserror ro_gui_cookies_finalise(void)
480 {
481 	nserror res;
482 
483 	if (cookie_window == NULL) {
484 		return NSERROR_OK;
485 	}
486 
487 	res = cookie_manager_fini();
488 	if (res == NSERROR_OK) {
489 		res = ro_corewindow_fini(&cookie_window->core);
490 
491 		free(cookie_window);
492 		cookie_window = NULL;
493 	}
494 
495 	return res;
496 }
497 
498 
499 /* exported interface documented in riscos/cookies.h */
ro_gui_cookies_check_window(wimp_w wh)500 bool ro_gui_cookies_check_window(wimp_w wh)
501 {
502 	if ((cookie_window != NULL) &&
503 	    (cookie_window->core.wh == wh)) {
504 		return true;
505 	}
506 	return false;
507 }
508 
509 
510 /* exported interface documented in riscos/cookies.h */
ro_gui_cookies_check_menu(wimp_menu * menu)511 bool ro_gui_cookies_check_menu(wimp_menu *menu)
512 {
513 	if ((cookie_window != NULL) &&
514 	    (cookie_window->menu == menu)) {
515 		return true;
516 	}
517 	return false;
518 }
519