1 /*
2  * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
3  * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
4  * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
5  * Copyright 2005 Richard Wilson <info@tinct.net>
6  * Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
7  * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
8  * Copyright 2014 Stephen Fryatt <stevef@netsurf-browser.org>
9  *
10  * This file is part of NetSurf, http://www.netsurf-browser.org/
11  *
12  * NetSurf is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; version 2 of the License.
15  *
16  * NetSurf is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include "utils/config.h"
26 
27 #include <assert.h>
28 #include <stddef.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <oslib/colourtrans.h>
32 #include <oslib/osfile.h>
33 #include <oslib/osgbpb.h>
34 #include <oslib/osspriteop.h>
35 #include <oslib/wimp.h>
36 
37 #include "utils/nsoption.h"
38 #include "utils/log.h"
39 #include "utils/messages.h"
40 #include "utils/nsurl.h"
41 #include "desktop/version.h"
42 #include "desktop/searchweb.h"
43 #include "netsurf/browser_window.h"
44 
45 #include "riscos/configure.h"
46 #include "riscos/cookies.h"
47 #include "riscos/dialog.h"
48 #include "riscos/local_history.h"
49 #include "riscos/global_history.h"
50 #include "riscos/gui.h"
51 #include "riscos/window.h"
52 #include "riscos/hotlist.h"
53 #include "riscos/pageinfo.h"
54 #include "riscos/menus.h"
55 #include "riscos/save.h"
56 #include "riscos/toolbar.h"
57 #include "riscos/url_complete.h"
58 #include "riscos/url_suggest.h"
59 #include "riscos/wimp.h"
60 #include "riscos/wimp_event.h"
61 #include "riscos/wimputils.h"
62 
63 #define ICON_ZOOM_VALUE 1
64 #define ICON_ZOOM_DEC 2
65 #define ICON_ZOOM_INC 3
66 #define ICON_ZOOM_FRAMES 5
67 #define ICON_ZOOM_CANCEL 7
68 #define ICON_ZOOM_OK 8
69 
70 /*	The maximum number of persistent dialogues
71 */
72 #define MAX_PERSISTENT 64
73 
74 
75 wimp_w dialog_info, dialog_saveas,
76 	dialog_zoom, dialog_pageinfo, dialog_objinfo, dialog_tooltip,
77 	dialog_warning,
78 	dialog_folder, dialog_entry, dialog_search, dialog_print,
79 	dialog_url_complete, dialog_openurl;
80 
81 struct gui_window *ro_gui_current_zoom_gui;
82 
83 
84 /*	A simple mapping of parent and child
85 */
86 static struct {
87 	wimp_w dialog;
88 	wimp_w parent;
89 } persistent_dialog[MAX_PERSISTENT];
90 
91 
92 static bool ro_gui_dialog_open_url_init(void);
93 static bool ro_gui_dialog_openurl_apply(wimp_w w);
94 static bool ro_gui_dialog_open_url_menu_prepare(wimp_w w, wimp_i i,
95 		wimp_menu *menu, wimp_pointer *pointer);
96 
97 static bool ro_gui_dialog_zoom_apply(wimp_w w);
98 
99 /**
100  * Load and create dialogs from template file.
101  */
102 
ro_gui_dialog_init(void)103 void ro_gui_dialog_init(void)
104 {
105 	/* warning dialog */
106 	dialog_warning = ro_gui_dialog_create("warning");
107 	ro_gui_wimp_event_register_ok(dialog_warning, ICON_WARNING_CONTINUE,
108 			NULL);
109 	ro_gui_wimp_event_set_help_prefix(dialog_warning, "HelpWarning");
110 
111 	/* tooltip for history */
112 	dialog_tooltip = ro_gui_dialog_create("tooltip");
113 
114 	/* configure window */
115 	ro_gui_configure_initialise();
116 
117 	/* theme installation */
118 	dialog_theme_install = ro_gui_dialog_create("theme_inst");
119 	ro_gui_wimp_event_register_cancel(dialog_theme_install,
120 			ICON_THEME_INSTALL_CANCEL);
121 	ro_gui_wimp_event_register_ok(dialog_theme_install,
122 			ICON_THEME_INSTALL_INSTALL,
123 			ro_gui_theme_install_apply);
124 	ro_gui_wimp_event_set_help_prefix(dialog_theme_install, "HelpThemeInst");
125 
126 	/* search */
127 	ro_gui_search_init();
128 
129 	/* print */
130 	ro_gui_print_init();
131 
132 	/* about us */
133 	dialog_info = ro_gui_dialog_create("info");
134 	ro_gui_set_icon_string(dialog_info, 4, netsurf_version, true);
135 	ro_gui_wimp_event_set_help_prefix(dialog_info, "HelpAppInfo");
136 
137 	/* page info */
138 	dialog_pageinfo = ro_gui_dialog_create("pageinfo");
139 	ro_gui_wimp_event_set_help_prefix(dialog_pageinfo, "HelpPageInfo");
140 
141 	/* object info */
142 	dialog_objinfo = ro_gui_dialog_create("objectinfo");
143 	ro_gui_wimp_event_set_help_prefix(dialog_objinfo, "HelpObjInfo");
144 
145 	/* save as */
146 	dialog_saveas = ro_gui_saveas_create("saveas");
147 	ro_gui_wimp_event_register_button(dialog_saveas, ICON_SAVE_ICON,
148 			ro_gui_save_start_drag);
149 	ro_gui_wimp_event_register_text_field(dialog_saveas, ICON_SAVE_PATH);
150 	ro_gui_wimp_event_register_cancel(dialog_saveas, ICON_SAVE_CANCEL);
151 	ro_gui_wimp_event_register_ok(dialog_saveas, ICON_SAVE_OK,
152 			ro_gui_save_ok);
153 	ro_gui_wimp_event_set_help_prefix(dialog_saveas, "HelpSaveAs");
154 
155 	/* url suggestion */
156 	dialog_url_complete = ro_gui_dialog_create("url_suggest");
157 	ro_gui_wimp_event_register_mouse_click(dialog_url_complete,
158 			ro_gui_url_complete_click);
159 	ro_gui_wimp_event_register_pointer_entering_window(dialog_url_complete,
160 			ro_gui_url_complete_entering);
161 	ro_gui_wimp_event_register_redraw_window(dialog_url_complete,
162 			ro_gui_url_complete_redraw);
163 	ro_gui_wimp_event_set_help_prefix(dialog_url_complete, "HelpAutoURL");
164 
165 	/* open URL */
166 	ro_gui_dialog_open_url_init();
167 
168 	/* scale view */
169 	dialog_zoom = ro_gui_dialog_create("zoom");
170 	ro_gui_wimp_event_register_numeric_field(dialog_zoom, ICON_ZOOM_VALUE,
171 			ICON_ZOOM_INC, ICON_ZOOM_DEC, 10, 1600, 10, 0);
172 	ro_gui_wimp_event_register_checkbox(dialog_zoom, ICON_ZOOM_FRAMES);
173 	ro_gui_wimp_event_register_cancel(dialog_zoom, ICON_ZOOM_CANCEL);
174 	ro_gui_wimp_event_register_ok(dialog_zoom, ICON_ZOOM_OK,
175 			ro_gui_dialog_zoom_apply);
176 	ro_gui_wimp_event_set_help_prefix(dialog_zoom, "HelpScaleView");
177 
178 	/* core window based initialisation done last to allow any
179 	 * associated dialogues to be set up first.
180 	 */
181 
182 	/* hotlist window */
183 	ro_gui_hotlist_initialise();
184 
185 	/* local history window */
186 	ro_gui_local_history_initialise();
187 
188 	/* global history window */
189 	ro_gui_global_history_initialise();
190 
191 	/* cookies window */
192 	ro_gui_cookies_initialise();
193 
194 	/* page info window */
195 	ro_gui_pageinfo_initialise();
196 }
197 
198 
199 /**
200  * Create a window from a template.
201  *
202  * \param  template_name  name of template to load
203  * \return  window handle
204  *
205  * Exits through die() on error.
206  */
207 
ro_gui_dialog_create(const char * template_name)208 wimp_w ro_gui_dialog_create(const char *template_name)
209 {
210 	wimp_window *window;
211 	wimp_w w;
212 	os_error *error;
213 
214 	window = ro_gui_dialog_load_template(template_name);
215 
216 	/* create window */
217 	window->sprite_area = gui_sprites;
218 	error = xwimp_create_window(window, &w);
219 	if (error) {
220 		NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
221 		      error->errnum, error->errmess);
222 		xwimp_close_template();
223 		die(error->errmess);
224 	}
225 
226 	/* the window definition is copied by the wimp and may be freed */
227 	free(window);
228 
229 	return w;
230 }
231 
232 
233 /**
234  * Load a template without creating a window.
235  *
236  * \param  template_name  name of template to load
237  * \return  window block
238  *
239  * Exits through die() on error.
240  */
241 
ro_gui_dialog_load_template(const char * template_name)242 wimp_window * ro_gui_dialog_load_template(const char *template_name)
243 {
244 	char name[20];
245 	int context, window_size, data_size;
246 	char *data;
247 	wimp_window *window;
248 	os_error *error;
249 
250 	/* Template names must be <= 11 chars long */
251 	assert(strlen(template_name) <= 11);
252 
253 	/* wimp_load_template won't accept a const char * */
254 	strncpy(name, template_name, sizeof name);
255 
256 	/* find required buffer sizes */
257 	error = xwimp_load_template(wimp_GET_SIZE, 0, 0, wimp_NO_FONTS,
258 			name, 0, &window_size, &data_size, &context);
259 	if (error) {
260 		NSLOG(netsurf, INFO, "xwimp_load_template: 0x%x: %s",
261 		      error->errnum, error->errmess);
262 		xwimp_close_template();
263 		die(error->errmess);
264 	}
265 	if (!context) {
266 		NSLOG(netsurf, INFO, "template '%s' missing", template_name);
267 		xwimp_close_template();
268 		die("Template");
269 	}
270 
271 	/* allocate space for indirected data and temporary window buffer */
272 	data = malloc(data_size);
273 	window = malloc(window_size);
274 	if (!data || !window) {
275 		xwimp_close_template();
276 		die("NoMemory");
277 	}
278 
279 	/* load template */
280 	error = xwimp_load_template(window, data, data + data_size,
281 			wimp_NO_FONTS, name, 0, 0, 0, 0);
282 	if (error) {
283 		NSLOG(netsurf, INFO, "xwimp_load_template: 0x%x: %s",
284 		      error->errnum, error->errmess);
285 		xwimp_close_template();
286 		die(error->errmess);
287 	}
288 
289 	return window;
290 }
291 
292 
293 /**
294  * Open a dialog box, centred on the screen.
295  */
296 
ro_gui_dialog_open(wimp_w w)297 void ro_gui_dialog_open(wimp_w w)
298 {
299 	int screen_x, screen_y, dx, dy;
300 	wimp_window_state state;
301 	os_error *error;
302 
303 	/* find screen centre in os units */
304 	ro_gui_screen_size(&screen_x, &screen_y);
305 	screen_x /= 2;
306 	screen_y /= 2;
307 
308 	/* centre and open */
309 	state.w = w;
310 	error = xwimp_get_window_state(&state);
311 	if (error) {
312 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
313 		      error->errnum, error->errmess);
314 		ro_warn_user("WimpError", error->errmess);
315 		return;
316 	}
317 	dx = (state.visible.x1 - state.visible.x0) / 2;
318 	dy = (state.visible.y1 - state.visible.y0) / 2;
319 	state.visible.x0 = screen_x - dx;
320 	state.visible.x1 = screen_x + dx;
321 	state.visible.y0 = screen_y - dy;
322 	state.visible.y1 = screen_y + dy;
323 	state.next = wimp_TOP;
324 	ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
325 
326 	/*	Set the caret position */
327 	ro_gui_set_caret_first(w);
328 }
329 
330 
331 /**
332  * Close a dialog box.
333  */
334 
ro_gui_dialog_close(wimp_w close)335 void ro_gui_dialog_close(wimp_w close)
336 {
337 	int i;
338 	wimp_caret caret;
339 	wimp_w parent = (wimp_w)-1;
340 	os_error *error;
341 
342 	/* Check if we're a persistent window */
343 	for (i = 0; i < MAX_PERSISTENT; i++) {
344 		if (persistent_dialog[i].dialog == close) {
345 			/* We are => invalidate record */
346 			if (persistent_dialog[i].parent != NULL) {
347 				parent = persistent_dialog[i].parent;
348 			}
349 			persistent_dialog[i].parent = NULL;
350 			persistent_dialog[i].dialog = NULL;
351 			break;
352 		}
353 	}
354 
355 	/* Close any child windows */
356 	ro_gui_dialog_close_persistent(close);
357 
358 	/*	Give the caret back to the parent window. This code relies on
359 		the fact that only tree windows and browser windows open
360 		persistent dialogues, as the caret gets placed to no icon.
361 	*/
362 	error = xwimp_get_caret_position(&caret);
363 	if (error) {
364 		NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x: %s",
365 		      error->errnum, error->errmess);
366 		ro_warn_user("WimpError", error->errmess);
367 	} else if (caret.w == close) {
368 		/* Check if we are a persistent window */
369 		if (i < MAX_PERSISTENT) {
370 			error = xwimp_set_caret_position(
371 					parent,
372 					wimp_ICON_WINDOW, -100, -100,
373 					32, -1);
374 			/* parent may have been closed first */
375 			if ((error) && (error->errnum != 0x287)) {
376 				NSLOG(netsurf, INFO,
377 				      "xwimp_set_caret_position: 0x%x: %s",
378 				      error->errnum,
379 				      error->errmess);
380 				ro_warn_user("WimpError", error->errmess);
381 			}
382 		}
383 	}
384 
385 	error = xwimp_close_window(close);
386 	if (error) {
387 		NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
388 		      error->errnum, error->errmess);
389 		ro_warn_user("WimpError", error->errmess);
390 	}
391 }
392 
393 
394 /**
395  * Moves a window to the top of the stack.
396  *
397  * If the window is currently closed then:
398  *
399  *  * The window is opened in the centre of the screen (at the supplied size)
400  *  * Any toolbar editing session is stopped
401  *  * The scroll position is set to the top of the window
402  *
403  * If the window is currently open then:
404  *
405  *  * The window is brought to the top of the stack
406  *
407  * \param w		the window to show
408  * \param toolbar	the toolbar to consider
409  * \param width		the window width if it is currently closed (or 0 to retain)
410  * \param height	the window height if it is currently closed (or 0 to retain)
411  * \return true if the window was previously open
412  */
ro_gui_dialog_open_top(wimp_w w,struct toolbar * toolbar,int width,int height)413 bool ro_gui_dialog_open_top(wimp_w w, struct toolbar *toolbar,
414 		int width, int height) {
415 	os_error *error;
416 	int screen_width, screen_height;
417 	wimp_window_state state;
418 	bool open;
419 
420 	state.w = w;
421 	error = xwimp_get_window_state(&state);
422 	if (error) {
423 		ro_warn_user("WimpError", error->errmess);
424 		return false;
425 	}
426 
427 	/* if we're open we jump to the top of the stack, if not then we
428 	 * open in the centre of the screen. */
429 	open = state.flags & wimp_WINDOW_OPEN;
430 	if (!open) {
431 		int dimension;
432 		int scroll_width;
433 		/* cancel any editing */
434 		if (ro_toolbar_get_editing(toolbar))
435 			ro_toolbar_toggle_edit(toolbar);
436 
437 		/* move to the centre */
438 		ro_gui_screen_size(&screen_width, &screen_height);
439 		dimension = ((width == 0) ?
440 				(state.visible.x1 - state.visible.x0) : width);
441 		scroll_width = ro_get_vscroll_width(w);
442 		state.visible.x0 = (screen_width - (dimension + scroll_width)) / 2;
443 		state.visible.x1 = state.visible.x0 + dimension;
444 		dimension = ((height == 0) ?
445 				(state.visible.y1 - state.visible.y0) : height);
446 		state.visible.y0 = (screen_height - dimension) / 2;
447 		state.visible.y1 = state.visible.y0 + dimension;
448 		state.xscroll = 0;
449 		state.yscroll = 0;
450 		if (toolbar)
451 			state.yscroll = ro_toolbar_height(toolbar);
452 	}
453 
454 	/* open the window at the top of the stack */
455 	state.next = wimp_TOP;
456 	ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
457 	return open;
458 }
459 
460 
461 /**
462  * Open window at the location of the pointer.
463  */
464 
ro_gui_dialog_open_at_pointer(wimp_w w)465 void ro_gui_dialog_open_at_pointer(wimp_w w)
466 {
467 	wimp_pointer ptr;
468 	os_error *error;
469 
470 	/* get the pointer position */
471 	error = xwimp_get_pointer_info(&ptr);
472 	if (error) {
473 		NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
474 		      error->errnum, error->errmess);
475 		ro_warn_user("WimpError", error->errmess);
476 		return;
477 	}
478 
479 	ro_gui_dialog_open_xy(w, ptr.pos.x - 64, ptr.pos.y);
480 }
481 
482 
483 /**
484  * Open window at a specified location.
485  */
486 
ro_gui_dialog_open_xy(wimp_w w,int x,int y)487 void ro_gui_dialog_open_xy(wimp_w w, int x, int y)
488 {
489 	wimp_window_state state;
490 	os_error *error;
491 	int dx, dy;
492 
493 	/* move the window */
494 	state.w = w;
495 	error = xwimp_get_window_state(&state);
496 	if (error) {
497 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
498 		      error->errnum, error->errmess);
499 		ro_warn_user("WimpError", error->errmess);
500 		return;
501 	}
502 	dx = (state.visible.x1 - state.visible.x0);
503 	dy = (state.visible.y1 - state.visible.y0);
504 	state.visible.x0 = x;
505 	state.visible.x1 = x + dx;
506 	state.visible.y0 = y - dy;
507 	state.visible.y1 = y;
508 
509 	/* if the window is already open, close it first so that it opens fully
510 	 * on screen */
511 	error = xwimp_close_window(w);
512 	if (error) {
513 		NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
514 		      error->errnum, error->errmess);
515 		ro_warn_user("WimpError", error->errmess);
516 		return;
517 	}
518 
519 	/* open the window at the top of the stack */
520 	state.next = wimp_TOP;
521 	ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
522 }
523 
524 
525 /**
526  * Opens a window at the centre of either another window or the screen
527  *
528  * /param parent the parent window (NULL for centre of screen)
529  * /param child the child window
530  */
ro_gui_dialog_open_centre_parent(wimp_w parent,wimp_w child)531 static void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child)
532 {
533 	os_error *error;
534 	wimp_window_state state;
535 	int mid_x, mid_y;
536 	int dimension, scroll_width;
537 
538 	/* get the parent window state */
539 	if (parent) {
540 		state.w = parent;
541 		error = xwimp_get_window_state(&state);
542 		if (error) {
543 			NSLOG(netsurf, INFO,
544 			      "xwimp_get_window_state: 0x%x: %s",
545 			      error->errnum,
546 			      error->errmess);
547 			ro_warn_user("WimpError", error->errmess);
548 			return;
549 		}
550 		scroll_width = ro_get_vscroll_width(parent);
551 		mid_x = (state.visible.x0 + state.visible.x1 + scroll_width);
552 		mid_y = (state.visible.y0 + state.visible.y1);
553 	} else {
554 		ro_gui_screen_size(&mid_x, &mid_y);
555 	}
556 	mid_x /= 2;
557 	mid_y /= 2;
558 
559 	/* get the child window state */
560 	state.w = child;
561 	error = xwimp_get_window_state(&state);
562 	if (error) {
563 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
564 		      error->errnum, error->errmess);
565 		ro_warn_user("WimpError", error->errmess);
566 		return;
567 	}
568 
569 	/* move to the centre of the parent at the top of the stack */
570 	dimension = state.visible.x1 - state.visible.x0;
571 	scroll_width = ro_get_vscroll_width(parent);
572 	state.visible.x0 = mid_x - (dimension + scroll_width) / 2;
573 	state.visible.x1 = state.visible.x0 + dimension;
574 	dimension = state.visible.y1 - state.visible.y0;
575 	state.visible.y0 = mid_y - dimension / 2;
576 	state.visible.y1 = state.visible.y0 + dimension;
577 	state.next = wimp_TOP;
578 	ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
579 }
580 
581 
582 /**
583  * Open a persistent dialog box relative to the pointer.
584  *
585  * \param  parent   the owning window (NULL for no owner)
586  * \param  w	    the dialog window
587  * \param  pointer  open the window at the pointer (centre of the parent
588  *		    otherwise)
589  */
590 
ro_gui_dialog_open_persistent(wimp_w parent,wimp_w w,bool pointer)591 void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer) {
592 
593 	if (pointer) {
594 		ro_gui_dialog_open_at_pointer(w);
595 	} else {
596 		ro_gui_dialog_open_centre_parent(parent, w);
597 	}
598 
599 	/* todo: use wimp_event definitions rather than special cases */
600 	if ((w == dialog_pageinfo) || (w == dialog_objinfo))
601 		ro_gui_wimp_update_window_furniture(w, wimp_WINDOW_CLOSE_ICON,
602 				wimp_WINDOW_CLOSE_ICON);
603 	ro_gui_dialog_add_persistent(parent, w);
604 	ro_gui_set_caret_first(w);
605 }
606 
607 
ro_gui_dialog_add_persistent(wimp_w parent,wimp_w w)608 void ro_gui_dialog_add_persistent(wimp_w parent, wimp_w w) {
609 	int i;
610 
611 	/* all persistant windows have a back icon */
612 	ro_gui_wimp_update_window_furniture(w, wimp_WINDOW_BACK_ICON,
613 			wimp_WINDOW_BACK_ICON);
614 
615 	/*	Add a mapping
616 	*/
617 	if ((parent == NULL) || (parent == wimp_ICON_BAR))
618 		return;
619 	for (i = 0; i < MAX_PERSISTENT; i++) {
620 		if (persistent_dialog[i].dialog == NULL ||
621 				persistent_dialog[i].dialog == w) {
622 			persistent_dialog[i].dialog = w;
623 			persistent_dialog[i].parent = parent;
624 			return;
625 		}
626 	}
627 	NSLOG(netsurf, INFO, "Unable to map persistent dialog to parent.");
628 	return;
629 }
630 
631 
632 /**
633  * Close persistent dialogs associated with a window.
634  *
635  * \param  parent  the window to close children of
636  */
637 
ro_gui_dialog_close_persistent(wimp_w parent)638 void ro_gui_dialog_close_persistent(wimp_w parent) {
639 	int	i;
640 	wimp_w	w;
641 
642 	/* Check our mappings.
643 	 *
644 	 * The window handle is copied into w before proceeding, as
645 	 * ro_gui_dialog_close() will NULL persistent_dialog[i].dialog as
646 	 * part of the closing process.  This would mean that the subsequent
647 	 * event dispatch would fail.  (These events are logged to allow
648 	 * side effects to be investigated -- this code hasn't worked before).
649 	 */
650 	for (i = 0; i < MAX_PERSISTENT; i++) {
651 		if (persistent_dialog[i].parent == parent &&
652 				persistent_dialog[i].dialog != NULL) {
653 			w = persistent_dialog[i].dialog;
654 			ro_gui_dialog_close(w);
655 			if (ro_gui_wimp_event_close_window(w))
656 				NSLOG(netsurf, INFO,
657 				      "Persistent dialog close event: 0x%x",
658 				      (unsigned)w);
659 			persistent_dialog[i].parent = NULL;
660 			persistent_dialog[i].dialog = NULL;
661 		}
662 	}
663 }
664 
665 
666 /**
667  * Save the current options.
668  */
669 
ro_gui_save_options(void)670 void ro_gui_save_options(void)
671 {
672 	nsoption_write("<NetSurf$ChoicesSave>", NULL, NULL);
673 }
674 
ro_gui_dialog_zoom_apply(wimp_w w)675 bool ro_gui_dialog_zoom_apply(wimp_w w)
676 {
677 	unsigned int scale;
678 
679 	scale = atoi(ro_gui_get_icon_string(w, ICON_ZOOM_VALUE));
680 	ro_gui_window_set_scale(ro_gui_current_zoom_gui, scale * 0.01);
681 	return true;
682 }
683 
684 
685 /**
686  * Prepares the Scale view dialog.
687  */
688 
ro_gui_dialog_prepare_zoom(struct gui_window * g)689 void ro_gui_dialog_prepare_zoom(struct gui_window *g)
690 {
691 	char scale_buffer[8];
692 	sprintf(scale_buffer, "%.0f", browser_window_get_scale(g->bw) * 100);
693 	ro_gui_set_icon_string(dialog_zoom, ICON_ZOOM_VALUE, scale_buffer, true);
694 	ro_gui_set_icon_selected_state(dialog_zoom, ICON_ZOOM_FRAMES, true);
695 	ro_gui_set_icon_shaded_state(dialog_zoom, ICON_ZOOM_FRAMES, true);
696 	ro_gui_current_zoom_gui = g;
697 	ro_gui_wimp_event_memorise(dialog_zoom);
698 }
699 
700 /**
701  * Update the Scale View dialog to reflect the current window settings
702  *
703  * \param g  the gui_window to update for
704  */
ro_gui_dialog_update_zoom(struct gui_window * g)705 void ro_gui_dialog_update_zoom(struct gui_window *g) {
706 	if (g == ro_gui_current_zoom_gui)
707 		ro_gui_dialog_prepare_zoom(g);
708 }
709 
710 
711 /**
712  * Create the Open URL dialogue, allocating storage for the URL field icon
713  * as we go.
714  *
715  * \return		true on success; false on failure (although errors with
716  *			the templates or memory allocation will exit via die()).
717  */
718 
ro_gui_dialog_open_url_init(void)719 static bool ro_gui_dialog_open_url_init(void)
720 {
721 	wimp_window	*definition;
722 	char		*buffer;
723 	os_error	*error;
724 
725 	definition = ro_gui_dialog_load_template("open_url");
726 
727 	/* _load_template() should die on any error, so we trust its data. */
728 
729 	assert(definition != NULL);
730 
731 	/* Create the dialogue, with modifications. */
732 
733 	if ((definition->icons[ICON_OPENURL_URL].flags & wimp_ICON_INDIRECTED)
734 			== 0) {
735 		NSLOG(netsurf, INFO, "open_url URL icon not indirected");
736 		xwimp_close_template();
737 		die("Template");
738 	}
739 
740 	buffer = malloc(RO_GUI_MAX_URL_SIZE);
741 	if (buffer == NULL) {
742 		xwimp_close_template();
743 		die("NoMemory");
744 	}
745 
746 	definition->icons[ICON_OPENURL_URL].data.indirected_text.text = buffer;
747 	definition->icons[ICON_OPENURL_URL].data.indirected_text.size =
748 			RO_GUI_MAX_URL_SIZE;
749 	definition->sprite_area = gui_sprites;
750 
751 	error = xwimp_create_window(definition, &dialog_openurl);
752 	if (error != NULL) {
753 		NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
754 		      error->errnum, error->errmess);
755 		xwimp_close_template();
756 		die(error->errmess);
757 	}
758 
759 	free(definition);
760 
761 	ro_gui_wimp_event_register_menu_gright(dialog_openurl, ICON_OPENURL_URL,
762 			ICON_OPENURL_MENU, ro_gui_url_suggest_menu);
763 	ro_gui_wimp_event_register_cancel(dialog_openurl, ICON_OPENURL_CANCEL);
764 	ro_gui_wimp_event_register_ok(dialog_openurl, ICON_OPENURL_OPEN,
765 			ro_gui_dialog_openurl_apply);
766 	ro_gui_wimp_event_register_menu_prepare(dialog_openurl,
767 			ro_gui_dialog_open_url_menu_prepare);
768 	ro_gui_wimp_event_set_help_prefix(dialog_openurl, "HelpOpenURL");
769 
770 	return true;
771 }
772 
773 
774 
ro_gui_dialog_openurl_apply(wimp_w w)775 bool ro_gui_dialog_openurl_apply(wimp_w w)
776 {
777 	nserror res;
778 	const char *url_s;
779 	nsurl *url;
780 
781 	url_s = ro_gui_get_icon_string(w, ICON_OPENURL_URL);
782 
783 	res = search_web_omni(url_s, SEARCH_WEB_OMNI_NONE, &url);
784 
785 	if (res == NSERROR_OK) {
786 		res = browser_window_create(BW_CREATE_HISTORY,
787 					    url,
788 					    NULL,
789 					    NULL,
790 					    NULL);
791 		nsurl_unref(url);
792 	}
793 
794 	if (res != NSERROR_OK) {
795 		ro_warn_user(messages_get_errorcode(res), 0);
796 		return false;
797 	}
798 
799 	return true;
800 }
801 
802 
803 /**
804  * Prepares the Open URL dialog.
805  */
806 
ro_gui_dialog_prepare_open_url(void)807 void ro_gui_dialog_prepare_open_url(void)
808 {
809 	ro_gui_set_icon_string(dialog_openurl, ICON_OPENURL_URL, "", true);
810 	ro_gui_set_icon_shaded_state(dialog_openurl,
811 			ICON_OPENURL_MENU, !ro_gui_url_suggest_prepare_menu());
812 	ro_gui_wimp_event_memorise(dialog_openurl);
813 }
814 
815 
816 /**
817  * Callback to prepare menus in the Open URL dialog.  At present, this
818  * only has to handle the URL Suggestion pop-up.
819  *
820  * \param w		The window handle owning the menu.
821  * \param i		The icon handle owning the menu.
822  * \param *menu		The menu to be prepared.
823  * \param *pointer	The associated mouse click event block, or NULL
824  *			on an Adjust-click re-opening.
825  * \return		true if the event was handled; false if not.
826  */
827 
ro_gui_dialog_open_url_menu_prepare(wimp_w w,wimp_i i,wimp_menu * menu,wimp_pointer * pointer)828 bool ro_gui_dialog_open_url_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
829 		wimp_pointer *pointer)
830 {
831 	if (menu != ro_gui_url_suggest_menu || i != ICON_OPENURL_MENU)
832 		return false;
833 
834 	if (pointer != NULL)
835 		return ro_gui_url_suggest_prepare_menu();
836 
837 	return true;
838 }
839