1 /*
2  * Copyright 2004, 2005 Richard Wilson <info@tinct.net>
3  * Copyright 2011-2014 Stephen Fryatt <stevef@netsurf-browser.org>
4  *
5  * This file is part of NetSurf, http://www.netsurf-browser.org/
6  *
7  * NetSurf is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * NetSurf is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * \file
22  * RISC OS URL bar implementation.
23  *
24  * The treeview resources are retrieved from resource url necessitating
25  * the use of the hlcache content interface.
26  */
27 
28 #include <stddef.h>
29 #include "oslib/wimp.h"
30 
31 #include "utils/log.h"
32 #include "utils/messages.h"
33 #include "netsurf/browser_window.h"
34 #include "netsurf/plotters.h"
35 #include "netsurf/content.h"
36 #include "content/hlcache.h"
37 
38 #include "riscos/gui.h"
39 #include "riscos/hotlist.h"
40 #include "riscos/url_suggest.h"
41 #include "riscos/wimp.h"
42 #include "riscos/wimp_event.h"
43 #include "riscos/window.h"
44 #include "riscos/ucstables.h"
45 #include "riscos/filetype.h"
46 #include "riscos/gui/url_bar.h"
47 
48 #define URLBAR_HEIGHT 52
49 #define URLBAR_FAVICON_SIZE 16
50 #define URLBAR_HOTLIST_SIZE 17
51 #define URLBAR_PGINFO_WIDTH ((26) * 2)
52 #define URLBAR_FAVICON_WIDTH ((5 + URLBAR_FAVICON_SIZE + 5) * 2)
53 #define URLBAR_HOTLIST_WIDTH ((5 + URLBAR_HOTLIST_SIZE + 5) * 2)
54 #define URLBAR_MIN_WIDTH 52
55 #define URLBAR_GRIGHT_GUTTER 8
56 
57 #define URLBAR_PGINFO_NAME_LENGTH 12
58 #define URLBAR_FAVICON_NAME_LENGTH 12
59 
60 struct url_bar {
61 	/** The applied theme (or NULL to use the default) */
62 	struct theme_descriptor	*theme;
63 
64 	/** The widget dimensions. */
65 	int			x_min, y_min;
66 
67 	/** The window and icon details. */
68 	wimp_w			window;
69 	os_box			extent;
70 	osspriteop_area		*sprites;
71 
72 	wimp_i			container_icon;
73 
74 	bool			hidden;
75 	bool			display;
76 	bool			shaded;
77 
78 	struct {
79 		char		sprite[URLBAR_PGINFO_NAME_LENGTH];
80 		os_box		extent;
81 	} pginfo;
82 
83 	struct {
84 		char		sprite[URLBAR_FAVICON_NAME_LENGTH];
85 		int		type;
86 		struct hlcache_handle *content;
87 		os_box		extent;
88 		os_coord	offset;
89 		int		width;
90 		int		height;
91 	} favicon;
92 
93 	struct {
94 		wimp_i		icon;
95 		char		*buffer;
96 		size_t		size;
97 		char		*buffer_utf8;
98 	} text;
99 
100 	struct {
101 		wimp_i		icon;
102 		int		x;
103 		int		y;
104 	} suggest;
105 
106 	struct {
107 		bool			set;
108 		os_box			extent;
109 		os_coord		offset;
110 	} hotlist;
111 };
112 
113 static char text_validation[] = "Pptr_write;KN";
114 static char suggest_icon[] = "gright";
115 static char suggest_validation[] = "R5;Sgright,pgright";
116 static char null_text_string[] = "";
117 
118 /** Treeview content resource data */
119 struct url_bar_resource {
120 	const char *url;
121 	struct hlcache_handle *c;
122 	int height;
123 	bool ready;
124 };
125 
126 enum url_bar_resource_id {
127 	URLBAR_RES_HOTLIST_ADD = 0,
128 	URLBAR_RES_HOTLIST_REMOVE,
129 	URLBAR_RES_LAST
130 };
131 
132 /** Treeview content resources */
133 static struct url_bar_resource url_bar_res[URLBAR_RES_LAST] = {
134 	{ "resource:icons/hotlist-add.png", NULL, 0, false },
135 	{ "resource:icons/hotlist-rmv.png", NULL, 0, false }
136 };
137 
138 
139 /**
140  * Position the icons in the URL bar to take account of the currently
141  * configured extent.
142  *
143  * \param *url_bar The URL bar to update.
144  * \param full true to resize everything;
145  *             false to move only the right-hand end of the bar.
146  * \return true if successful; else false.
147  */
ro_gui_url_bar_icon_resize(struct url_bar * url_bar,bool full)148 static bool ro_gui_url_bar_icon_resize(struct url_bar *url_bar, bool full)
149 {
150 	int x0, y0, x1, y1;
151 	int centre;
152 	os_error *error;
153 	os_coord eig = {1, 1};
154 	wimp_caret caret;
155 
156 	if ((url_bar == NULL) ||
157 	    (url_bar->window == NULL)) {
158 		return false;
159 	}
160 
161 	/* calculate 1px in OS units */
162 	ro_convert_pixels_to_os_units(&eig, (os_mode) -1);
163 
164 	/* The vertical centre line of the widget's extent. */
165 	centre = url_bar->extent.y0 +
166 		(url_bar->extent.y1 - url_bar->extent.y0) / 2;
167 
168 	/* Position the container icon. */
169 	if (url_bar->container_icon != -1) {
170 		x0 = url_bar->extent.x0;
171 		x1 = url_bar->extent.x1 -
172 			url_bar->suggest.x - URLBAR_GRIGHT_GUTTER;
173 
174 		y0 = centre - (URLBAR_HEIGHT / 2);
175 		y1 = y0 + URLBAR_HEIGHT;
176 
177 		error = xwimp_resize_icon(url_bar->window,
178 					  url_bar->container_icon,
179 					  x0, y0, x1, y1);
180 		if (error != NULL) {
181 			NSLOG(netsurf, INFO,
182 			      "xwimp_resize_icon: 0x%x: %s",
183 			      error->errnum, error->errmess);
184 			ro_warn_user("WimpError", error->errmess);
185 			url_bar->container_icon = -1;
186 			return false;
187 		}
188 	}
189 
190 	/* Position the URL Suggest icon. */
191 	if (url_bar->suggest.icon != -1) {
192 		x0 = url_bar->extent.x1 - url_bar->suggest.x;
193 		x1 = url_bar->extent.x1;
194 
195 		y0 = centre - (url_bar->suggest.y / 2);
196 		y1 = y0 + url_bar->suggest.y;
197 
198 		error = xwimp_resize_icon(url_bar->window,
199 					  url_bar->suggest.icon,
200 					  x0, y0, x1, y1);
201 		if (error != NULL) {
202 			NSLOG(netsurf, INFO,
203 			      "xwimp_resize_icon: 0x%x: %s",
204 			      error->errnum, error->errmess);
205 			ro_warn_user("WimpError", error->errmess);
206 			url_bar->suggest.icon = -1;
207 			return false;
208 		}
209 	}
210 
211 	/* Position the Text icon. */
212 	if (url_bar->text.icon != -1) {
213 		x0 = url_bar->extent.x0 + URLBAR_PGINFO_WIDTH + URLBAR_FAVICON_WIDTH;
214 		x1 = url_bar->extent.x1 - eig.x - URLBAR_HOTLIST_WIDTH -
215 			url_bar->suggest.x - URLBAR_GRIGHT_GUTTER;
216 
217 		y0 = centre - (URLBAR_HEIGHT / 2) + eig.y;
218 		y1 = y0 + URLBAR_HEIGHT - 2 * eig.y;
219 
220 		error = xwimp_resize_icon(url_bar->window,
221 					  url_bar->text.icon,
222 					  x0, y0, x1, y1);
223 		if (error != NULL) {
224 			NSLOG(netsurf, INFO,
225 			      "xwimp_resize_icon: 0x%x: %s",
226 			      error->errnum, error->errmess);
227 			ro_warn_user("WimpError", error->errmess);
228 			url_bar->text.icon = -1;
229 			return false;
230 		}
231 
232 		if (xwimp_get_caret_position(&caret) == NULL) {
233 			if ((caret.w == url_bar->window) &&
234 			    (caret.i == url_bar->text.icon)) {
235 				xwimp_set_caret_position(url_bar->window,
236 							 url_bar->text.icon,
237 							 caret.pos.x,
238 							 caret.pos.y,
239 							 -1,
240 							 caret.index);
241 			}
242 		}
243 	}
244 
245 	/* Position the page info icon. */
246 	url_bar->pginfo.extent.x0 = url_bar->extent.x0 + eig.x;
247 	url_bar->pginfo.extent.x1 = url_bar->extent.x0 + URLBAR_PGINFO_WIDTH;
248 	url_bar->pginfo.extent.y0 = centre - (URLBAR_HEIGHT / 2) + eig.y;
249 	url_bar->pginfo.extent.y1 = url_bar->pginfo.extent.y0 + URLBAR_HEIGHT
250 		- 2 * eig.y;
251 
252 	/* Position the Favicon icon. */
253 	url_bar->favicon.extent.x0 = url_bar->extent.x0 + URLBAR_PGINFO_WIDTH ;
254 	url_bar->favicon.extent.x1 = url_bar->extent.x0 + URLBAR_PGINFO_WIDTH + URLBAR_FAVICON_WIDTH;
255 	url_bar->favicon.extent.y0 = centre - (URLBAR_HEIGHT / 2) + eig.y;
256 	url_bar->favicon.extent.y1 = url_bar->favicon.extent.y0 + URLBAR_HEIGHT
257 		- 2 * eig.y;
258 
259 	/* Position the Hotlist icon. */
260 	url_bar->hotlist.extent.x0 = url_bar->extent.x1 - eig.x -
261 		URLBAR_HOTLIST_WIDTH - url_bar->suggest.x -
262 		URLBAR_GRIGHT_GUTTER;
263 	url_bar->hotlist.extent.x1 = url_bar->hotlist.extent.x0 +
264 		URLBAR_HOTLIST_WIDTH;
265 	url_bar->hotlist.extent.y0 = centre - (URLBAR_HEIGHT / 2) + eig.y;
266 	url_bar->hotlist.extent.y1 = url_bar->hotlist.extent.y0 + URLBAR_HEIGHT
267 		- 2 * eig.y;
268 
269 	url_bar->hotlist.offset.x = ((url_bar->hotlist.extent.x1 -
270 				      url_bar->hotlist.extent.x0) -
271 				     (URLBAR_HOTLIST_SIZE * 2)) / 2;
272 	url_bar->hotlist.offset.y = ((url_bar->hotlist.extent.y1 -
273 				      url_bar->hotlist.extent.y0) -
274 				     (URLBAR_HOTLIST_SIZE * 2)) / 2 - 1;
275 
276 	return true;
277 }
278 
279 
280 /**
281  * Create or delete a URL bar's icons if required to bring it into sync with
282  * the current hidden setting.
283  *
284  * \param *url_bar The URL bar to update.
285  * \return true if successful; else false.
286  */
ro_gui_url_bar_icon_update(struct url_bar * url_bar)287 static bool ro_gui_url_bar_icon_update(struct url_bar *url_bar)
288 {
289 	wimp_icon_create icon;
290 	os_error *error;
291 	bool resize;
292 
293 	if ((url_bar == NULL) ||
294 	    (url_bar->window == NULL)) {
295 		return false;
296 	}
297 
298 	icon.w = url_bar->window;
299 	icon.icon.extent.x0 = 0;
300 	icon.icon.extent.y0 = 0;
301 	icon.icon.extent.x1 = 0;
302 	icon.icon.extent.y1 = 0;
303 
304 	resize = false;
305 
306 	/* Create or delete the container icon. */
307 
308 	if (!url_bar->hidden && url_bar->container_icon == -1) {
309 		icon.icon.flags = wimp_ICON_BORDER |
310 			(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
311 			(wimp_BUTTON_DOUBLE_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT);
312 		error = xwimp_create_icon(&icon, &url_bar->container_icon);
313 		if (error != NULL) {
314 			NSLOG(netsurf, INFO,
315 			      "xwimp_create_icon: 0x%x: %s",
316 			      error->errnum, error->errmess);
317 			ro_warn_user("WimpError", error->errmess);
318 			url_bar->container_icon = -1;
319 			return false;
320 		}
321 
322 		resize = true;
323 	} else if ((url_bar->hidden) &&
324 		   (url_bar->container_icon != -1)) {
325 		error = xwimp_delete_icon(url_bar->window,
326 					  url_bar->container_icon);
327 		if (error != NULL) {
328 			NSLOG(netsurf, INFO,
329 			      "xwimp_delete_icon: 0x%x: %s",
330 			      error->errnum, error->errmess);
331 			ro_warn_user("WimpError", error->errmess);
332 			return false;
333 		}
334 
335 		url_bar->container_icon = -1;
336 	}
337 
338 	/* Create or delete the text icon. */
339 	if (!url_bar->hidden &&
340 	    url_bar->text.icon == -1) {
341 		icon.icon.data.indirected_text.text = url_bar->text.buffer;
342 		icon.icon.data.indirected_text.validation = text_validation;
343 		icon.icon.data.indirected_text.size = url_bar->text.size;
344 		icon.icon.flags = wimp_ICON_TEXT |
345 			wimp_ICON_INDIRECTED |
346 			wimp_ICON_VCENTRED |
347 			wimp_ICON_FILLED |
348 			(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT);
349 
350 		if (url_bar->display) {
351 			icon.icon.flags |= (wimp_BUTTON_NEVER <<
352 					    wimp_ICON_BUTTON_TYPE_SHIFT);
353 		} else {
354 			icon.icon.flags |= (wimp_BUTTON_WRITE_CLICK_DRAG <<
355 					    wimp_ICON_BUTTON_TYPE_SHIFT);
356 		}
357 		error = xwimp_create_icon(&icon, &url_bar->text.icon);
358 		if (error) {
359 			NSLOG(netsurf, INFO,
360 			      "xwimp_create_icon: 0x%x: %s",
361 			      error->errnum, error->errmess);
362 			ro_warn_user("WimpError", error->errmess);
363 			url_bar->text.icon = -1;
364 			return false;
365 		}
366 
367 		resize = true;
368 
369 	} else if (url_bar->hidden &&
370 		   url_bar->text.icon != -1) {
371 		error = xwimp_delete_icon(url_bar->window,
372 					  url_bar->text.icon);
373 		if (error != NULL) {
374 			NSLOG(netsurf, INFO,
375 			      "xwimp_delete_icon: 0x%x: %s",
376 			      error->errnum, error->errmess);
377 			ro_warn_user("WimpError", error->errmess);
378 			return false;
379 		}
380 
381 		url_bar->text.icon = -1;
382 	}
383 
384 	/* Create or delete the suggest icon. */
385 	if (!url_bar->hidden &&
386 	    url_bar->suggest.icon == -1) {
387 		icon.icon.data.indirected_text.text = null_text_string;
388 		icon.icon.data.indirected_text.size = 1;
389 		icon.icon.data.indirected_text.validation = suggest_validation;
390 		icon.icon.flags = wimp_ICON_TEXT |
391 			wimp_ICON_SPRITE |
392 			wimp_ICON_INDIRECTED |
393 			wimp_ICON_HCENTRED |
394 			wimp_ICON_VCENTRED |
395 			(wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT);
396 
397 		error = xwimp_create_icon(&icon, &url_bar->suggest.icon);
398 		if (error) {
399 			NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
400 			      error->errnum, error->errmess);
401 			ro_warn_user("WimpError", error->errmess);
402 			return false;
403 		}
404 
405 		if (!url_bar->display)
406 			ro_gui_wimp_event_register_menu_gright(url_bar->window,
407 							       wimp_ICON_WINDOW,
408 							       url_bar->suggest.icon,
409 							       ro_gui_url_suggest_menu);
410 
411 		if (!ro_gui_url_bar_update_urlsuggest(url_bar)) {
412 			return false;
413 		}
414 
415 		resize = true;
416 
417 	} else if (url_bar->hidden &&
418 		   url_bar->suggest.icon != -1) {
419 		ro_gui_wimp_event_deregister(url_bar->window,
420 					     url_bar->suggest.icon);
421 		error = xwimp_delete_icon(url_bar->window,
422 					  url_bar->suggest.icon);
423 		if (error != NULL) {
424 			NSLOG(netsurf, INFO,
425 			      "xwimp_delete_icon: 0x%x: %s",
426 			      error->errnum, error->errmess);
427 			ro_warn_user("WimpError", error->errmess);
428 			return false;
429 		}
430 
431 		url_bar->suggest.icon = -1;
432 	}
433 
434 	/* If any icons were created, resize the bar. */
435 	if (resize && !ro_gui_url_bar_icon_resize(url_bar, true)) {
436 		return false;
437 	}
438 
439 	/* If there are any icons, apply shading as necessary. */
440 	if (url_bar->container_icon != -1) {
441 		ro_gui_set_icon_shaded_state(url_bar->window,
442 					     url_bar->container_icon,
443 					     url_bar->shaded);
444 	}
445 
446 	if (url_bar->text.icon != -1) {
447 		ro_gui_set_icon_shaded_state(url_bar->window,
448 					     url_bar->text.icon,
449 					     url_bar->shaded);
450 	}
451 
452 	if (url_bar->suggest.icon != -1) {
453 		ro_gui_set_icon_shaded_state(url_bar->window,
454 					     url_bar->suggest.icon,
455 					     url_bar->shaded);
456 	}
457 
458 	return true;
459 }
460 
461 
462 /**
463  * Set the state of a URL Bar's hotlist icon.
464  *
465  * \param *url_bar The URL Bar to update.
466  * \param set TRUE to set the hotlist icon; FALSE to clear it.
467  */
ro_gui_url_bar_set_hotlist(struct url_bar * url_bar,bool set)468 static void ro_gui_url_bar_set_hotlist(struct url_bar *url_bar, bool set)
469 {
470 	if (url_bar == NULL ||
471 	    set == url_bar->hotlist.set) {
472 		return;
473 	}
474 
475 	url_bar->hotlist.set = set;
476 
477 	if (!url_bar->hidden) {
478 		xwimp_force_redraw(url_bar->window,
479 				   url_bar->hotlist.extent.x0,
480 				   url_bar->hotlist.extent.y0,
481 				   url_bar->hotlist.extent.x1,
482 				   url_bar->hotlist.extent.y1);
483 	}
484 }
485 
486 
487 /**
488  * Callback for hlcache.
489  */
490 static nserror
ro_gui_url_bar_res_cb(hlcache_handle * handle,const hlcache_event * event,void * pw)491 ro_gui_url_bar_res_cb(hlcache_handle *handle,
492 		      const hlcache_event *event, void *pw)
493 {
494 	struct url_bar_resource *r = pw;
495 
496 	switch (event->type) {
497 	case CONTENT_MSG_READY:
498 	case CONTENT_MSG_DONE:
499 		r->ready = true;
500 		r->height = content_get_height(handle);
501 		break;
502 
503 	default:
504 		break;
505 	}
506 
507 	return NSERROR_OK;
508 }
509 
510 
511 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_create(struct theme_descriptor * theme)512 struct url_bar *ro_gui_url_bar_create(struct theme_descriptor *theme)
513 {
514 	struct url_bar *url_bar;
515 
516 	/* Allocate memory. */
517 
518 	url_bar = malloc(sizeof(struct url_bar));
519 	if (url_bar == NULL) {
520 		NSLOG(netsurf, INFO, "No memory for malloc()");
521 		return NULL;
522 	}
523 
524 	/* Set up default parameters. */
525 
526 	url_bar->theme = theme;
527 	url_bar->sprites = ro_gui_theme_get_sprites(theme);
528 
529 	url_bar->display = false;
530 	url_bar->shaded = false;
531 
532 	url_bar->x_min = URLBAR_FAVICON_WIDTH + URLBAR_MIN_WIDTH +
533 		URLBAR_HOTLIST_WIDTH;
534 	url_bar->y_min = URLBAR_HEIGHT;
535 
536 	url_bar->extent.x0 = 0;
537 	url_bar->extent.y0 = 0;
538 	url_bar->extent.x1 = 0;
539 	url_bar->extent.y1 = 0;
540 
541 	url_bar->window = NULL;
542 	url_bar->container_icon = -1;
543 	url_bar->text.icon = -1;
544 	url_bar->suggest.icon = -1;
545 
546 	url_bar->pginfo.extent.x0 = 0;
547 	url_bar->pginfo.extent.y0 = 0;
548 	url_bar->pginfo.extent.x1 = 0;
549 	url_bar->pginfo.extent.y1 = 0;
550 	strncpy(url_bar->pginfo.sprite,
551 		"pgiinternal",
552 		URLBAR_PGINFO_NAME_LENGTH);
553 
554 	url_bar->favicon.extent.x0 = 0;
555 	url_bar->favicon.extent.y0 = 0;
556 	url_bar->favicon.extent.x1 = 0;
557 	url_bar->favicon.extent.y1 = 0;
558 	url_bar->favicon.width = 0;
559 	url_bar->favicon.height = 0;
560 	url_bar->favicon.content = NULL;
561 	url_bar->favicon.type = 0;
562 	strncpy(url_bar->favicon.sprite,
563 		"Ssmall_xxx",
564 		URLBAR_FAVICON_NAME_LENGTH);
565 
566 	url_bar->hotlist.set = false;
567 	url_bar->hotlist.extent.x0 = 0;
568 	url_bar->hotlist.extent.y0 = 0;
569 	url_bar->hotlist.extent.x1 = 0;
570 	url_bar->hotlist.extent.y1 = 0;
571 
572 	url_bar->text.size = RO_GUI_MAX_URL_SIZE;
573 	url_bar->text.buffer = malloc(url_bar->text.size);
574 	if (url_bar->text.buffer == NULL) {
575 		free(url_bar);
576 		return NULL;
577 	}
578 	url_bar->text.buffer[0] = 0;
579 	url_bar->text.buffer_utf8 = NULL;
580 
581 	url_bar->hidden = false;
582 
583 	return url_bar;
584 }
585 
586 
587 /* This is an exported interface documented in url_bar.h */
588 bool
ro_gui_url_bar_rebuild(struct url_bar * url_bar,struct theme_descriptor * theme,theme_style style,wimp_w window,bool display,bool shaded)589 ro_gui_url_bar_rebuild(struct url_bar *url_bar,
590 		       struct theme_descriptor *theme,
591 		       theme_style style,
592 		       wimp_w window,
593 		       bool display,
594 		       bool shaded)
595 {
596 	if (url_bar == NULL) {
597 		return false;
598 	}
599 
600 	url_bar->theme = theme;
601 	url_bar->window = window;
602 
603 	url_bar->display = display;
604 	url_bar->shaded = shaded;
605 
606 	url_bar->container_icon = -1;
607 	url_bar->text.icon = -1;
608 	url_bar->suggest.icon = -1;
609 
610 	ro_gui_wimp_get_sprite_dimensions((osspriteop_area *) -1,
611 					  suggest_icon,
612 					  &url_bar->suggest.x,
613 					  &url_bar->suggest.y);
614 
615 	url_bar->x_min = URLBAR_PGINFO_WIDTH +
616 		URLBAR_FAVICON_WIDTH +
617 		URLBAR_MIN_WIDTH +
618 		URLBAR_HOTLIST_WIDTH +
619 		URLBAR_GRIGHT_GUTTER +
620 		url_bar->suggest.x;
621 
622 	url_bar->y_min = (url_bar->suggest.y > URLBAR_HEIGHT) ?
623 		url_bar->suggest.y : URLBAR_HEIGHT;
624 
625 	return ro_gui_url_bar_icon_update(url_bar);
626 }
627 
628 
629 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_destroy(struct url_bar * url_bar)630 void ro_gui_url_bar_destroy(struct url_bar *url_bar)
631 {
632 	if (url_bar == NULL) {
633 		return;
634 	}
635 
636 	if (url_bar->text.buffer_utf8 != NULL) {
637 		free(url_bar->text.buffer_utf8);
638 	}
639 
640 	if (url_bar->text.buffer != NULL) {
641 		free(url_bar->text.buffer);
642 	}
643 
644 	free(url_bar);
645 }
646 
647 
648 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_get_dims(struct url_bar * url_bar,int * width,int * height)649 bool ro_gui_url_bar_get_dims(struct url_bar *url_bar, int *width, int *height)
650 {
651 	if (url_bar == NULL) {
652 		return false;
653 	}
654 
655 	if (url_bar->x_min != -1 &&
656 	    url_bar->y_min != -1) {
657 		if (width != NULL) {
658 			*width = url_bar->x_min;
659 		}
660 		if (height != NULL) {
661 			*height = url_bar->y_min;
662 		}
663 
664 		return true;
665 	}
666 
667 	return false;
668 }
669 
670 
671 /* This is an exported interface documented in url_bar.h */
672 bool
ro_gui_url_bar_set_extent(struct url_bar * url_bar,int x0,int y0,int x1,int y1)673 ro_gui_url_bar_set_extent(struct url_bar *url_bar,
674 			  int x0, int y0, int x1, int y1)
675 {
676 	bool stretch;
677 
678 	if (url_bar == NULL) {
679 		return false;
680 	}
681 
682 	if ((x1 - x0) < url_bar->x_min ||
683 	    (y1 - y0) < url_bar->y_min) {
684 		return false;
685 	}
686 
687 	if (url_bar->extent.x0 == x0 &&
688 	    url_bar->extent.y0 == y0 &&
689 	    url_bar->extent.x1 == x1 &&
690 	    url_bar->extent.y1 == y1) {
691 		return true;
692 	}
693 
694 	/* If it's only the length that changes, less needs to be updated. */
695 	stretch = (url_bar->extent.x0 == x0 &&
696 		   url_bar->extent.y0 == y0 &&
697 		   url_bar->extent.y1 == y1) ? true : false;
698 
699 	/* Redraw the relevant bits of the toolbar. */
700 	if (url_bar->window != NULL &&
701 	    !url_bar->hidden) {
702 		if (stretch) {
703 			xwimp_force_redraw(url_bar->window,
704 					   x0 + URLBAR_PGINFO_WIDTH + URLBAR_FAVICON_WIDTH, y0,
705 					   (x1 > url_bar->extent.x1) ?
706 					   x1 : url_bar->extent.x1, y1);
707 		} else {
708 			xwimp_force_redraw(url_bar->window,
709 					   url_bar->extent.x0,
710 					   url_bar->extent.y0,
711 					   url_bar->extent.x1,
712 					   url_bar->extent.y1);
713 			xwimp_force_redraw(url_bar->window, x0, y0, x1, y1);
714 		}
715 	}
716 
717 	/* Reposition the URL bar icons. */
718 	url_bar->extent.x0 = x0;
719 	url_bar->extent.y0 = y0;
720 	url_bar->extent.x1 = x1;
721 	url_bar->extent.y1 = y1;
722 
723 	return ro_gui_url_bar_icon_resize(url_bar, !stretch);
724 }
725 
726 
727 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_hide(struct url_bar * url_bar,bool hide)728 bool ro_gui_url_bar_hide(struct url_bar *url_bar, bool hide)
729 {
730 	if (url_bar == NULL || url_bar->hidden == hide)
731 		return (url_bar == NULL) ? false : true;
732 
733 	url_bar->hidden = hide;
734 
735 	return ro_gui_url_bar_icon_update(url_bar);
736 }
737 
738 
739 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_redraw(struct url_bar * url_bar,wimp_draw * redraw)740 void ro_gui_url_bar_redraw(struct url_bar *url_bar, wimp_draw *redraw)
741 {
742 	wimp_icon icon;
743 	struct rect clip;
744 	bool draw_pginfo = true;
745 	bool draw_favicon = true;
746 	bool draw_hotlist = true;
747 
748 	/* Test for a valid URL bar */
749 	if (url_bar == NULL || url_bar->hidden)
750 		return;
751 
752 	if ((redraw->clip.x0 - (redraw->box.x0 - redraw->xscroll)) >
753 	    (url_bar->pginfo.extent.x1) ||
754 	    (redraw->clip.y0 - (redraw->box.y1 - redraw->yscroll)) >
755 	    (url_bar->pginfo.extent.y1) ||
756 	    (redraw->clip.x1 - (redraw->box.x0 - redraw->xscroll)) <
757 	    (url_bar->pginfo.extent.x0) ||
758 	    (redraw->clip.y1 - (redraw->box.y1 - redraw->yscroll)) <
759 	    (url_bar->pginfo.extent.y0)) {
760 		/* page info not in redraw area */
761 		draw_pginfo = false;
762 	}
763 
764 	if ((redraw->clip.x0 - (redraw->box.x0 - redraw->xscroll)) >
765 	    (url_bar->favicon.extent.x1) ||
766 	    (redraw->clip.y0 - (redraw->box.y1 - redraw->yscroll)) >
767 	    (url_bar->favicon.extent.y1) ||
768 	    (redraw->clip.x1 - (redraw->box.x0 - redraw->xscroll)) <
769 	    (url_bar->favicon.extent.x0) ||
770 	    (redraw->clip.y1 - (redraw->box.y1 - redraw->yscroll)) <
771 	    (url_bar->favicon.extent.y0)) {
772 		/* Favicon not in redraw area */
773 		draw_favicon = false;
774 	}
775 
776 	if ((redraw->clip.x0 - (redraw->box.x0 - redraw->xscroll)) >
777 	    (url_bar->hotlist.extent.x1) ||
778 	    (redraw->clip.y0 - (redraw->box.y1 - redraw->yscroll)) >
779 	    (url_bar->hotlist.extent.y1) ||
780 	    (redraw->clip.x1 - (redraw->box.x0 - redraw->xscroll)) <
781 	    (url_bar->hotlist.extent.x0) ||
782 	    (redraw->clip.y1 - (redraw->box.y1 - redraw->yscroll)) <
783 	    (url_bar->hotlist.extent.y0)) {
784 		/* Hotlist icon not in redraw area */
785 		draw_hotlist = false;
786 	}
787 
788 	if (draw_pginfo) {
789 		icon.flags = wimp_ICON_SPRITE |
790 			wimp_ICON_INDIRECTED |
791 			wimp_ICON_FILLED |
792 			wimp_ICON_HCENTRED |
793 			wimp_ICON_VCENTRED |
794 			(wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT);
795 		icon.data.indirected_sprite.id = (osspriteop_id)url_bar->pginfo.sprite;
796 		icon.data.indirected_sprite.area = url_bar->sprites;
797 		icon.data.indirected_sprite.size = 12;
798 
799 		icon.extent.x0 = url_bar->pginfo.extent.x0;
800 		icon.extent.x1 = url_bar->pginfo.extent.x1;
801 		icon.extent.y0 = url_bar->pginfo.extent.y0;
802 		icon.extent.y1 = url_bar->pginfo.extent.y1;
803 
804 		xwimp_plot_icon(&icon);
805 	}
806 
807 	if (draw_favicon) {
808 		if (url_bar->favicon.content == NULL) {
809 			icon.data.indirected_text.text = null_text_string;
810 			icon.data.indirected_text.validation =
811 				url_bar->favicon.sprite;
812 			icon.data.indirected_text.size = 1;
813 			icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE |
814 				wimp_ICON_INDIRECTED |
815 				wimp_ICON_FILLED |
816 				wimp_ICON_HCENTRED |
817 				wimp_ICON_VCENTRED;
818 			icon.extent.x0 = url_bar->favicon.extent.x0;
819 			icon.extent.x1 = url_bar->favicon.extent.x1;
820 			icon.extent.y0 = url_bar->favicon.extent.y0;
821 			icon.extent.y1 = url_bar->favicon.extent.y1;
822 
823 			xwimp_plot_icon(&icon);
824 		} else {
825 			struct content_redraw_data data;
826 			struct redraw_context ctx = {
827 				.interactive = true,
828 				.background_images = true,
829 				.plot = &ro_plotters
830 			};
831 
832 			xwimp_set_colour(wimp_COLOUR_WHITE);
833 			xos_plot(os_MOVE_TO,
834 				 (redraw->box.x0 - redraw->xscroll) +
835 				 url_bar->favicon.extent.x0,
836 				 (redraw->box.y1 - redraw->yscroll) +
837 				 url_bar->favicon.extent.y0);
838 			xos_plot(os_PLOT_TO | os_PLOT_RECTANGLE,
839 				 (redraw->box.x0 - redraw->xscroll) +
840 				 url_bar->favicon.extent.x1,
841 				 (redraw->box.y1 - redraw->yscroll) +
842 				 url_bar->favicon.extent.y1);
843 
844 			clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2;
845 			clip.y0 = (ro_plot_origin_y - redraw->clip.y0) / 2;
846 			clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2;
847 			clip.y1 = (ro_plot_origin_y - redraw->clip.y1) / 2;
848 
849 			data.x = (url_bar->favicon.extent.x0 +
850 				  url_bar->favicon.offset.x) / 2;
851 			data.y = (url_bar->favicon.offset.y -
852 				  url_bar->favicon.extent.y1) / 2;
853 			data.width = url_bar->favicon.width;
854 			data.height = url_bar->favicon.height;
855 			data.background_colour = 0xFFFFFF;
856 			data.scale = 1;
857 			data.repeat_x = false;
858 			data.repeat_y = false;
859 
860 			content_redraw(url_bar->favicon.content,
861 				       &data, &clip, &ctx);
862 		}
863 	}
864 
865 	if (draw_hotlist) {
866 		struct content_redraw_data data;
867 		struct redraw_context ctx = {
868 			.interactive = true,
869 			.background_images = true,
870 			.plot = &ro_plotters
871 		};
872 		struct url_bar_resource *hotlist_icon = url_bar->hotlist.set ?
873 			&(url_bar_res[URLBAR_RES_HOTLIST_REMOVE]) :
874 			&(url_bar_res[URLBAR_RES_HOTLIST_ADD]);
875 
876 		xwimp_set_colour(wimp_COLOUR_WHITE);
877 		xos_plot(os_MOVE_TO,
878 			 (redraw->box.x0 - redraw->xscroll) +
879 			 url_bar->hotlist.extent.x0,
880 			 (redraw->box.y1 - redraw->yscroll) +
881 			 url_bar->hotlist.extent.y0);
882 		xos_plot(os_PLOT_TO | os_PLOT_RECTANGLE,
883 			 (redraw->box.x0 - redraw->xscroll) +
884 			 url_bar->hotlist.extent.x1,
885 			 (redraw->box.y1 - redraw->yscroll) +
886 			 url_bar->hotlist.extent.y1);
887 
888 		if (hotlist_icon->ready == false) {
889 			return;
890 		}
891 
892 		clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2;
893 		clip.y0 = (ro_plot_origin_y - redraw->clip.y0) / 2;
894 		clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2;
895 		clip.y1 = (ro_plot_origin_y - redraw->clip.y1) / 2;
896 
897 		data.x = (url_bar->hotlist.extent.x0 +
898 			  url_bar->hotlist.offset.x) / 2;
899 		data.y = (url_bar->hotlist.offset.y -
900 			  url_bar->hotlist.extent.y1) / 2;
901 		data.width = URLBAR_HOTLIST_SIZE;
902 		data.height = URLBAR_HOTLIST_SIZE;
903 		data.background_colour = 0xFFFFFF;
904 		data.scale = 1;
905 		data.repeat_x = false;
906 		data.repeat_y = false;
907 
908 		content_redraw(hotlist_icon->c, &data, &clip, &ctx);
909 	}
910 }
911 
912 /**
913  * check if os point is inside an os box
914  *
915  * \param pos The coordinate of the point
916  * \param box The box to check against
917  * \return true if point is inside the box else false
918  */
is_point_in_box(os_coord * pos,os_box * box)919 static inline bool is_point_in_box(os_coord *pos, os_box *box)
920 {
921 	if (pos->x < box->x0 ||
922 	    pos->x > box->x1 ||
923 	    pos->y < box->y0 ||
924 	    pos->y > box->y1) {
925 		return false;
926 	}
927 	return true;
928 }
929 
930 /* This is an exported interface documented in url_bar.h */
931 bool
ro_gui_url_bar_click(struct url_bar * url_bar,wimp_pointer * pointer,wimp_window_state * state,url_bar_action * action)932 ro_gui_url_bar_click(struct url_bar *url_bar,
933 		     wimp_pointer *pointer,
934 		     wimp_window_state *state,
935 		     url_bar_action *action)
936 {
937 	os_coord pos;
938 
939 	if (url_bar == NULL || url_bar->hidden ||
940 	    url_bar->display || url_bar->shaded) {
941 		return false;
942 	}
943 
944 	/* Check that the click was within our part of the window. */
945 	pos.x = pointer->pos.x - state->visible.x0 + state->xscroll;
946 	pos.y = pointer->pos.y - state->visible.y1 + state->yscroll;
947 
948 	if (!is_point_in_box(&pos, &url_bar->extent)) {
949 		return false;
950 	}
951 
952 	/* If we have a Select or Adjust click, check if it originated on the
953 	 * hotlist icon; if it did, return an event.
954 	 */
955 	if (pointer->buttons == wimp_SINGLE_SELECT ||
956 	    pointer->buttons == wimp_SINGLE_ADJUST) {
957 		if (is_point_in_box(&pos, &url_bar->hotlist.extent)) {
958 			if (pointer->buttons == wimp_SINGLE_SELECT &&
959 			    action != NULL) {
960 				*action = TOOLBAR_URL_SELECT_HOTLIST;
961 			} else if (pointer->buttons == wimp_SINGLE_ADJUST &&
962 				   action != NULL) {
963 				*action = TOOLBAR_URL_ADJUST_HOTLIST;
964 			}
965 			return true;
966 		}
967 
968 		if (is_point_in_box(&pos, &url_bar->pginfo.extent)) {
969 			if (pointer->buttons == wimp_SINGLE_SELECT &&
970 			    action != NULL) {
971 				*action = TOOLBAR_URL_SELECT_PGINFO;
972 			} else if (pointer->buttons == wimp_SINGLE_ADJUST &&
973 				   action != NULL) {
974 				*action = TOOLBAR_URL_ADJUST_PGINFO;
975 			}
976 			return true;
977 		}
978 
979 	}
980 
981 	/* If we find a Select or Adjust drag, check if it originated on the
982 	 * URL bar or over the favicon.  If either, then return an event.
983 	 */
984 	if (pointer->buttons == wimp_DRAG_SELECT ||
985 	    pointer->buttons == wimp_DRAG_ADJUST) {
986 		if (pointer->i == url_bar->text.icon) {
987 			if (action != NULL) {
988 				*action = TOOLBAR_URL_DRAG_URL;
989 			}
990 			return true;
991 		}
992 
993 		if (is_point_in_box(&pos, &url_bar->favicon.extent)) {
994 			if (action != NULL) {
995 				*action = TOOLBAR_URL_DRAG_FAVICON;
996 			}
997 			return true;
998 		}
999 	}
1000 
1001 	return false;
1002 }
1003 
1004 
1005 /* This is an exported interface documented in url_bar.h */
1006 bool
ro_gui_url_bar_menu_prepare(struct url_bar * url_bar,wimp_i i,wimp_menu * menu,wimp_pointer * pointer)1007 ro_gui_url_bar_menu_prepare(struct url_bar *url_bar,
1008 			    wimp_i i,
1009 			    wimp_menu *menu,
1010 			    wimp_pointer *pointer)
1011 {
1012 	if (url_bar == NULL ||
1013 	    url_bar->suggest.icon != i ||
1014 	    menu != ro_gui_url_suggest_menu) {
1015 		return false;
1016 	}
1017 
1018 	if (pointer != NULL) {
1019 		return ro_gui_url_suggest_prepare_menu();
1020 	}
1021 
1022 	return true;
1023 }
1024 
1025 
1026 /* This is an exported interface documented in url_bar.h */
1027 bool
ro_gui_url_bar_menu_select(struct url_bar * url_bar,wimp_i i,wimp_menu * menu,wimp_selection * selection,menu_action action)1028 ro_gui_url_bar_menu_select(struct url_bar *url_bar,
1029 			   wimp_i i,
1030 			   wimp_menu *menu,
1031 			   wimp_selection *selection,
1032 			   menu_action action)
1033 {
1034 	const char *urltxt;
1035 	struct gui_window *g;
1036 
1037 	if (url_bar == NULL ||
1038 	    url_bar->suggest.icon != i ||
1039 	    menu != ro_gui_url_suggest_menu) {
1040 		return false;
1041 	}
1042 
1043 	urltxt = ro_gui_url_suggest_get_selection(selection);
1044 	g = ro_gui_toolbar_lookup(url_bar->window);
1045 
1046 	if (urltxt != NULL &&
1047 	    g != NULL &&
1048 	    g->bw != NULL) {
1049 		nsurl *url;
1050 		nserror error;
1051 
1052 		error = nsurl_create(urltxt, &url);
1053 		if (error != NSERROR_OK) {
1054 			ro_warn_user(messages_get_errorcode(error), 0);
1055 		} else {
1056 			ro_gui_window_set_url(g, url);
1057 
1058 			browser_window_navigate(g->bw,
1059 						url,
1060 						NULL,
1061 						BW_NAVIGATE_HISTORY,
1062 						NULL,
1063 						NULL,
1064 						NULL);
1065 			nsurl_unref(url);
1066 		}
1067 	}
1068 
1069 	return true;
1070 }
1071 
1072 
1073 /* This is an exported interface documented in url_bar.h */
1074 bool
ro_gui_url_bar_help_suffix(struct url_bar * url_bar,wimp_i i,os_coord * mouse,wimp_window_state * state,wimp_mouse_state buttons,const char ** suffix)1075 ro_gui_url_bar_help_suffix(struct url_bar *url_bar,
1076 			   wimp_i i,
1077 			   os_coord *mouse,
1078 			   wimp_window_state *state,
1079 			   wimp_mouse_state buttons,
1080 			   const char **suffix)
1081 {
1082 	os_coord pos;
1083 
1084 	if (url_bar == NULL || url_bar->hidden) {
1085 		return false;
1086 	}
1087 
1088 	/* Check that the click was within our part of the window. */
1089 
1090 	pos.x = mouse->x - state->visible.x0 + state->xscroll;
1091 	pos.y = mouse->y - state->visible.y1 + state->yscroll;
1092 
1093 	if (pos.x < url_bar->extent.x0 ||
1094 	    pos.x > url_bar->extent.x1 ||
1095 	    pos.y < url_bar->extent.y0 ||
1096 	    pos.y > url_bar->extent.y1) {
1097 		return false;
1098 	}
1099 
1100 	/* Return hard-coded icon numbers that match the ones that were
1101 	 * always allocated to the URL bar in a previous implementation.
1102 	 * If Messages can be updated, this could be changed.
1103 	 */
1104 
1105 	if (i == url_bar->text.icon) {
1106 		*suffix = "14";
1107 	} else if (i == url_bar->suggest.icon) {
1108 		*suffix = "15";
1109 	} else if (pos.x >= url_bar->hotlist.extent.x0 &&
1110 		   pos.x <= url_bar->hotlist.extent.x1 &&
1111 		   pos.y >= url_bar->hotlist.extent.y0 &&
1112 		   pos.y <= url_bar->hotlist.extent.y1) {
1113 		*suffix = "Hot";
1114 	} else if (pos.x >= url_bar->favicon.extent.x0 &&
1115 		   pos.x <= url_bar->favicon.extent.x1 &&
1116 		   pos.y >= url_bar->favicon.extent.y0 &&
1117 		   pos.y <= url_bar->favicon.extent.y1) {
1118 		*suffix = "Fav";
1119 	} else {
1120 		*suffix = "";
1121 	}
1122 
1123 	return true;
1124 }
1125 
1126 
1127 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_take_caret(struct url_bar * url_bar)1128 bool ro_gui_url_bar_take_caret(struct url_bar *url_bar)
1129 {
1130 	os_error *error;
1131 
1132 	if (url_bar == NULL || url_bar->hidden) {
1133 		return false;
1134 	}
1135 
1136 	error = xwimp_set_caret_position(url_bar->window,
1137 					 url_bar->text.icon,
1138 					 -1, -1, -1, 0);
1139 	if (error) {
1140 		NSLOG(netsurf, INFO,
1141 		      "xwimp_set_caret_position: 0x%x: %s",
1142 		      error->errnum, error->errmess);
1143 		ro_warn_user("WimpError", error->errmess);
1144 
1145 		return false;
1146 	}
1147 
1148 	return true;
1149 }
1150 
1151 
1152 /* This is an exported interface documented in url_bar.h */
1153 void
ro_gui_url_bar_set_url(struct url_bar * url_bar,const char * url,bool is_utf8,bool set_caret)1154 ro_gui_url_bar_set_url(struct url_bar *url_bar,
1155 		       const char *url,
1156 		       bool is_utf8,
1157 		       bool set_caret)
1158 {
1159 	wimp_caret caret;
1160 	os_error *error;
1161 	char *local_text = NULL;
1162 	const char *local_url;
1163 	nsurl *n;
1164 
1165 	if (url_bar == NULL ||
1166 	    url_bar->text.buffer == NULL ||
1167 	    url == NULL) {
1168 		return;
1169 	}
1170 
1171 	/* Before we do anything with the URL, get it into local encoding so
1172 	 * that behaviour is consistent with the rest of the URL Bar module
1173 	 * (which will act on the icon's text buffer, which is always in local
1174 	 * encoding).
1175 	 */
1176 
1177 	if (is_utf8) {
1178 		nserror err;
1179 
1180 		err = utf8_to_local_encoding(url, 0, &local_text);
1181 		if (err != NSERROR_OK) {
1182 			/* A bad encoding should never happen, so assert this */
1183 			assert(err != NSERROR_BAD_ENCODING);
1184 			NSLOG(netsurf, INFO, "utf8_to_enc failed");
1185 			/* Paranoia */
1186 			local_text = NULL;
1187 		}
1188 		local_url = (local_text != NULL) ? local_text : url;
1189 	} else {
1190 		local_url = url;
1191 	}
1192 
1193 	/* Copy the text into the icon buffer. If the text is too long, truncate
1194 	 * for URL bar and log the full URL.
1195 	 */
1196 	if (strlen(local_url) >= url_bar->text.size) {
1197 		NSLOG(netsurf, WARNING,
1198 		      "URL too long to show in URL bar (%zu chars): %s",
1199 		      strlen(url), url);
1200 	}
1201 
1202 	strncpy(url_bar->text.buffer, local_url, url_bar->text.size - 1);
1203 	url_bar->text.buffer[url_bar->text.size - 1] = '\0';
1204 
1205 	if (local_text != NULL) {
1206 		free(local_text);
1207 	}
1208 
1209 	/* Set the hotlist flag. */
1210 	if (nsurl_create(url, &n) == NSERROR_OK) {
1211 		ro_gui_url_bar_set_hotlist(url_bar, ro_gui_hotlist_has_page(n));
1212 		nsurl_unref(n);
1213 	}
1214 
1215 	/* If there's no icon, then there's nothing else to do... */
1216 	if (url_bar->text.icon == -1) {
1217 		return;
1218 	}
1219 
1220 	/* ...if there is, redraw the icon and fix the caret's position. */
1221 	ro_gui_redraw_icon(url_bar->window, url_bar->text.icon);
1222 
1223 	error = xwimp_get_caret_position(&caret);
1224 	if (error) {
1225 		NSLOG(netsurf, INFO,
1226 		      "xwimp_get_caret_position: 0x%x: %s",
1227 		      error->errnum, error->errmess);
1228 		ro_warn_user("WimpError", error->errmess);
1229 		return;
1230 	}
1231 
1232 	if (set_caret ||
1233 	    (caret.w == url_bar->window &&
1234 	     caret.i == url_bar->text.icon)) {
1235 		const char *set_url;
1236 		set_url = ro_gui_get_icon_string(url_bar->window,
1237 						 url_bar->text.icon);
1238 
1239 		error = xwimp_set_caret_position(url_bar->window,
1240 						 url_bar->text.icon,
1241 						 0, 0, -1,
1242 						 strlen(set_url));
1243 		if (error) {
1244 			NSLOG(netsurf, INFO,
1245 			      "xwimp_set_caret_position: 0x%x: %s",
1246 			      error->errnum,
1247 			      error->errmess);
1248 			ro_warn_user("WimpError", error->errmess);
1249 		}
1250 	}
1251 }
1252 
1253 
1254 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_update_hotlist(struct url_bar * url_bar)1255 void ro_gui_url_bar_update_hotlist(struct url_bar *url_bar)
1256 {
1257 	const char *url;
1258 	nsurl *n;
1259 
1260 	if (url_bar == NULL) {
1261 		return;
1262 	}
1263 
1264 	url = (const char *) url_bar->text.buffer;
1265 	if (url != NULL &&
1266 	    nsurl_create(url, &n) == NSERROR_OK) {
1267 		ro_gui_url_bar_set_hotlist(url_bar, ro_gui_hotlist_has_page(n));
1268 		nsurl_unref(n);
1269 	}
1270 }
1271 
1272 
1273 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_get_url(struct url_bar * url_bar)1274 const char *ro_gui_url_bar_get_url(struct url_bar *url_bar)
1275 {
1276 	nserror res;
1277 
1278 	if ((url_bar == NULL) ||
1279 	    (url_bar->text.buffer == NULL)) {
1280 		return NULL;
1281 	}
1282 
1283 	if (url_bar->text.buffer_utf8 != NULL) {
1284 		free(url_bar->text.buffer_utf8);
1285 		url_bar->text.buffer_utf8 = NULL;
1286 	}
1287 
1288 	if (url_bar->text.buffer[0] == '\0') {
1289 		return (const char *) url_bar->text.buffer;
1290 	}
1291 
1292 	res = utf8_from_local_encoding(url_bar->text.buffer, 0,
1293 				       &url_bar->text.buffer_utf8);
1294 	if (res == NSERROR_OK) {
1295 		return (const char *)url_bar->text.buffer_utf8;
1296 	}
1297 
1298 	return (const char *) url_bar->text.buffer;
1299 }
1300 
1301 
1302 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_get_url_extent(struct url_bar * url_bar,os_box * extent)1303 bool ro_gui_url_bar_get_url_extent(struct url_bar *url_bar, os_box *extent)
1304 {
1305 	wimp_icon_state state;
1306 	os_error *error;
1307 
1308 	if (url_bar == NULL || url_bar->hidden) {
1309 		return false;
1310 	}
1311 
1312 	if (extent == NULL) {
1313 		return true;
1314 	}
1315 
1316 	state.w = url_bar->window;
1317 	state.i = url_bar->container_icon;
1318 	error = xwimp_get_icon_state(&state);
1319 	if (error) {
1320 		NSLOG(netsurf, INFO,
1321 		      "xwimp_get_icon_state: 0x%x: %s",
1322 		      error->errnum, error->errmess);
1323 		ro_warn_user("WimpError", error->errmess);
1324 		return false;
1325 	}
1326 
1327 	extent->x0 = state.icon.extent.x0;
1328 	extent->y0 = state.icon.extent.y0;
1329 	extent->x1 = state.icon.extent.x1;
1330 	extent->y1 = state.icon.extent.y1;
1331 
1332 	return true;
1333 }
1334 
1335 
1336 /* This is an exported interface documented in url_bar.h */
1337 bool
ro_gui_url_bar_test_for_text_field_click(struct url_bar * url_bar,wimp_pointer * pointer)1338 ro_gui_url_bar_test_for_text_field_click(struct url_bar *url_bar,
1339 					 wimp_pointer *pointer)
1340 {
1341 	if (url_bar == NULL ||
1342 	    url_bar->hidden ||
1343 	    pointer == NULL) {
1344 		return false;
1345 	}
1346 
1347 	return (pointer->w == url_bar->window &&
1348 		pointer->i == url_bar->text.icon) ? true : false;
1349 }
1350 
1351 
1352 /* This is an exported interface documented in url_bar.h */
1353 bool
ro_gui_url_bar_test_for_text_field_keypress(struct url_bar * url_bar,wimp_key * key)1354 ro_gui_url_bar_test_for_text_field_keypress(struct url_bar *url_bar,
1355 					    wimp_key *key)
1356 {
1357 	const char *url;
1358 	nsurl *n;
1359 
1360 	if (url_bar == NULL ||
1361 	    url_bar->hidden ||
1362 	    key == NULL) {
1363 		return false;
1364 	}
1365 
1366 	if (key->w != url_bar->window ||
1367 	    key->i != url_bar->text.icon) {
1368 		return false;
1369 	}
1370 
1371 	/* Update hotlist indicator */
1372 
1373 	url = (const char *) url_bar->text.buffer;
1374 	if (url != NULL &&
1375 	    nsurl_create(url, &n) == NSERROR_OK) {
1376 		ro_gui_url_bar_set_hotlist(url_bar, ro_gui_hotlist_has_page(n));
1377 		nsurl_unref(n);
1378 	} else if (url_bar->hotlist.set) {
1379 		ro_gui_url_bar_set_hotlist(url_bar, false);
1380 	}
1381 
1382 	return true;
1383 }
1384 
1385 
1386 /* This is an exported interface documented in url_bar.h */
1387 bool
ro_gui_url_bar_set_site_favicon(struct url_bar * url_bar,struct hlcache_handle * h)1388 ro_gui_url_bar_set_site_favicon(struct url_bar *url_bar,
1389 				struct hlcache_handle *h)
1390 {
1391 	content_type type = CONTENT_NONE;
1392 
1393 	if (url_bar == NULL) {
1394 		return false;
1395 	}
1396 
1397 	if (h != NULL) {
1398 		type = content_get_type(h);
1399 	}
1400 
1401 	// \TODO -- Maybe test for CONTENT_ICO ???
1402 
1403 	if (type == CONTENT_IMAGE) {
1404 		url_bar->favicon.content = h;
1405 		url_bar->favicon.width = content_get_width(h);
1406 		url_bar->favicon.height = content_get_height(h);
1407 
1408 		if (url_bar->favicon.width > URLBAR_FAVICON_SIZE) {
1409 			url_bar->favicon.width = URLBAR_FAVICON_SIZE;
1410 		}
1411 
1412 		if (url_bar->favicon.height > URLBAR_FAVICON_SIZE) {
1413 			url_bar->favicon.height = URLBAR_FAVICON_SIZE;
1414 		}
1415 
1416 		url_bar->favicon.offset.x = ((url_bar->favicon.extent.x1 -
1417 					      url_bar->favicon.extent.x0) -
1418 					     (url_bar->favicon.width * 2)) / 2;
1419 		url_bar->favicon.offset.y = ((url_bar->favicon.extent.y1 -
1420 					      url_bar->favicon.extent.y0) -
1421 					     (url_bar->favicon.height * 2)) / 2;
1422 	} else {
1423 		url_bar->favicon.content = NULL;
1424 
1425 		if (url_bar->favicon.type != 0) {
1426 			snprintf(url_bar->favicon.sprite,
1427 				 URLBAR_FAVICON_NAME_LENGTH,
1428 				 "Ssmall_%.3x", url_bar->favicon.type);
1429 		} else {
1430 			snprintf(url_bar->favicon.sprite,
1431 				 URLBAR_FAVICON_NAME_LENGTH,
1432 				 "Ssmall_xxx");
1433 		}
1434 	}
1435 
1436 	if (!url_bar->hidden) {
1437 		xwimp_force_redraw(url_bar->window,
1438 				   url_bar->favicon.extent.x0,
1439 				   url_bar->favicon.extent.y0,
1440 				   url_bar->favicon.extent.x1,
1441 				   url_bar->favicon.extent.y1);
1442 	}
1443 
1444 	return true;
1445 }
1446 
1447 
1448 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_page_info_change(struct url_bar * url_bar)1449 bool ro_gui_url_bar_page_info_change(struct url_bar *url_bar)
1450 {
1451 	browser_window_page_info_state pistate;
1452 	const char *icon_name;
1453 	struct gui_window *g;
1454 
1455 	g = ro_gui_toolbar_lookup(url_bar->window);
1456 
1457 	pistate = browser_window_get_page_info_state(g->bw);
1458 
1459 	switch (pistate) {
1460 	case PAGE_STATE_LOCAL:
1461 		icon_name = "pgilocal";
1462 		break;
1463 
1464 	case PAGE_STATE_INSECURE:
1465 		icon_name = "pgiinsecure";
1466 		break;
1467 
1468 	case PAGE_STATE_SECURE_OVERRIDE:
1469 		icon_name = "pgiwarning";
1470 		break;
1471 
1472 	case PAGE_STATE_SECURE_ISSUES:
1473 		icon_name = "pgiwarning";
1474 		break;
1475 
1476 	case PAGE_STATE_SECURE:
1477 		icon_name = "pgisecure";
1478 		break;
1479 
1480 	case PAGE_STATE_INTERNAL:
1481 	default:
1482 		icon_name = "pgiinternal";
1483 		break;
1484 	}
1485 
1486 	strncpy(url_bar->pginfo.sprite,	icon_name, URLBAR_PGINFO_NAME_LENGTH);
1487 
1488 	if (!url_bar->hidden) {
1489 		xwimp_force_redraw(url_bar->window,
1490 				   url_bar->pginfo.extent.x0,
1491 				   url_bar->pginfo.extent.y0,
1492 				   url_bar->pginfo.extent.x1,
1493 				   url_bar->pginfo.extent.y1);
1494 	}
1495 
1496 	return true;
1497 }
1498 
1499 
1500 /* This is an exported interface documented in url_bar.h */
1501 bool
ro_gui_url_bar_set_content_favicon(struct url_bar * url_bar,struct gui_window * g)1502 ro_gui_url_bar_set_content_favicon(struct url_bar *url_bar,
1503 				   struct gui_window *g)
1504 {
1505 	int type = 0;
1506 	char sprite[URLBAR_FAVICON_NAME_LENGTH];
1507 	struct hlcache_handle *h;
1508 
1509 	if (url_bar == NULL ||
1510 	    g == NULL) {
1511 		return false;
1512 	}
1513 
1514 	h = browser_window_get_content(g->bw);
1515 	if (h != NULL) {
1516 		type = ro_content_filetype(h);
1517 	}
1518 
1519 	if (type != 0) {
1520 		snprintf(sprite, URLBAR_FAVICON_NAME_LENGTH,
1521 			 "small_%.3x", type);
1522 
1523 		if (!ro_gui_wimp_sprite_exists(sprite)) {
1524 			type = 0;
1525 		}
1526 	}
1527 
1528 	url_bar->favicon.type = type;
1529 
1530 	if (url_bar->favicon.content == NULL) {
1531 		if (type == 0) {
1532 			snprintf(url_bar->favicon.sprite,
1533 				 URLBAR_FAVICON_NAME_LENGTH, "Ssmall_xxx");
1534 		} else {
1535 			snprintf(url_bar->favicon.sprite,
1536 				 URLBAR_FAVICON_NAME_LENGTH, "S%s", sprite);
1537 		}
1538 
1539 		if (!url_bar->hidden) {
1540 			xwimp_force_redraw(url_bar->window,
1541 					   url_bar->favicon.extent.x0,
1542 					   url_bar->favicon.extent.y0,
1543 					   url_bar->favicon.extent.x1,
1544 					   url_bar->favicon.extent.y1);
1545 		}
1546 	}
1547 
1548 	return true;
1549 }
1550 
1551 
1552 /* This is an exported interface documented in url_bar.h */
ro_gui_url_bar_update_urlsuggest(struct url_bar * url_bar)1553 bool ro_gui_url_bar_update_urlsuggest(struct url_bar *url_bar)
1554 {
1555 	if (url_bar == NULL ||
1556 	    url_bar->hidden) {
1557 		return (url_bar == NULL) ? false : true;
1558 	}
1559 
1560 	if (url_bar->window != NULL &&
1561 	    url_bar->suggest.icon != -1) {
1562 		ro_gui_set_icon_shaded_state(url_bar->window,
1563 					     url_bar->suggest.icon,
1564 					     !ro_gui_url_suggest_get_menu_available());
1565 	}
1566 
1567 	return true;
1568 }
1569 
1570 
1571 /* Exported interface, documented in url_bar.h */
ro_gui_url_bar_init(void)1572 bool ro_gui_url_bar_init(void)
1573 {
1574 	int i;
1575 
1576 	for (i = 0; i < URLBAR_RES_LAST; i++) {
1577 		nsurl *url;
1578 		if (nsurl_create(url_bar_res[i].url, &url) == NSERROR_OK) {
1579 			hlcache_handle_retrieve(url,
1580 						0,
1581 						NULL,
1582 						NULL,
1583 						ro_gui_url_bar_res_cb,
1584 						&(url_bar_res[i]),
1585 						NULL,
1586 						CONTENT_IMAGE,
1587 						&(url_bar_res[i].c));
1588 			nsurl_unref(url);
1589 		}
1590 	}
1591 
1592 	return true;
1593 }
1594 
1595 
1596 /* Exported interface, documented in url_bar.h */
ro_gui_url_bar_fini(void)1597 void ro_gui_url_bar_fini(void)
1598 {
1599 	int i;
1600 
1601 	for (i = 0; i < URLBAR_RES_LAST; i++) {
1602 		hlcache_handle_release(url_bar_res[i].c);
1603 	}
1604 }
1605