1 /*
2 * Copyright 2004, 2005 Richard Wilson <info@tinct.net>
3 * Copyright 2010, 2011 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 /** \file
21 * Window toolbars (implementation).
22 */
23
24 #include <alloca.h>
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include "oslib/dragasprite.h"
30 #include "oslib/os.h"
31 #include "oslib/osgbpb.h"
32 #include "oslib/osfile.h"
33 #include "oslib/osfind.h"
34 #include "oslib/osspriteop.h"
35 #include "oslib/wimpspriteop.h"
36 #include "oslib/squash.h"
37 #include "oslib/wimp.h"
38 #include "oslib/wimpextend.h"
39 #include "oslib/wimpspriteop.h"
40
41 #include "utils/log.h"
42 #include "utils/nsoption.h"
43
44 #include "riscos/cookies.h"
45 #include "riscos/dialog.h"
46 #include "riscos/global_history.h"
47 #include "riscos/gui.h"
48 #include "riscos/gui/button_bar.h"
49 #include "riscos/gui/throbber.h"
50 #include "riscos/gui/url_bar.h"
51 #include "riscos/hotlist.h"
52 #include "riscos/menus.h"
53 #include "riscos/save.h"
54 #include "riscos/theme.h"
55 #include "riscos/toolbar.h"
56 #include "riscos/url_complete.h"
57 #include "riscos/wimp.h"
58 #include "riscos/wimp_event.h"
59 #include "riscos/wimputils.h"
60 #include "riscos/window.h"
61
62
63 #define TOOLBAR_WIDGET_GUTTER 8
64 #define TOOLBAR_DEFAULT_WIDTH 16384
65
66 /* Toolbar rows used to index into the arrays of row-specific data.
67 */
68
69 #define TOOLBAR_ROW_TOP 0
70 #define TOOLBAR_ROW_DIV1 1
71 #define TOOLBAR_ROW_EDIT 2
72 #define TOOLBAR_MAX_ROWS 3
73
74 /* The toolbar data structure.
75 */
76
77 struct toolbar {
78 /** Bar details. */
79 struct theme_descriptor *theme;
80 theme_style style;
81 toolbar_flags flags;
82
83 int current_width, current_height;
84 int full_width, full_height;
85 int clip_width, clip_height;
86
87 /** Toolbar and parent window handles. */
88 wimp_w toolbar_handle;
89 wimp_w parent_handle;
90
91 /** Row locations and sizes. */
92 int row_y0[TOOLBAR_MAX_ROWS];
93 int row_y1[TOOLBAR_MAX_ROWS];
94
95 /** Details for the button bar. */
96 struct button_bar *buttons;
97 bool buttons_display;
98 os_coord buttons_size;
99
100 /** Details for the URL bar. */
101 struct url_bar *url;
102 bool url_display;
103 os_coord url_size;
104
105 /** Details for the throbber. */
106 struct throbber *throbber;
107 bool throbber_display;
108 bool throbber_right;
109 os_coord throbber_size;
110
111 /** Client callback data. */
112 const struct toolbar_callbacks *callbacks;
113 void *client_data;
114
115 /** Details for the toolbar editor. */
116 wimp_i editor_div1;
117 struct button_bar *editor;
118 os_coord editor_size;
119
120 bool editing;
121
122 /** Interactive help data. */
123
124 const char *help_prefix;
125
126 /** The next bar in the toolbar list. */
127 struct toolbar *next;
128 };
129
130
131 /* Global variables for the toolbar module.
132 */
133
134 /** The list of defined toolbars. */
135 static struct toolbar *ro_toolbar_bars = NULL;
136
137 /** The Toolber Menu */
138 wimp_menu *toolbar_menu;
139
140
141 /* A basic window definition for the toolbar and status bar.
142 */
143
144 static wimp_window ro_toolbar_window = {
145 {0, 0, 1, 1},
146 0,
147 0,
148 wimp_TOP,
149 wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | wimp_WINDOW_NO_BOUNDS |
150 wimp_WINDOW_FURNITURE_WINDOW |
151 wimp_WINDOW_IGNORE_XEXTENT | wimp_WINDOW_IGNORE_YEXTENT,
152 wimp_COLOUR_BLACK,
153 wimp_COLOUR_LIGHT_GREY,
154 wimp_COLOUR_LIGHT_GREY,
155 wimp_COLOUR_VERY_LIGHT_GREY,
156 wimp_COLOUR_DARK_GREY,
157 wimp_COLOUR_MID_LIGHT_GREY,
158 wimp_COLOUR_CREAM,
159 wimp_WINDOW_NEVER3D | 0x16u /* RISC OS 5.03+ */,
160 {0, 0, TOOLBAR_DEFAULT_WIDTH, 16384},
161 0,
162 wimp_BUTTON_DOUBLE_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT,
163 wimpspriteop_AREA,
164 1,
165 1,
166 {""},
167 0,
168 { }
169 };
170
171 static char ro_toolbar_null_string[] = "";
172 static char ro_toolbar_line_validation[] = "R2";
173
174 /*
175 * Private function prototypes.
176 */
177
178 static void ro_toolbar_update_current_widgets(struct toolbar *toolbar);
179 static void ro_toolbar_refresh_widget_dimensions(struct toolbar *toolbar);
180 static void ro_toolbar_reformat_widgets(struct toolbar *toolbar);
181
182 static void ro_toolbar_redraw(wimp_draw *redraw);
183 static bool ro_toolbar_click(wimp_pointer *pointer);
184 static bool ro_toolbar_keypress(wimp_key *key);
185 static bool ro_toolbar_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
186 wimp_pointer *pointer);
187 static void ro_toolbar_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
188 wimp_selection *selection, menu_action action);
189 static bool ro_toolbar_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
190 wimp_selection *selection, menu_action action);
191 static const char *ro_toolbar_get_help_suffix(wimp_w w, wimp_i i, os_coord *pos,
192 wimp_mouse_state buttons);
193
194 static void ro_toolbar_update_buttons(struct toolbar *toolbar);
195
196
197 /* This is an exported interface documented in toolbar.h */
198
ro_toolbar_init(void)199 void ro_toolbar_init(void)
200 {
201 /* browser toolbar menu */
202 static const struct ns_menu toolbar_definition = {
203 "Toolbar", {
204 { "Toolbars", NO_ACTION, 0 },
205 { "Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
206 { "Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 },
207 { "Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 },
208 { "EditToolbar", TOOLBAR_EDIT, 0 },
209 {NULL, 0, 0}
210 }
211 };
212 toolbar_menu = ro_gui_menu_define_menu(
213 &toolbar_definition);
214 }
215
216
217 /* This is an exported interface documented in toolbar.h */
218
ro_toolbar_create(struct theme_descriptor * descriptor,wimp_w parent,theme_style style,toolbar_flags bar_flags,const struct toolbar_callbacks * callbacks,void * client_data,const char * help)219 struct toolbar *ro_toolbar_create(struct theme_descriptor *descriptor,
220 wimp_w parent, theme_style style, toolbar_flags bar_flags,
221 const struct toolbar_callbacks *callbacks, void *client_data,
222 const char *help)
223 {
224 struct toolbar *toolbar;
225
226 /* Allocate memory for the bar and link it into the list of bars. */
227
228 toolbar = calloc(sizeof(struct toolbar), 1);
229 if (toolbar == NULL) {
230 NSLOG(netsurf, INFO, "No memory for malloc()");
231 ro_warn_user("NoMemory", 0);
232 return NULL;
233 }
234
235 toolbar->next = ro_toolbar_bars;
236 ro_toolbar_bars = toolbar;
237
238 /* Store the supplied settings. */
239
240 toolbar->flags = bar_flags;
241 toolbar->theme = descriptor;
242 toolbar->style = style;
243 toolbar->parent_handle = parent;
244 toolbar->callbacks = callbacks;
245 toolbar->client_data = client_data;
246
247 /* Set up the internal widgets: initially, there are none. */
248
249 toolbar->buttons = NULL;
250 toolbar->buttons_display = false;
251
252 toolbar->url = NULL;
253 toolbar->url_display = false;
254
255 toolbar->throbber = NULL;
256 toolbar->throbber_display = false;
257
258 /* Set up the bar editor. */
259
260 toolbar->editor = NULL;
261 toolbar->editor_div1 = -1;
262
263 toolbar->editing = false;
264
265 toolbar->help_prefix = help;
266
267 return toolbar;
268 }
269
270
271 /* This is an exported interface documented in toolbar.h */
272
ro_toolbar_add_buttons(struct toolbar * toolbar,const struct button_bar_buttons buttons[],char * button_order)273 bool ro_toolbar_add_buttons(struct toolbar *toolbar,
274 const struct button_bar_buttons buttons[], char *button_order)
275 {
276 if (toolbar == NULL)
277 return false;
278
279 if (toolbar->buttons != NULL)
280 return false;
281
282 toolbar->buttons = ro_gui_button_bar_create(toolbar->theme, buttons);
283 if (toolbar->buttons != NULL) {
284 toolbar->buttons_display = true;
285 ro_gui_button_bar_arrange_buttons(toolbar->buttons,
286 button_order);
287 }
288
289 toolbar->editor = ro_gui_button_bar_create(toolbar->theme, buttons);
290 if (toolbar->editor != NULL)
291 ro_gui_button_bar_hide(toolbar->editor, !toolbar->editing);
292
293 if (toolbar->buttons != NULL && toolbar->editor != NULL)
294 if (!ro_gui_button_bar_link_editor(toolbar->buttons,
295 toolbar->editor,
296 (void (*)(void *))
297 ro_toolbar_update_current_widgets,
298 toolbar))
299 return false;
300
301 return (toolbar->buttons == NULL || toolbar->editor == NULL) ?
302 false : true;
303 }
304
305
306 /* This is an exported interface documented in toolbar.h */
307
ro_toolbar_add_throbber(struct toolbar * toolbar)308 bool ro_toolbar_add_throbber(struct toolbar *toolbar)
309 {
310 if (toolbar == NULL)
311 return false;
312
313 if (toolbar->throbber != NULL)
314 return false;
315
316 toolbar->throbber = ro_gui_throbber_create(toolbar->theme);
317
318 if (toolbar->throbber != NULL)
319 toolbar->throbber_display = true;
320
321 return (toolbar->throbber == NULL) ? false : true;
322 }
323
324
325 /* This is an exported interface documented in toolbar.h */
326
ro_toolbar_add_url(struct toolbar * toolbar)327 bool ro_toolbar_add_url(struct toolbar *toolbar)
328 {
329 if (toolbar == NULL)
330 return false;
331
332 if (toolbar->url != NULL)
333 return false;
334
335 toolbar->url = ro_gui_url_bar_create(toolbar->theme);
336
337 if (toolbar->url != NULL)
338 toolbar->url_display = true;
339
340 return (toolbar->url == NULL) ? false : true;
341 }
342
343
344 /* This is an exported interface documented in toolbar.h */
345
ro_toolbar_rebuild(struct toolbar * toolbar)346 bool ro_toolbar_rebuild(struct toolbar *toolbar)
347 {
348 os_error *error;
349 wimp_icon_create icon;
350 wimp_w old_window = NULL;
351
352 if (toolbar == NULL)
353 return false;
354
355 /* Start to set up the toolbar window. */
356
357 ro_toolbar_window.sprite_area =
358 ro_gui_theme_get_sprites(toolbar->theme);
359 ro_toolbar_window.work_bg =
360 ro_gui_theme_get_style_element(toolbar->theme,
361 toolbar->style, THEME_ELEMENT_BACKGROUND);
362
363 /* Delete any existing toolbar window... */
364
365 if (toolbar->toolbar_handle != NULL) {
366 old_window = toolbar->toolbar_handle;
367 error = xwimp_delete_window(toolbar->toolbar_handle);
368 if (error)
369 NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x: %s",
370 error->errnum, error->errmess);
371 toolbar->toolbar_handle = NULL;
372 }
373
374 /* ...and create a new window. */
375
376 error = xwimp_create_window(&ro_toolbar_window,
377 &toolbar->toolbar_handle);
378 if (error) {
379 NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
380 error->errnum, error->errmess);
381 ro_warn_user("WimpError", error->errmess);
382 return false;
383 }
384
385 /* Set up the toolbar's event handlers. Only set the user activity-
386 * related callbacks if the bar isn't for display purposes. If the
387 * toolbar is being recreated, simply transfer the handlers across
388 * from the old, now-deleted window.
389 */
390
391 if (old_window == NULL) {
392 ro_gui_wimp_event_register_redraw_window(
393 toolbar->toolbar_handle, ro_toolbar_redraw);
394 ro_gui_wimp_event_set_user_data(toolbar->toolbar_handle,
395 toolbar);
396
397 if (!(toolbar->flags & TOOLBAR_FLAGS_DISPLAY)) {
398 ro_gui_wimp_event_register_mouse_click(
399 toolbar->toolbar_handle,
400 ro_toolbar_click);
401 ro_gui_wimp_event_register_keypress(
402 toolbar->toolbar_handle,
403 ro_toolbar_keypress);
404 ro_gui_wimp_event_register_menu_prepare(
405 toolbar->toolbar_handle,
406 ro_toolbar_menu_prepare);
407 ro_gui_wimp_event_register_menu_warning(
408 toolbar->toolbar_handle,
409 ro_toolbar_menu_warning);
410 ro_gui_wimp_event_register_menu_selection(
411 toolbar->toolbar_handle,
412 ro_toolbar_menu_select);
413 ro_gui_wimp_event_register_menu(toolbar->toolbar_handle,
414 toolbar_menu, true, false);
415 ro_gui_wimp_event_register_help_suffix(
416 toolbar->toolbar_handle,
417 ro_toolbar_get_help_suffix);
418 }
419 } else {
420 ro_gui_wimp_event_transfer(old_window, toolbar->toolbar_handle);
421 }
422
423 /* The help prefix changes from edit to non-edit mode. */
424
425 ro_gui_wimp_event_set_help_prefix(toolbar->toolbar_handle,
426 (toolbar->editing) ?
427 "HelpEditToolbar" : toolbar->help_prefix);
428
429 /* Place the widgets into the new bar, using the new theme.
430 *
431 * \TODO -- If any widgets fail to rebuild, then we currently just
432 * carry on without them. Not sure if the whole bar
433 * rebuild should fail here?
434 */
435
436 if (toolbar->throbber != NULL) {
437 if (!ro_gui_throbber_rebuild(toolbar->throbber, toolbar->theme,
438 toolbar->style, toolbar->toolbar_handle,
439 toolbar->editing)) {
440 ro_gui_throbber_destroy(toolbar->throbber);
441 toolbar->throbber = NULL;
442 }
443
444 ro_gui_theme_get_throbber_data(toolbar->theme, NULL, NULL, NULL,
445 &toolbar->throbber_right, NULL);
446 }
447
448 if (toolbar->buttons != NULL) {
449 if (!ro_gui_button_bar_rebuild(toolbar->buttons, toolbar->theme,
450 toolbar->style, toolbar->toolbar_handle,
451 toolbar->editing)) {
452 ro_gui_button_bar_destroy(toolbar->buttons);
453 toolbar->buttons = NULL;
454 }
455 }
456
457 if (toolbar->editor != NULL) {
458 if (!ro_gui_button_bar_rebuild(toolbar->editor, toolbar->theme,
459 toolbar->style, toolbar->toolbar_handle,
460 toolbar->editing)) {
461 ro_gui_button_bar_destroy(toolbar->editor);
462 toolbar->editor = NULL;
463 }
464 }
465
466 if (toolbar->url != NULL) {
467 if (!ro_gui_url_bar_rebuild(toolbar->url, toolbar->theme,
468 toolbar->style, toolbar->toolbar_handle,
469 toolbar->flags & TOOLBAR_FLAGS_DISPLAY,
470 toolbar->editing)) {
471 ro_gui_url_bar_destroy(toolbar->url);
472 toolbar->url = NULL;
473 }
474 }
475
476 /* If this is an editor, add in a divider icon and the editor
477 * button bar.
478 */
479
480 if (toolbar->editing) {
481 icon.w = toolbar->toolbar_handle;
482 icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
483 wimp_ICON_VCENTRED | wimp_ICON_BORDER |
484 (wimp_COLOUR_BLACK <<
485 wimp_ICON_FG_COLOUR_SHIFT) |
486 (wimp_COLOUR_VERY_LIGHT_GREY <<
487 wimp_ICON_BG_COLOUR_SHIFT);
488 icon.icon.extent.x0 = 0;
489 icon.icon.extent.x1 = 0;
490 icon.icon.extent.y1 = 0;
491 icon.icon.extent.y0 = 0;
492 icon.icon.data.indirected_text.text = ro_toolbar_null_string;
493 icon.icon.data.indirected_text.validation =
494 ro_toolbar_line_validation;
495 icon.icon.data.indirected_text.size = 1;
496 error = xwimp_create_icon(&icon, &toolbar->editor_div1);
497 if (error) {
498 NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
499 error->errnum, error->errmess);
500 ro_warn_user("WimpError", error->errmess);
501 toolbar->editor_div1 = -1;
502 }
503 }
504
505 /* Establish the required dimensions to fit the widgets, then
506 * reflow the bar contents.
507 */
508
509 ro_toolbar_refresh_widget_dimensions(toolbar);
510
511 ro_toolbar_process(toolbar, -1, true);
512
513 if (toolbar->parent_handle != NULL)
514 ro_toolbar_attach(toolbar, toolbar->parent_handle);
515
516 ro_toolbar_update_buttons(toolbar);
517
518 return true;
519 }
520
521
522 /* This is an exported interface documented in toolbar.h */
523
ro_toolbar_attach(struct toolbar * toolbar,wimp_w parent)524 bool ro_toolbar_attach(struct toolbar *toolbar, wimp_w parent)
525 {
526 wimp_outline outline;
527 wimp_window_state state;
528 os_error *error;
529
530 if (toolbar == NULL || toolbar->toolbar_handle == NULL)
531 return false;
532
533 toolbar->parent_handle = parent;
534
535 /* Only try to attach the toolbar if there's any of it visible to
536 * matter.
537 */
538
539 if (toolbar->current_height > 0) {
540 outline.w = parent;
541 xwimp_get_window_outline(&outline);
542 state.w = parent;
543 xwimp_get_window_state(&state);
544 state.w = toolbar->toolbar_handle;
545 state.visible.x1 = outline.outline.x1 - 2;
546 state.visible.y0 = state.visible.y1 + 2 -
547 toolbar->current_height;
548 state.xscroll = 0;
549 state.yscroll = 0;
550 error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), parent,
551 wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
552 << wimp_CHILD_XORIGIN_SHIFT |
553 wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
554 << wimp_CHILD_YORIGIN_SHIFT |
555 wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
556 << wimp_CHILD_LS_EDGE_SHIFT |
557 wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
558 << wimp_CHILD_BS_EDGE_SHIFT |
559 wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
560 << wimp_CHILD_RS_EDGE_SHIFT |
561 wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
562 << wimp_CHILD_TS_EDGE_SHIFT);
563 if (error) {
564 NSLOG(netsurf, INFO,
565 "xwimp_open_window_nested: 0x%x: %s",
566 error->errnum,
567 error->errmess);
568 ro_warn_user("WimpError", error->errmess);
569 return false;
570 }
571
572 return true;
573 }
574
575 error = xwimp_close_window(toolbar->toolbar_handle);
576 if (error) {
577 NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
578 error->errnum, error->errmess);
579 ro_warn_user("WimpError", error->errmess);
580 return false;
581 }
582 return true;
583 }
584
585
586 /* This is an exported interface documented in toolbar.h */
587
ro_toolbar_process(struct toolbar * toolbar,int width,bool reformat)588 bool ro_toolbar_process(struct toolbar *toolbar, int width, bool reformat)
589 {
590 os_error *error;
591 wimp_outline outline;
592 wimp_window_state state;
593 os_box extent;
594 int old_height, old_width;
595
596 if (!toolbar)
597 return false;
598
599 old_height = toolbar->current_height;
600 old_width = toolbar->current_width;
601
602 /* Measure the parent window width if the caller has asked us to
603 * calculate the clip width ourselves. Otherwise, if a clip width
604 * has been specified, set the clip to that.
605 */
606
607 if ((toolbar->parent_handle != NULL) && (width == -1)) {
608 outline.w = toolbar->parent_handle;
609 error = xwimp_get_window_outline(&outline);
610 if (error) {
611 NSLOG(netsurf, INFO,
612 "xwimp_get_window_outline: 0x%x: %s",
613 error->errnum,
614 error->errmess);
615 ro_warn_user("WimpError", error->errmess);
616 return false;
617 }
618
619 toolbar->clip_width = outline.outline.x1 -
620 outline.outline.x0 - 2;
621 toolbar->current_width = toolbar->clip_width;
622 } else if (width != -1) {
623 toolbar->clip_width = width;
624 toolbar->current_width = toolbar->clip_width;
625 }
626
627 /* Find the parent visible height to clip our toolbar height to
628 */
629
630 if (toolbar->parent_handle != NULL) {
631 state.w = toolbar->parent_handle;
632 error = xwimp_get_window_state(&state);
633 if (error) {
634 NSLOG(netsurf, INFO,
635 "xwimp_get_window_state: 0x%x: %s",
636 error->errnum,
637 error->errmess);
638 ro_warn_user("WimpError", error->errmess);
639 return false;
640 }
641
642 toolbar->clip_height = state.visible.y1 - state.visible.y0 + 2;
643
644 /* We can't obscure the height of the scroll bar as we
645 * lose the resize icon if we do.
646 */
647
648 if (toolbar->clip_height >= toolbar->full_height)
649 toolbar->current_height = toolbar->full_height;
650 else
651 toolbar->current_height = toolbar->clip_height;
652
653 /* Resize the work area extent and update our position. */
654
655 if (old_height != toolbar->current_height) {
656 extent.x0 = 0;
657 extent.y0 = 0;
658 extent.x1 = TOOLBAR_DEFAULT_WIDTH;
659 extent.y1 = toolbar->current_height - 2;
660 error = xwimp_set_extent(toolbar->toolbar_handle,
661 &extent);
662 if (error) {
663 NSLOG(netsurf, INFO,
664 "xwimp_get_window_state: 0x%x: %s",
665 error->errnum,
666 error->errmess);
667 ro_warn_user("WimpError", error->errmess);
668 }
669
670 ro_toolbar_attach(toolbar, toolbar->parent_handle);
671 }
672 } else {
673 toolbar->clip_height = toolbar->full_height;
674 toolbar->current_height = toolbar->full_height;
675 }
676
677 /* Reflow the widgets into the toolbar if the dimensions have
678 * changed or we have been asked to anyway. */
679
680 if (toolbar->current_width != old_width || reformat)
681 ro_toolbar_reformat_widgets(toolbar);
682
683 return true;
684 }
685
686
687 /**
688 * Update the widgets currently on view in a toolbar. This can be used
689 * generally, but is primarily offered to widgets as a way for them
690 * to force an update.
691 *
692 * \param *toolbar The toolbar to update.
693 */
694
ro_toolbar_update_current_widgets(struct toolbar * toolbar)695 void ro_toolbar_update_current_widgets(struct toolbar *toolbar)
696 {
697 int old_height;
698
699 if (toolbar == NULL)
700 return;
701
702 old_height = toolbar->full_height;
703
704 ro_toolbar_refresh_widget_dimensions(toolbar);
705 ro_toolbar_reformat_widgets(toolbar);
706
707 /* If the toolbar height has changed, we need to tell the client. */
708
709 if (toolbar->full_height != old_height)
710 ro_toolbar_refresh(toolbar);
711 }
712
713
714 /**
715 * Get the minimum dimenstions required by the toolbar widgets after
716 * these have changed. The minimum dimensions are assumed not to change
717 * unless we change theme (ie. we rebuild the bar) or we knowingly
718 * alter a widget (eg. we add or remove button-bar buttons).
719 *
720 *
721 * \param *toolbar The toolbar to refresh.
722 */
723
ro_toolbar_refresh_widget_dimensions(struct toolbar * toolbar)724 void ro_toolbar_refresh_widget_dimensions(struct toolbar *toolbar)
725 {
726 int width, height;
727 int row_width, row_height;
728
729 if (toolbar == NULL)
730 return;
731
732 /* Process the toolbar editor and any associated divider rows.
733 */
734
735 if (toolbar->editor != NULL && toolbar->editing) {
736 width = 0;
737 height = 0;
738 ro_gui_button_bar_get_dims(toolbar->editor, &width, &height);
739
740 toolbar->editor_size.x = width;
741 toolbar->editor_size.y = height;
742
743 toolbar->row_y0[TOOLBAR_ROW_EDIT] = TOOLBAR_WIDGET_GUTTER;
744 toolbar->row_y1[TOOLBAR_ROW_EDIT] = TOOLBAR_WIDGET_GUTTER
745 + height;
746
747 toolbar->row_y0[TOOLBAR_ROW_DIV1] = TOOLBAR_WIDGET_GUTTER +
748 toolbar->row_y1[TOOLBAR_ROW_EDIT];
749 toolbar->row_y1[TOOLBAR_ROW_DIV1] = 8 +
750 toolbar->row_y0[TOOLBAR_ROW_DIV1];
751 } else {
752 toolbar->editor_size.x = 0;
753 toolbar->editor_size.y = 0;
754
755 toolbar->row_y0[TOOLBAR_ROW_EDIT] = 0;
756 toolbar->row_y1[TOOLBAR_ROW_EDIT] = 0;
757 toolbar->row_y0[TOOLBAR_ROW_DIV1] = 0;
758 toolbar->row_y1[TOOLBAR_ROW_DIV1] = 0;
759 }
760
761 /* Process the top row icons. */
762
763 row_width = 0;
764 row_height = 0;
765
766 /* If the editor is active, any button bar if forced into view. */
767
768 if (toolbar->buttons != NULL &&
769 (toolbar->buttons_display || toolbar->editing)) {
770 width = 0;
771 height = 0;
772 ro_gui_button_bar_get_dims(toolbar->buttons, &width, &height);
773
774 row_width += width;
775 toolbar->buttons_size.x = width;
776 toolbar->buttons_size.y = height;
777
778 if (height > row_height)
779 row_height = height;
780 } else {
781 toolbar->buttons_size.x = 0;
782 toolbar->buttons_size.y = 0;
783 }
784
785 if (toolbar->url != NULL && toolbar->url_display) {
786 width = 0;
787 height = 0;
788 ro_gui_url_bar_get_dims(toolbar->url, &width, &height);
789
790 if (row_width > 0)
791 row_width += TOOLBAR_WIDGET_GUTTER;
792 row_width += width;
793
794 toolbar->url_size.x = width;
795 toolbar->url_size.y = height;
796
797 if (height > row_height)
798 row_height = height;
799 } else {
800 toolbar->url_size.x = 0;
801 toolbar->url_size.y = 0;
802 }
803
804 if (toolbar->throbber != NULL && toolbar->throbber_display) {
805 width = 0;
806 height = 0;
807 ro_gui_throbber_get_dims(toolbar->throbber, &width, &height);
808
809 if (row_width > 0)
810 row_width += TOOLBAR_WIDGET_GUTTER;
811 row_width += width;
812
813 toolbar->throbber_size.x = width;
814 toolbar->throbber_size.y = height;
815
816 if (height > row_height)
817 row_height = height;
818 } else {
819 toolbar->throbber_size.x = 0;
820 toolbar->throbber_size.y = 0;
821 }
822
823 if (row_height > 0) {
824 toolbar->row_y0[TOOLBAR_ROW_TOP] = TOOLBAR_WIDGET_GUTTER +
825 toolbar->row_y1[TOOLBAR_ROW_DIV1];
826 toolbar->row_y1[TOOLBAR_ROW_TOP] = row_height +
827 toolbar->row_y0[TOOLBAR_ROW_TOP];
828 } else {
829 toolbar->row_y0[TOOLBAR_ROW_TOP] = 0;
830 toolbar->row_y1[TOOLBAR_ROW_TOP] = 0;
831 }
832
833 /* Establish the full dimensions of the bar.
834 *
835 * \TODO -- This currently assumes an "all or nothing" approach to
836 * the editor bar, and will need reworking once we have to
837 * worry about tab bars.
838 */
839
840 if (toolbar->row_y1[TOOLBAR_ROW_TOP] > 0) {
841 toolbar->full_height = toolbar->row_y1[TOOLBAR_ROW_TOP] +
842 TOOLBAR_WIDGET_GUTTER;
843 } else {
844 toolbar->full_height = 0;
845 }
846 toolbar->full_width = 2 * TOOLBAR_WIDGET_GUTTER +
847 ((row_width > toolbar->editor_size.x) ?
848 row_width : toolbar->editor_size.x);
849 }
850
851
852 /**
853 * Reformat (reflow) the widgets into the toolbar, based on the toolbar size
854 * and the previously calculated widget dimensions.
855 *
856 * \param *toolbar The toolbar to reformat.
857 */
858
ro_toolbar_reformat_widgets(struct toolbar * toolbar)859 void ro_toolbar_reformat_widgets(struct toolbar *toolbar)
860 {
861 int left_margin, right_margin;
862
863 left_margin = TOOLBAR_WIDGET_GUTTER;
864 right_margin = toolbar->clip_width - TOOLBAR_WIDGET_GUTTER;
865
866 /* Flow the toolbar editor row, which will be a fixed with and
867 * may alter the right margin.
868 */
869
870 if (toolbar->editor != NULL && toolbar->editing) {
871 if (right_margin < left_margin + toolbar->editor_size.x)
872 right_margin = left_margin + toolbar->editor_size.x;
873
874 ro_gui_button_bar_set_extent(toolbar->editor,
875 left_margin,
876 toolbar->row_y0[TOOLBAR_ROW_EDIT],
877 left_margin + toolbar->editor_size.x,
878 toolbar->row_y1[TOOLBAR_ROW_EDIT]);
879
880 if (toolbar->editor_div1 != -1)
881 xwimp_resize_icon(toolbar->toolbar_handle,
882 toolbar->editor_div1, -8,
883 toolbar->row_y0[TOOLBAR_ROW_DIV1],
884 toolbar->clip_width + 8,
885 toolbar->row_y1[TOOLBAR_ROW_DIV1]);
886 }
887
888 /* Flow the top row. */
889
890 if (toolbar->throbber != NULL && toolbar->throbber_display) {
891 if (toolbar->throbber_right) {
892 right_margin -= (toolbar->throbber_size.x +
893 TOOLBAR_WIDGET_GUTTER);
894 } else {
895 ro_gui_throbber_set_extent(toolbar->throbber,
896 left_margin,
897 toolbar->row_y0[TOOLBAR_ROW_TOP],
898 left_margin + toolbar->throbber_size.x,
899 toolbar->row_y1[TOOLBAR_ROW_TOP]);
900 left_margin += (toolbar->throbber_size.x +
901 TOOLBAR_WIDGET_GUTTER);
902 }
903 }
904
905 if (toolbar->buttons != NULL &&
906 (toolbar->buttons_display || toolbar->editing)) {
907 if (right_margin < left_margin + toolbar->buttons_size.x)
908 right_margin = left_margin + toolbar->buttons_size.x;
909
910 ro_gui_button_bar_set_extent(toolbar->buttons,
911 left_margin,
912 toolbar->row_y0[TOOLBAR_ROW_TOP],
913 left_margin + toolbar->buttons_size.x,
914 toolbar->row_y1[TOOLBAR_ROW_TOP]);
915 left_margin += (toolbar->buttons_size.x +
916 TOOLBAR_WIDGET_GUTTER);
917 }
918
919 if (toolbar->url != NULL && toolbar->url_display) {
920 if (right_margin < left_margin + toolbar->url_size.x)
921 right_margin = left_margin + toolbar->url_size.x;
922
923 ro_gui_url_bar_set_extent(toolbar->url,
924 left_margin,
925 toolbar->row_y0[TOOLBAR_ROW_TOP],
926 right_margin,
927 toolbar->row_y1[TOOLBAR_ROW_TOP]);
928
929 left_margin = right_margin + TOOLBAR_WIDGET_GUTTER;
930 }
931
932 if (toolbar->throbber != NULL && toolbar->throbber_display &&
933 toolbar->throbber_right) {
934 left_margin = right_margin + TOOLBAR_WIDGET_GUTTER;
935 ro_gui_throbber_set_extent(toolbar->throbber,
936 left_margin,
937 toolbar->row_y0[TOOLBAR_ROW_TOP],
938 left_margin + toolbar->throbber_size.x,
939 toolbar->row_y1[TOOLBAR_ROW_TOP]);
940 }
941
942 }
943
944
945 /* This is an exported interface documented in toolbar.h */
946
ro_toolbar_destroy(struct toolbar * toolbar)947 void ro_toolbar_destroy(struct toolbar *toolbar)
948 {
949 struct toolbar *bar;
950
951 if (toolbar == NULL)
952 return;
953
954 NSLOG(netsurf, INFO, "Destroying toolbar 0x%x", (unsigned int)toolbar);
955
956 /* Destroy the widgets. */
957
958 if (toolbar->buttons != NULL)
959 ro_gui_button_bar_destroy(toolbar->buttons);
960
961 if (toolbar->editor != NULL)
962 ro_gui_button_bar_destroy(toolbar->editor);
963
964 if (toolbar->url != NULL)
965 ro_gui_url_bar_destroy(toolbar->url);
966
967 if (toolbar->throbber != NULL)
968 ro_gui_throbber_destroy(toolbar->throbber);
969
970 /* Delete the toolbar window. */
971
972 if (toolbar->toolbar_handle != NULL) {
973 xwimp_delete_window(toolbar->toolbar_handle);
974 ro_gui_wimp_event_finalise(toolbar->toolbar_handle);
975 }
976
977 /* Remove the bar from the list and free the memory.
978 */
979
980 if (ro_toolbar_bars == toolbar) {
981 ro_toolbar_bars = toolbar->next;
982 } else {
983 for (bar = ro_toolbar_bars; bar != NULL && bar->next != toolbar;
984 bar = bar->next);
985
986 if (bar->next == toolbar)
987 bar->next = toolbar->next;
988 }
989
990 free(toolbar);
991
992 }
993
994
995 /**
996 * Handle redraw request events for a toolbar workarea.
997 *
998 * \param *redraw The redraw block for the event.
999 */
1000
ro_toolbar_redraw(wimp_draw * redraw)1001 void ro_toolbar_redraw(wimp_draw *redraw)
1002 {
1003 struct toolbar *toolbar;
1004 osbool more;
1005 os_error *error;
1006
1007 toolbar = (struct toolbar *)ro_gui_wimp_event_get_user_data(redraw->w);
1008
1009 assert(toolbar != NULL);
1010
1011 error = xwimp_redraw_window(redraw, &more);
1012 if (error) {
1013 NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
1014 error->errnum, error->errmess);
1015 ro_warn_user("WimpError", error->errmess);
1016 return;
1017 }
1018 while (more) {
1019 ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
1020 ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
1021
1022 if (toolbar->buttons != NULL && toolbar->buttons_display)
1023 ro_gui_button_bar_redraw(toolbar->buttons, redraw);
1024
1025 if (toolbar->editor != NULL && toolbar->editing)
1026 ro_gui_button_bar_redraw(toolbar->editor, redraw);
1027
1028 if (toolbar->url != NULL && toolbar->url_display)
1029 ro_gui_url_bar_redraw(toolbar->url, redraw);
1030
1031 error = xwimp_get_rectangle(redraw, &more);
1032 if (error) {
1033 NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
1034 error->errnum, error->errmess);
1035 ro_warn_user("WimpError", error->errmess);
1036 return;
1037 }
1038 }
1039 }
1040
1041
1042 /**
1043 * Process clicks on a toolbar, passing details on to clients where necessary.
1044 *
1045 * \param *pointer The wimp mouse click event.
1046 * \return True if the event was handled; else false.
1047 */
1048
ro_toolbar_click(wimp_pointer * pointer)1049 bool ro_toolbar_click(wimp_pointer *pointer)
1050 {
1051 struct toolbar *toolbar;
1052 union toolbar_action action;
1053 wimp_window_state state;
1054 os_error *error;
1055
1056 toolbar = (struct toolbar *)
1057 ro_gui_wimp_event_get_user_data(pointer->w);
1058
1059 if (toolbar == NULL)
1060 return false;
1061
1062 assert(pointer->w == toolbar->toolbar_handle);
1063
1064 state.w = toolbar->toolbar_handle;
1065 error = xwimp_get_window_state(&state);
1066 if (error) {
1067 NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
1068 error->errnum, error->errmess);
1069 ro_warn_user("WimpError", error->errmess);
1070 return false;
1071 }
1072
1073 /* If the click wasn't in the URL Bar's text field, then it will
1074 * need to close any URL Complete window that is open.
1075 *
1076 * \TODO -- This should really move into the URL Bar module, as
1077 * URL Complete is really an extension to that.
1078 */
1079
1080 if (toolbar->url != NULL && toolbar->url_display &&
1081 !ro_gui_url_bar_test_for_text_field_click(toolbar->url,
1082 pointer))
1083 ro_gui_url_complete_close();
1084
1085 /* Pass the click around the toolbar widgets. */
1086
1087 if (toolbar->buttons != NULL &&
1088 (toolbar->buttons_display || toolbar->editing) &&
1089 ro_gui_button_bar_click(toolbar->buttons, pointer,
1090 &state, &action.button)) {
1091 if (action.button != TOOLBAR_BUTTON_NONE &&
1092 !toolbar->editing &&
1093 toolbar->callbacks != NULL &&
1094 toolbar->callbacks->user_action != NULL)
1095 toolbar->callbacks->user_action(toolbar->client_data,
1096 TOOLBAR_ACTION_BUTTON, action);
1097 return true;
1098 }
1099
1100 if (toolbar->url != NULL && toolbar->url_display &&
1101 ro_gui_url_bar_click(toolbar->url, pointer,
1102 &state, &action.url)) {
1103 if (action.url != TOOLBAR_URL_NONE &&
1104 !toolbar->editing &&
1105 toolbar->callbacks != NULL &&
1106 toolbar->callbacks->user_action != NULL)
1107 toolbar->callbacks->user_action(toolbar->client_data,
1108 TOOLBAR_ACTION_URL, action);
1109 return true;
1110 }
1111
1112 if (toolbar->editor != NULL && toolbar->editing &&
1113 ro_gui_button_bar_click(toolbar->editor, pointer,
1114 &state, &action.button)) {
1115 return true;
1116 }
1117
1118 /* Nothing else has handled this, so try passing it to the
1119 * URL Complete module.
1120 *
1121 * \TODO -- This should really move into the URL Bar module, as
1122 * URL Complete is really an extension to that.
1123 */
1124
1125 if (toolbar->url != NULL && toolbar->url_display &&
1126 ro_gui_url_bar_test_for_text_field_click(toolbar->url,
1127 pointer)) {
1128 ro_gui_url_complete_start(toolbar);
1129 return true;
1130 }
1131
1132 return false;
1133 }
1134
1135
1136 /**
1137 * Process keypresses in a toolbar, passing details on to clients where
1138 * necessary.
1139 *
1140 * \param *key The wimp key press event.
1141 * \return True if the event was handled; else false.
1142 */
1143
ro_toolbar_keypress(wimp_key * key)1144 bool ro_toolbar_keypress(wimp_key *key)
1145 {
1146 struct toolbar *toolbar;
1147
1148 toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(key->w);
1149
1150 if (toolbar == NULL)
1151 return false;
1152
1153 /* Pass the keypress on to the client and stop if they handle it. */
1154
1155 if (toolbar->callbacks->key_press != NULL &&
1156 toolbar->callbacks->key_press(toolbar->client_data, key))
1157 return true;
1158
1159 /* If the caret is in the URL bar, ask the URL Complete module if it
1160 * wants to handle the keypress.
1161 *
1162 * \TODO -- This should really move into the URL Bar module, as
1163 * URL Complete is really an extension to that.
1164 */
1165
1166 if (toolbar->url != NULL && toolbar->url_display &&
1167 ro_gui_url_bar_test_for_text_field_keypress(
1168 toolbar->url, key) &&
1169 ro_gui_url_complete_keypress(toolbar, key->c))
1170 return true;
1171
1172 return false;
1173 }
1174
1175
1176 /**
1177 * Prepare the toolbar menu for (re-)opening
1178 *
1179 * \param w The window owning the menu.
1180 * \param i The icon owning the menu.
1181 * \param *menu The menu about to be opened.
1182 * \param *pointer Pointer to the relevant wimp event block, or
1183 * NULL for an Adjust click.
1184 * \return true if the event was handled; else false.
1185 */
1186
ro_toolbar_menu_prepare(wimp_w w,wimp_i i,wimp_menu * menu,wimp_pointer * pointer)1187 bool ro_toolbar_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
1188 wimp_pointer *pointer)
1189 {
1190 struct toolbar *toolbar;
1191
1192 toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(w);
1193
1194 if (toolbar == NULL)
1195 return false;
1196
1197 /* Pass the event on to potentially interested widgets. */
1198
1199 if (toolbar->url != NULL && ro_gui_url_bar_menu_prepare(toolbar->url,
1200 i, menu, pointer))
1201 return true;
1202
1203 /* Try to process the event as a toolbar menu. */
1204
1205 if (menu != toolbar_menu)
1206 return false;
1207
1208 /* Shade menu entries according to the state of the window and object
1209 * under the pointer.
1210 */
1211
1212 /* Toolbar (Sub)Menu */
1213
1214 ro_gui_menu_set_entry_shaded(menu, TOOLBAR_EDIT,
1215 ro_toolbar_menu_edit_shade(toolbar));
1216 ro_gui_menu_set_entry_ticked(menu, TOOLBAR_EDIT,
1217 ro_toolbar_menu_edit_tick(toolbar));
1218
1219 ro_gui_menu_set_entry_shaded(menu, TOOLBAR_BUTTONS,
1220 ro_toolbar_menu_option_shade(toolbar) ||
1221 toolbar->buttons == NULL);
1222 ro_gui_menu_set_entry_ticked(menu, TOOLBAR_BUTTONS,
1223 ro_toolbar_menu_buttons_tick(toolbar) &&
1224 toolbar->buttons != NULL);
1225
1226 ro_gui_menu_set_entry_shaded(menu, TOOLBAR_ADDRESS_BAR,
1227 ro_toolbar_menu_edit_shade(toolbar) ||
1228 toolbar->url == NULL);
1229 ro_gui_menu_set_entry_ticked(menu, TOOLBAR_ADDRESS_BAR,
1230 ro_toolbar_menu_url_tick(toolbar) &&
1231 toolbar->url != NULL);
1232
1233 ro_gui_menu_set_entry_shaded(menu, TOOLBAR_THROBBER,
1234 ro_toolbar_menu_edit_shade(toolbar) ||
1235 toolbar->throbber == NULL);
1236 ro_gui_menu_set_entry_ticked(menu, TOOLBAR_THROBBER,
1237 ro_toolbar_menu_throbber_tick(toolbar) &&
1238 toolbar->throbber != NULL);
1239
1240 return true;
1241 }
1242
1243
1244 /**
1245 * Handle submenu warnings for the toolbar menu
1246 *
1247 * \param w The window owning the menu.
1248 * \param i The icon owning the menu.
1249 * \param *menu The menu to which the warning applies.
1250 * \param *selection The wimp menu selection data.
1251 * \param action The selected menu action.
1252 */
1253
ro_toolbar_menu_warning(wimp_w w,wimp_i i,wimp_menu * menu,wimp_selection * selection,menu_action action)1254 void ro_toolbar_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
1255 wimp_selection *selection, menu_action action)
1256 {
1257 /* Do nothing */
1258 }
1259
1260
1261 /**
1262 * Handle selections from the toolbar menu
1263 *
1264 * \param w The window owning the menu.
1265 * \param i The icon owning the menu.
1266 * \param *menu The menu from which the selection was made.
1267 * \param *selection The wimp menu selection data.
1268 * \param action The selected menu action.
1269 * \return true if action accepted; else false.
1270 */
1271
ro_toolbar_menu_select(wimp_w w,wimp_i i,wimp_menu * menu,wimp_selection * selection,menu_action action)1272 bool ro_toolbar_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
1273 wimp_selection *selection, menu_action action)
1274 {
1275 struct toolbar *toolbar;
1276
1277 toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(w);
1278
1279 if (toolbar == NULL)
1280 return false;
1281
1282 /* Pass the event on to potentially interested widgets. */
1283
1284 if (toolbar->url != NULL && ro_gui_url_bar_menu_select(toolbar->url,
1285 i, menu, selection, action))
1286 return true;
1287
1288 /* Try to process the event as a toolbar menu. */
1289
1290 if (menu != toolbar_menu)
1291 return false;
1292
1293 switch (action) {
1294 case TOOLBAR_BUTTONS:
1295 ro_toolbar_set_display_buttons(toolbar,
1296 !ro_toolbar_get_display_buttons(toolbar));
1297 break;
1298 case TOOLBAR_ADDRESS_BAR:
1299 ro_toolbar_set_display_url(toolbar,
1300 !ro_toolbar_get_display_url(toolbar));
1301 if (ro_toolbar_get_display_url(toolbar))
1302 ro_toolbar_take_caret(toolbar);
1303 break;
1304 case TOOLBAR_THROBBER:
1305 ro_toolbar_set_display_throbber(toolbar,
1306 !ro_toolbar_get_display_throbber(toolbar));
1307 break;
1308 case TOOLBAR_EDIT:
1309 ro_toolbar_toggle_edit(toolbar);
1310 break;
1311 default:
1312 return false;
1313 }
1314
1315 return true;
1316 }
1317
1318
1319 /**
1320 * Translate the contents of a message_HELP_REQUEST into a suffix for a
1321 * NetSurf message token. The help system will then add this to whatever
1322 * prefix the current toolbar has registered with WimpEvent.
1323 *
1324 * \param w The window handle under the mouse.
1325 * \param i The icon handle under the mouse.
1326 * \param *pos The mouse position.
1327 * \param buttons The mouse button state.
1328 * \return The required help token suffix.
1329 */
1330
ro_toolbar_get_help_suffix(wimp_w w,wimp_i i,os_coord * pos,wimp_mouse_state buttons)1331 const char *ro_toolbar_get_help_suffix(wimp_w w, wimp_i i, os_coord *pos,
1332 wimp_mouse_state buttons)
1333 {
1334 struct toolbar *toolbar;
1335 wimp_window_state state;
1336 os_error *error;
1337 const char *suffix;
1338
1339 toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(w);
1340
1341 if (toolbar == NULL || toolbar->toolbar_handle != w)
1342 return NULL;
1343
1344 state.w = toolbar->toolbar_handle;
1345 error = xwimp_get_window_state(&state);
1346 if (error) {
1347 NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
1348 error->errnum, error->errmess);
1349 ro_warn_user("WimpError", error->errmess);
1350 return NULL;
1351 }
1352
1353 /* Pass the help request around the toolbar widgets. */
1354
1355 if (toolbar->throbber != NULL && toolbar->throbber_display &&
1356 ro_gui_throbber_help_suffix(toolbar->throbber, i,
1357 pos, &state, buttons, &suffix))
1358 return suffix;
1359
1360 if (toolbar->url != NULL && toolbar->url_display &&
1361 ro_gui_url_bar_help_suffix(toolbar->url, i,
1362 pos, &state, buttons, &suffix))
1363 return suffix;
1364
1365 if (toolbar->buttons != NULL && toolbar->buttons_display &&
1366 ro_gui_button_bar_help_suffix(toolbar->buttons, i,
1367 pos, &state, buttons, &suffix))
1368 return suffix;
1369
1370 return "";
1371 }
1372
1373
1374 /* This is an exported interface documented in toolbar.h */
1375
ro_toolbar_update_client_data(struct toolbar * toolbar,void * client_data)1376 void ro_toolbar_update_client_data(struct toolbar *toolbar, void *client_data)
1377 {
1378 if (toolbar != NULL)
1379 toolbar->client_data = client_data;
1380 }
1381
1382
1383 /* This is an exported interface documented in toolbar.h */
1384
ro_toolbar_update_all_buttons(void)1385 void ro_toolbar_update_all_buttons(void)
1386 {
1387 struct toolbar *bar;
1388
1389 bar = ro_toolbar_bars;
1390 while (bar != NULL) {
1391 ro_toolbar_update_buttons(bar);
1392
1393 bar = bar->next;
1394 }
1395 }
1396
1397
1398 /**
1399 * Update the state of a toolbar's buttons.
1400 *
1401 * \param toolbar the toolbar to update
1402 */
1403
ro_toolbar_update_buttons(struct toolbar * toolbar)1404 void ro_toolbar_update_buttons(struct toolbar *toolbar)
1405 {
1406 assert(toolbar != NULL);
1407
1408 if (toolbar->callbacks != NULL &&
1409 toolbar->callbacks->update_buttons != NULL)
1410 toolbar->callbacks->update_buttons(toolbar->client_data);
1411 }
1412
1413 /* This is an exported interface documented in toolbar.h */
1414
ro_toolbar_refresh(struct toolbar * toolbar)1415 void ro_toolbar_refresh(struct toolbar *toolbar)
1416 {
1417 assert(toolbar != NULL);
1418
1419 ro_toolbar_process(toolbar, -1, true);
1420 if (toolbar->callbacks != NULL &&
1421 toolbar->callbacks->change_size != NULL)
1422 toolbar->callbacks->change_size(toolbar->client_data);
1423
1424 if (toolbar->toolbar_handle != NULL)
1425 xwimp_force_redraw(toolbar->toolbar_handle, 0, 0,
1426 toolbar->current_width,
1427 toolbar->current_height);
1428 }
1429
1430
1431 /* This is an exported interface documented in toolbar.h */
1432
ro_toolbar_theme_update(void)1433 void ro_toolbar_theme_update(void)
1434 {
1435 struct toolbar *bar, *next;
1436 bool ok;
1437
1438 bar = ro_toolbar_bars;
1439 while (bar != NULL) {
1440 /* Take the next bar address now, as *bar may become invalid
1441 * during the update process (if an update fails and
1442 * ro_toolbar_destroy() is called) and we don't want to lose
1443 * the link to the rest of the chain.
1444 */
1445
1446 next = bar->next;
1447
1448 /* Only process the bar if the theme is set to the default.
1449 * Otherwise, it's up to the owner to do whatever they need
1450 * to do for themselves.
1451 */
1452
1453 if (bar->theme == NULL) {
1454 ok = ro_toolbar_rebuild(bar);
1455
1456 if (!ok)
1457 ro_toolbar_destroy(bar);
1458 } else {
1459 ok = true;
1460 }
1461
1462 if (bar->callbacks != NULL &&
1463 bar->callbacks->theme_update != NULL)
1464 bar->callbacks->theme_update(bar->client_data, ok);
1465
1466 bar = next;
1467 }
1468 }
1469
1470
1471 /* This is an exported interface documented in toolbar.h */
1472
ro_toolbar_parent_window_lookup(wimp_w w)1473 struct toolbar *ro_toolbar_parent_window_lookup(wimp_w w)
1474 {
1475 struct toolbar *toolbar;
1476
1477 toolbar = ro_toolbar_bars;
1478 while (toolbar != NULL && toolbar->parent_handle != w)
1479 toolbar = toolbar->next;
1480
1481 return toolbar;
1482 }
1483
1484
1485 /* This is an exported interface documented in toolbar.h */
1486
ro_toolbar_window_lookup(wimp_w w)1487 struct toolbar *ro_toolbar_window_lookup(wimp_w w)
1488 {
1489 struct toolbar *toolbar;
1490
1491 toolbar = ro_toolbar_bars;
1492 while (toolbar != NULL && toolbar->toolbar_handle != w)
1493 toolbar = toolbar->next;
1494
1495 return toolbar;
1496 }
1497
1498
1499 /* This is an exported interface documented in toolbar.h */
1500
ro_toolbar_get_parent_window(struct toolbar * toolbar)1501 wimp_w ro_toolbar_get_parent_window(struct toolbar *toolbar)
1502 {
1503 return (toolbar != NULL) ? toolbar->parent_handle : 0;
1504 }
1505
1506
1507 /* This is an exported interface documented in toolbar.h */
1508
ro_toolbar_get_window(struct toolbar * toolbar)1509 wimp_w ro_toolbar_get_window(struct toolbar *toolbar)
1510 {
1511 return (toolbar != NULL) ? toolbar->toolbar_handle : 0;
1512 }
1513
1514
1515 /* This is an exported interface documented in toolbar.h */
1516
ro_toolbar_height(struct toolbar * toolbar)1517 int ro_toolbar_height(struct toolbar *toolbar)
1518 {
1519 return (toolbar == NULL) ? 0 : toolbar->current_height;
1520 }
1521
1522
1523 /* This is an exported interface documented in toolbar.h */
1524
ro_toolbar_full_height(struct toolbar * toolbar)1525 int ro_toolbar_full_height(struct toolbar *toolbar)
1526 {
1527 return (toolbar == NULL) ? 0 : toolbar->full_height;
1528 }
1529
1530
1531 /* This is an exported interface documented in toolbar.h */
1532
ro_toolbar_start_throbbing(struct toolbar * toolbar)1533 void ro_toolbar_start_throbbing(struct toolbar *toolbar)
1534 {
1535 if (toolbar != NULL && toolbar->throbber != NULL)
1536 ro_gui_throbber_animate(toolbar->throbber);
1537 }
1538
1539
1540 /* This is an exported interface documented in toolbar.h */
ro_toolbar_stop_throbbing(struct toolbar * toolbar)1541 void ro_toolbar_stop_throbbing(struct toolbar *toolbar)
1542 {
1543 if (toolbar != NULL && toolbar->throbber != NULL)
1544 ro_gui_throbber_stop(toolbar->throbber);
1545 }
1546
1547
1548 /* This is an exported interface documented in toolbar.h */
ro_toolbar_page_info_change(struct toolbar * toolbar)1549 void ro_toolbar_page_info_change(struct toolbar *toolbar)
1550 {
1551 if (toolbar == NULL || toolbar->url == NULL)
1552 return;
1553
1554 ro_gui_url_bar_page_info_change(toolbar->url);
1555 }
1556
1557
1558 /* This is an exported interface documented in toolbar.h */
ro_toolbar_throb(struct toolbar * toolbar)1559 void ro_toolbar_throb(struct toolbar *toolbar)
1560 {
1561 if (toolbar != NULL && toolbar->throbber != NULL)
1562 ro_gui_throbber_animate(toolbar->throbber);
1563 }
1564
1565
1566 /* This is an exported interface documented in toolbar.h */
1567
ro_toolbar_set_button_order(struct toolbar * toolbar,char order[])1568 bool ro_toolbar_set_button_order(struct toolbar *toolbar, char order[])
1569 {
1570 if (toolbar == NULL || toolbar->buttons == NULL)
1571 return false;
1572
1573 if (!ro_gui_button_bar_arrange_buttons(toolbar->buttons, order))
1574 return false;
1575
1576 ro_toolbar_refresh_widget_dimensions(toolbar);
1577
1578 return ro_toolbar_process(toolbar, -1, true);
1579 }
1580
1581
1582 /* This is an exported interface documented in toolbar.h */
1583
ro_toolbar_set_button_shaded_state(struct toolbar * toolbar,button_bar_action action,bool shaded)1584 void ro_toolbar_set_button_shaded_state(struct toolbar *toolbar,
1585 button_bar_action action, bool shaded)
1586 {
1587 if (toolbar == NULL || toolbar->buttons == NULL)
1588 return;
1589
1590 ro_gui_button_bar_shade_button(toolbar->buttons, action, shaded);
1591 }
1592
1593
1594 /* This is an exported interface documented in toolbar.h */
1595
ro_toolbar_take_caret(struct toolbar * toolbar)1596 bool ro_toolbar_take_caret(struct toolbar *toolbar)
1597 {
1598 if (toolbar == NULL || toolbar->url == NULL || !toolbar->url_display)
1599 return false;
1600
1601 return ro_gui_url_bar_take_caret(toolbar->url);
1602 }
1603
1604
1605 /* This is an exported interface documented in toolbar.h */
1606
ro_toolbar_set_url(struct toolbar * toolbar,const char * url,bool is_utf8,bool set_caret)1607 void ro_toolbar_set_url(struct toolbar *toolbar, const char *url,
1608 bool is_utf8, bool set_caret)
1609 {
1610 if (toolbar != NULL && toolbar->url != NULL)
1611 ro_gui_url_bar_set_url(toolbar->url, url, is_utf8, set_caret);
1612 }
1613
1614
1615 /* This is an exported interface documented in toolbar.h */
1616
ro_toolbar_get_url(struct toolbar * toolbar)1617 const char *ro_toolbar_get_url(struct toolbar *toolbar)
1618 {
1619 if (toolbar == NULL || toolbar->url == NULL)
1620 return NULL;
1621
1622 return ro_gui_url_bar_get_url(toolbar->url);
1623 }
1624
1625
1626 /* This is an exported interface documented in toolbar.h */
1627
ro_toolbar_update_all_hotlists(void)1628 void ro_toolbar_update_all_hotlists(void)
1629 {
1630 struct toolbar *bar;
1631
1632 bar = ro_toolbar_bars;
1633 while (bar != NULL) {
1634 ro_toolbar_update_hotlist(bar);
1635
1636 bar = bar->next;
1637 }
1638 }
1639
1640
1641 /* This is an exported interface documented in toolbar.h */
1642
ro_toolbar_update_hotlist(struct toolbar * toolbar)1643 void ro_toolbar_update_hotlist(struct toolbar *toolbar)
1644 {
1645 if (toolbar == NULL || toolbar->url == NULL)
1646 return;
1647
1648 ro_gui_url_bar_update_hotlist(toolbar->url);
1649 }
1650
1651
1652 /* This is an exported interface documented in toolbar.h */
1653
ro_toolbar_get_url_field_extent(struct toolbar * toolbar,os_box * extent)1654 bool ro_toolbar_get_url_field_extent(struct toolbar *toolbar, os_box *extent)
1655 {
1656 if (toolbar == NULL || toolbar->url == NULL)
1657 return false;
1658
1659 if (extent == NULL)
1660 return true;
1661
1662 return ro_gui_url_bar_get_url_extent(toolbar->url, extent);
1663 }
1664
1665
1666 /* This is an exported interface documented in toolbar.h */
ro_toolbar_set_site_favicon(struct toolbar * toolbar,struct hlcache_handle * h)1667 void ro_toolbar_set_site_favicon(struct toolbar *toolbar,
1668 struct hlcache_handle *h)
1669 {
1670 if (toolbar == NULL || toolbar->url == NULL)
1671 return;
1672
1673 ro_gui_url_bar_set_site_favicon(toolbar->url, h);
1674 }
1675
1676
1677 /* This is an exported interface documented in toolbar.h */
ro_toolbar_set_content_favicon(struct toolbar * toolbar,struct gui_window * g)1678 void ro_toolbar_set_content_favicon(struct toolbar *toolbar,
1679 struct gui_window *g)
1680 {
1681 if (toolbar == NULL || toolbar->url == NULL)
1682 return;
1683
1684 ro_gui_url_bar_set_content_favicon(toolbar->url, g);
1685 }
1686
1687
1688 /* This is an exported interface documented in toolbar.h */
1689
ro_toolbar_update_urlsuggest(struct toolbar * toolbar)1690 void ro_toolbar_update_urlsuggest(struct toolbar *toolbar)
1691 {
1692 if (toolbar == NULL || toolbar->url == NULL)
1693 return;
1694
1695 ro_gui_url_bar_update_urlsuggest(toolbar->url);
1696 }
1697
1698
1699 /* This is an exported interface documented in toolbar.h */
1700
ro_toolbar_set_display_buttons(struct toolbar * toolbar,bool display)1701 void ro_toolbar_set_display_buttons(struct toolbar *toolbar, bool display)
1702 {
1703 if (toolbar == NULL || toolbar->buttons == NULL)
1704 return;
1705
1706 toolbar->buttons_display = display;
1707 ro_gui_button_bar_hide(toolbar->buttons, !display);
1708 ro_toolbar_refresh_widget_dimensions(toolbar);
1709 ro_toolbar_refresh(toolbar);
1710 }
1711
1712
1713 /* This is an exported interface documented in toolbar.h */
1714
ro_toolbar_set_display_url(struct toolbar * toolbar,bool display)1715 void ro_toolbar_set_display_url(struct toolbar *toolbar, bool display)
1716 {
1717 if (toolbar == NULL || toolbar->url == NULL)
1718 return;
1719
1720 toolbar->url_display = display;
1721 ro_gui_url_bar_hide(toolbar->url, !display);
1722 ro_toolbar_refresh_widget_dimensions(toolbar);
1723 ro_toolbar_refresh(toolbar);
1724 }
1725
1726
1727 /* This is an exported interface documented in toolbar.h */
1728
ro_toolbar_set_display_throbber(struct toolbar * toolbar,bool display)1729 void ro_toolbar_set_display_throbber(struct toolbar *toolbar, bool display)
1730 {
1731 if (toolbar == NULL || toolbar->throbber == NULL)
1732 return;
1733
1734 toolbar->throbber_display = display;
1735 ro_gui_throbber_hide(toolbar->throbber, !display);
1736 ro_toolbar_refresh_widget_dimensions(toolbar);
1737 ro_toolbar_refresh(toolbar);
1738 }
1739
1740
1741 /* This is an exported interface documented in toolbar.h */
1742
ro_toolbar_get_display_buttons(struct toolbar * toolbar)1743 bool ro_toolbar_get_display_buttons(struct toolbar *toolbar)
1744 {
1745 return (toolbar == NULL || toolbar->buttons == NULL) ?
1746 false : toolbar->buttons_display;
1747 }
1748
1749
1750 /* This is an exported interface documented in toolbar.h */
1751
ro_toolbar_get_display_url(struct toolbar * toolbar)1752 bool ro_toolbar_get_display_url(struct toolbar *toolbar)
1753 {
1754 return (toolbar == NULL || toolbar->url == NULL) ?
1755 false : toolbar->url_display;
1756 }
1757
1758
1759 /* This is an exported interface documented in toolbar.h */
1760
ro_toolbar_get_display_throbber(struct toolbar * toolbar)1761 bool ro_toolbar_get_display_throbber(struct toolbar *toolbar)
1762 {
1763 return (toolbar == NULL || toolbar->throbber == NULL) ?
1764 false : toolbar->throbber_display;
1765 }
1766
1767
1768 /* This is an exported interface documented in toolbar.h */
1769
ro_toolbar_get_editing(struct toolbar * toolbar)1770 bool ro_toolbar_get_editing(struct toolbar *toolbar)
1771 {
1772 return (toolbar == NULL || !toolbar->editing) ? false : true;
1773 }
1774
1775
1776 /* This is an exported interface documented in toolbar.h */
1777
ro_toolbar_toggle_edit(struct toolbar * toolbar)1778 bool ro_toolbar_toggle_edit(struct toolbar *toolbar)
1779 {
1780 if (toolbar == NULL || toolbar->editor == NULL)
1781 return false;
1782
1783 toolbar->editing = !toolbar->editing;
1784
1785 ro_gui_button_bar_hide(toolbar->editor, !toolbar->editing);
1786 ro_gui_button_bar_hide(toolbar->buttons,
1787 !toolbar->buttons_display && !toolbar->editing);
1788
1789 if (!ro_toolbar_rebuild(toolbar)) {
1790 ro_toolbar_destroy(toolbar);
1791 return false;
1792 }
1793
1794 ro_toolbar_refresh(toolbar);
1795
1796 /* If there's a callback registered and an edit has finished,
1797 * tell out client what the new button state is.
1798 */
1799
1800 if (!toolbar->editing && toolbar->buttons != NULL &&
1801 toolbar->callbacks != NULL &&
1802 toolbar->callbacks->save_buttons != NULL) {
1803 char *new_buttons;
1804 new_buttons = ro_gui_button_bar_get_config(toolbar->buttons);
1805 toolbar->callbacks->save_buttons(toolbar->client_data,
1806 new_buttons);
1807 }
1808
1809 return true;
1810 }
1811
1812