NetSurf
menus.c
Go to the documentation of this file.
1/*
2 * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
3 * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
4 * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
5 * Copyright 2005 Richard Wilson <info@tinct.net>
6 *
7 * This file is part of NetSurf, http://www.netsurf-browser.org/
8 *
9 * NetSurf is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * NetSurf is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22/**
23 * \file
24 * Menu creation and handling implementation.
25 */
26
27#include <ctype.h>
28#include <stdlib.h>
29#include <string.h>
30#include <stddef.h>
31#include "oslib/os.h"
32#include "oslib/osbyte.h"
33#include "oslib/osgbpb.h"
34#include "oslib/territory.h"
35#include "oslib/wimp.h"
36
37#include "utils/log.h"
38#include "utils/messages.h"
39#include "utils/utf8.h"
41#include "desktop/searchweb.h"
42
43#include "riscos/dialog.h"
44#include "riscos/configure.h"
45#include "riscos/cookies.h"
46#include "riscos/gui.h"
48#include "riscos/help.h"
49#include "riscos/hotlist.h"
50#include "riscos/menus.h"
51#include "utils/nsoption.h"
52#include "riscos/save.h"
53#include "riscos/tinct.h"
54#include "riscos/toolbar.h"
55#include "riscos/url_suggest.h"
56#include "riscos/wimp.h"
57#include "riscos/wimp_event.h"
58#include "riscos/ucstables.h"
59
61 menu_action action; /**< menu action */
62 wimp_menu_entry *menu_entry; /**< corresponding menu entry */
63 const char *entry_key; /**< Messages key for entry text */
64 struct menu_definition_entry *next; /**< next menu entry */
65};
66
68 wimp_menu *menu; /**< corresponding menu */
69 const char *title_key; /**< Messages key for title text */
70 int current_encoding; /**< Identifier for current text encoding of menu text (as per OS_Byte,71,127) */
71 struct menu_definition_entry *entries; /**< menu entries */
72 struct menu_definition *next; /**< next menu */
73};
74
75static void ro_gui_menu_closed(void);
76static void ro_gui_menu_define_menu_add(struct menu_definition *definition,
77 const struct ns_menu *menu, int depth,
78 wimp_menu_entry *parent_entry,
79 int first, int last, const char *prefix, int prefix_length);
80static struct menu_definition *ro_gui_menu_find_menu(wimp_menu *menu);
81static struct menu_definition_entry *ro_gui_menu_find_entry(wimp_menu *menu,
83static menu_action ro_gui_menu_find_action(wimp_menu *menu,
84 wimp_menu_entry *menu_entry);
85static int ro_gui_menu_get_checksum(void);
86static bool ro_gui_menu_translate(struct menu_definition *menu);
87
88
89/* default menu item flags */
90#define DEFAULT_FLAGS (wimp_ICON_TEXT | wimp_ICON_FILLED | \
91 (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | \
92 (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT))
93
94/** The currently defined menus to perform actions for */
96/** The current menu being worked with (may not be open) */
97wimp_menu *current_menu;
98/** Whether a menu is currently open */
99bool current_menu_open = false;
100/** Window that owns the current menu */
102/** Icon that owns the current menu (only valid for popup menus) */
103static wimp_i current_menu_icon;
104/** The available menus */
106
107/* the values given in PRM 3-157 for how to check menus/windows are
108 * incorrect so we use a hack of checking if the sub-menu has bit 0
109 * set which is undocumented but true of window handles on
110 * all target OS versions */
111#define IS_MENU(menu) !((int)(menu) & 1)
112
113/**
114 * Create menu structures.
115 */
116
117/**
118 * create a search provider menu.
119 *
120 * The menu is limited to 40 entries which ought to be sufficient
121 */
122static wimp_menu *ro_gui_menu_init_search_provider(void)
123{
124 static struct ns_menu search_provider_definition = {
125 "SearchProvider", {
126 { "searchprovider00", NO_ACTION, 0 },
127 { "searchprovider01", NO_ACTION, 0 },
128 { "searchprovider02", NO_ACTION, 0 },
129 { "searchprovider03", NO_ACTION, 0 },
130 { "searchprovider04", NO_ACTION, 0 },
131 { "searchprovider05", NO_ACTION, 0 },
132 { "searchprovider06", NO_ACTION, 0 },
133 { "searchprovider07", NO_ACTION, 0 },
134 { "searchprovider08", NO_ACTION, 0 },
135 { "searchprovider09", NO_ACTION, 0 },
136 { "searchprovider10", NO_ACTION, 0 },
137 { "searchprovider11", NO_ACTION, 0 },
138 { "searchprovider12", NO_ACTION, 0 },
139 { "searchprovider13", NO_ACTION, 0 },
140 { "searchprovider14", NO_ACTION, 0 },
141 { "searchprovider15", NO_ACTION, 0 },
142 { "searchprovider16", NO_ACTION, 0 },
143 { "searchprovider17", NO_ACTION, 0 },
144 { "searchprovider18", NO_ACTION, 0 },
145 { "searchprovider19", NO_ACTION, 0 },
146 { "searchprovider20", NO_ACTION, 0 },
147 { "searchprovider21", NO_ACTION, 0 },
148 { "searchprovider22", NO_ACTION, 0 },
149 { "searchprovider23", NO_ACTION, 0 },
150 { "searchprovider24", NO_ACTION, 0 },
151 { "searchprovider25", NO_ACTION, 0 },
152 { "searchprovider26", NO_ACTION, 0 },
153 { "searchprovider27", NO_ACTION, 0 },
154 { "searchprovider28", NO_ACTION, 0 },
155 { "searchprovider29", NO_ACTION, 0 },
156 { "searchprovider30", NO_ACTION, 0 },
157 { "searchprovider31", NO_ACTION, 0 },
158 { "searchprovider32", NO_ACTION, 0 },
159 { "searchprovider33", NO_ACTION, 0 },
160 { "searchprovider34", NO_ACTION, 0 },
161 { "searchprovider35", NO_ACTION, 0 },
162 { "searchprovider36", NO_ACTION, 0 },
163 { "searchprovider37", NO_ACTION, 0 },
164 { "searchprovider38", NO_ACTION, 0 },
165 { "searchprovider39", NO_ACTION, 0 },
166 { NULL, 0, 0 }
167 }
168 };
169 ssize_t iter = -1;
170 const char *name;
171 unsigned int provider = 0;
172
173 iter = search_web_iterate_providers(iter, &name);
174 while ((iter != -1) &&
175 (search_provider_definition.entries[provider].text != NULL)) {
176 messages_add_key_value(search_provider_definition.entries[provider].text, name);
177 provider++;
178 iter = search_web_iterate_providers(iter, &name);
179 }
180 search_provider_definition.entries[provider].text = NULL;
181
182 return ro_gui_menu_define_menu(&search_provider_definition);
183}
184
186{
187 /* image quality menu */
188 static const struct ns_menu images_definition = {
189 "Display", {
190 { "ImgStyle0", NO_ACTION, 0 },
191 { "ImgStyle1", NO_ACTION, 0 },
192 { "ImgStyle2", NO_ACTION, 0 },
193 { "ImgStyle3", NO_ACTION, 0 },
194 {NULL, 0, 0}
195 }
196 };
197 image_quality_menu = ro_gui_menu_define_menu(&images_definition);
198
199 /* proxy menu */
200 static const struct ns_menu proxy_type_definition = {
201 "ProxyType", {
202 { "ProxyNone", NO_ACTION, 0 },
203 { "ProxyNoAuth", NO_ACTION, 0 },
204 { "ProxyBasic", NO_ACTION, 0 },
205 { "ProxyNTLM", NO_ACTION, 0 },
206 {NULL, 0, 0}
207 }
208 };
209 proxy_type_menu = ro_gui_menu_define_menu(&proxy_type_definition);
210
211 /* special case menus */
213
214 /* Note: This table *must* be kept in sync with the LangNames file */
215 static const struct ns_menu lang_definition = {
216 "Languages", {
217 { "lang_af", NO_ACTION, 0 },
218 { "lang_bm", NO_ACTION, 0 },
219 { "lang_ca", NO_ACTION, 0 },
220 { "lang_cs", NO_ACTION, 0 },
221 { "lang_cy", NO_ACTION, 0 },
222 { "lang_da", NO_ACTION, 0 },
223 { "lang_de", NO_ACTION, 0 },
224 { "lang_en", NO_ACTION, 0 },
225 { "lang_es", NO_ACTION, 0 },
226 { "lang_et", NO_ACTION, 0 },
227 { "lang_eu", NO_ACTION, 0 },
228 { "lang_ff", NO_ACTION, 0 },
229 { "lang_fi", NO_ACTION, 0 },
230 { "lang_fr", NO_ACTION, 0 },
231 { "lang_ga", NO_ACTION, 0 },
232 { "lang_gl", NO_ACTION, 0 },
233 { "lang_ha", NO_ACTION, 0 },
234 { "lang_hr", NO_ACTION, 0 },
235 { "lang_hu", NO_ACTION, 0 },
236 { "lang_id", NO_ACTION, 0 },
237 { "lang_is", NO_ACTION, 0 },
238 { "lang_it", NO_ACTION, 0 },
239 { "lang_lt", NO_ACTION, 0 },
240 { "lang_lv", NO_ACTION, 0 },
241 { "lang_ms", NO_ACTION, 0 },
242 { "lang_mt", NO_ACTION, 0 },
243 { "lang_nl", NO_ACTION, 0 },
244 { "lang_no", NO_ACTION, 0 },
245 { "lang_pl", NO_ACTION, 0 },
246 { "lang_pt", NO_ACTION, 0 },
247 { "lang_rn", NO_ACTION, 0 },
248 { "lang_ro", NO_ACTION, 0 },
249 { "lang_rw", NO_ACTION, 0 },
250 { "lang_sk", NO_ACTION, 0 },
251 { "lang_sl", NO_ACTION, 0 },
252 { "lang_so", NO_ACTION, 0 },
253 { "lang_sq", NO_ACTION, 0 },
254 { "lang_sr", NO_ACTION, 0 },
255 { "lang_sv", NO_ACTION, 0 },
256 { "lang_sw", NO_ACTION, 0 },
257 { "lang_tr", NO_ACTION, 0 },
258 { "lang_uz", NO_ACTION, 0 },
259 { "lang_vi", NO_ACTION, 0 },
260 { "lang_wo", NO_ACTION, 0 },
261 { "lang_xs", NO_ACTION, 0 },
262 { "lang_yo", NO_ACTION, 0 },
263 { "lang_zu", NO_ACTION, 0 },
264 { NULL, 0, 0 }
265 }
266 };
267 languages_menu = ro_gui_menu_define_menu(&lang_definition);
268
270}
271
272
273/**
274 * Display a menu.
275 *
276 * \param *menu Pointer to the menu to be displayed.
277 * \param x The x position.
278 * \param y The y position.
279 * \param w The window that the menu belongs to.
280 */
281
282void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w)
283{
284 os_error *error;
285 struct menu_definition *definition;
286
287 /* translate menu, if necessary (this returns quickly
288 * if there's nothing to be done) */
289 definition = ro_gui_menu_find_menu(menu);
290 if (definition) {
291 if (!ro_gui_menu_translate(definition)) {
292 ro_warn_user("NoMemory", 0);
293 return;
294 }
295 }
296
297 /* store the menu characteristics */
300 current_menu_icon = wimp_ICON_WINDOW;
301
302 /* create the menu */
303 current_menu_open = true;
304 error = xwimp_create_menu(menu, x - 64, y);
305 if (error) {
306 NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
307 error->errnum, error->errmess);
308 ro_warn_user("MenuError", error->errmess);
310 }
311}
312
313
314/**
315 * Display a pop-up menu next to the specified icon.
316 *
317 * \param menu menu to open
318 * \param w window handle
319 * \param i icon handle
320 */
321
322void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i)
323{
324 wimp_window_state state;
325 wimp_icon_state icon_state;
326 os_error *error;
327
328 state.w = w;
329 icon_state.w = w;
330 icon_state.i = i;
331 error = xwimp_get_window_state(&state);
332 if (error) {
333 NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
334 error->errnum, error->errmess);
335 ro_warn_user("MenuError", error->errmess);
336 return;
337 }
338
339 error = xwimp_get_icon_state(&icon_state);
340 if (error) {
341 NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
342 error->errnum, error->errmess);
343 ro_warn_user("MenuError", error->errmess);
344 return;
345 }
346
348 state.visible.x0 + icon_state.icon.extent.x1 + 64,
349 state.visible.y1 + icon_state.icon.extent.y1 -
350 state.yscroll, w);
352}
353
354
355/**
356 * Forcibly close any menu or transient dialogue box that is currently open.
357 */
358
360{
361 os_error *error;
362
363 if (current_menu == NULL)
364 return;
365
366 error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
367 if (error) {
368 NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
369 error->errnum, error->errmess);
370 ro_warn_user("MenuError", error->errmess);
371 }
372
374}
375
376
377/**
378 * Allow the current menu window to change, if the window is deleted and
379 * recreated while a menu is active on an Adjust-click.
380 *
381 * \param from The original window handle.
382 * \param to The new replacement window handle.
383 */
384
386{
387
390}
391
392
393/**
394 * Handle menu selection.
395 */
396
397void ro_gui_menu_selection(wimp_selection *selection)
398{
399 int i; //, j;
400 wimp_menu_entry *menu_entry;
401 menu_action action;
402 wimp_pointer pointer;
403 os_error *error;
404 int previous_menu_icon = current_menu_icon;
405
406 /* if we are using gui_multitask then menu selection events
407 * may be delivered after the menu has been closed. As such,
408 * we simply ignore these events. */
409 if (!current_menu)
410 return;
411
412 assert(current_menu_window);
413
414 /* get the menu entry and associated action and definition */
415 menu_entry = &current_menu->entries[selection->items[0]];
416 for (i = 1; selection->items[i] != -1; i++)
417 menu_entry = &menu_entry->sub_menu->
418 entries[selection->items[i]];
419 action = ro_gui_menu_find_action(current_menu, menu_entry);
420
421 /* Deal with the menu action. If this manages to re-prepare the
422 * menu for re-opening, we test for and act on Adjust clicks.
423 */
424
427 return;
428
429 /* re-open the menu for Adjust clicks */
430 error = xwimp_get_pointer_info(&pointer);
431 if (error) {
432 NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
433 error->errnum, error->errmess);
434 ro_warn_user("WimpError", error->errmess);
436 return;
437 }
438
439 if (pointer.buttons != wimp_CLICK_ADJUST) {
441 return;
442 }
443
445 current_menu_icon = previous_menu_icon;
446}
447
448
449/**
450 * Handle Message_MenuWarning.
451 */
452void ro_gui_menu_warning(wimp_message_menu_warning *warning)
453{
454 int i;
455 menu_action action;
456 wimp_menu_entry *menu_entry;
457 os_error *error;
458
459 assert(current_menu);
460 assert(current_menu_window);
461
462 /* get the sub-menu of the warning */
463 if (warning->selection.items[0] == -1)
464 return;
465 menu_entry = &current_menu->entries[warning->selection.items[0]];
466 for (i = 1; warning->selection.items[i] != -1; i++)
467 menu_entry = &menu_entry->sub_menu->
468 entries[warning->selection.items[i]];
469 action = ro_gui_menu_find_action(current_menu, menu_entry);
470
471 /* Process the warning via Wimp_Event, then register the resulting
472 * submenu with the module.
473 */
474
476 current_menu_icon, current_menu, &(warning->selection),
477 action);
478
479 if (IS_MENU(menu_entry->sub_menu)) {
481 } else {
483 menu_entry->sub_menu);
484
485 /* If this is a dialogue box, remove the close and back icons.
486 */
487
489 menu_entry->sub_menu,
490 wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_BACK_ICON,
491 0);
492 }
493
494 /* open the sub-menu */
495
496 error = xwimp_create_sub_menu(menu_entry->sub_menu,
497 warning->pos.x, warning->pos.y);
498 if (error) {
499 NSLOG(netsurf, INFO, "xwimp_create_sub_menu: 0x%x: %s",
500 error->errnum, error->errmess);
501 ro_warn_user("MenuError", error->errmess);
502 }
503}
504
505
506/**
507 * Handle Message_MenusDeleted, removing our current record of an open menu
508 * if it matches the deleted menu handle.
509 *
510 * \param *deleted The message block.
511 */
512
513void ro_gui_menu_message_deleted(wimp_message_menus_deleted *deleted)
514{
515 if (deleted != NULL && deleted->menu == current_menu)
517}
518
519
520/**
521 * Clean up after a menu has been closed, or forcibly close an open menu.
522 */
523
524static void ro_gui_menu_closed(void)
525{
526 if (current_menu != NULL)
529
530 current_menu = NULL;
531 current_menu_window = NULL;
533 current_menu_open = false;
534}
535
536
537/**
538 * Update the current menu by sending it a Menu Prepare event through wimp_event
539 * and then reopening it if the contents has changed.
540 *
541 * \param *menu The menu to refresh: if 0, the current menu will be
542 * refreshed regardless, otherwise it will be refreshed
543 * only if it matches the supplied handle.
544 */
545
546void ro_gui_menu_refresh(wimp_menu *menu)
547{
548 int checksum = 0;
549
551 return;
552
553 checksum = ro_gui_menu_get_checksum();
554
557 return;
558
559 /* \TODO -- Call the menu's event handler here. */
560
561 if (checksum != ro_gui_menu_get_checksum()) {
562 os_error *error;
563 error = xwimp_create_menu(current_menu, 0, 0);
564 if (error) {
565 NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
566 error->errnum, error->errmess);
567 ro_warn_user("MenuError", error->errmess);
568 }
569 }
570}
571
572
573
574
575/**
576 * Creates a wimp_menu and adds it to the list to handle actions for.
577 *
578 * \param menu The data to create the menu with
579 * \return The menu created, or NULL on failure
580 */
581wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu)
582{
583 struct menu_definition *definition;
584 int entry;
585
586 definition = calloc(sizeof(struct menu_definition), 1);
587 if (!definition) {
588 die("No memory to create menu definition.");
589 return NULL; /* For the benefit of scan-build */
590 }
591
592 /* link in the menu to our list */
593 definition->next = ro_gui_menu_definitions;
594 ro_gui_menu_definitions = definition;
595
596 /* count number of menu entries */
597 for (entry = 0; menu->entries[entry].text; entry++)
598 /* do nothing */;
599
600 /* create our definitions */
601 ro_gui_menu_define_menu_add(definition, menu, 0, NULL,
602 0, entry, NULL, 0);
603
604 /* and translate menu into current encoding */
605 if (!ro_gui_menu_translate(definition))
606 die("No memory to translate menu.");
607
608 return definition->menu;
609}
610
611/**
612 * Create a wimp menu tree from ns_menu data.
613 * This function does *not* deal with the menu textual content - it simply
614 * creates and populates the appropriate structures. Textual content is
615 * generated by ro_gui_menu_translate_menu()
616 *
617 * \param definition Top level menu definition
618 * \param menu Menu declaration data
619 * \param depth Depth of menu we're currently building
620 * \param parent_entry Entry in parent menu, or NULL if root menu
621 * \param first First index in declaration data that is used by this menu
622 * \param last Last index in declaration data that is used by this menu
623 * \param prefix Prefix pf menu declaration string already seen
624 * \param prefix_length Length of prefix
625 */
627 const struct ns_menu *menu, int depth,
628 wimp_menu_entry *parent_entry, int first, int last,
629 const char *prefix, int prefix_length)
630{
631 int entry;
632 int entries = 0;
633 int matches[last - first + 1];
634 const char *text, *menu_text;
635 wimp_menu *new_menu;
636 struct menu_definition_entry *definition_entry;
637
638 /* step 1: store the matches for depth and subset string */
639 for (entry = first; entry < last; entry++) {
640 const char *match;
641 int cur_depth = 0;
642 match = menu->entries[entry].text;
643
644 /* skip specials at start of string */
645 while (!isalnum(*match))
646 match++;
647
648 /* attempt prefix match */
649 if ((prefix) && (strncmp(match, prefix, prefix_length)))
650 continue;
651
652 /* Find depth of this entry */
653 while (*match)
654 if (*match++ == '.')
655 cur_depth++;
656
657 if (depth == cur_depth)
658 matches[entries++] = entry;
659 }
660 matches[entries] = last;
661
662 /* no entries, so exit */
663 if (entries == 0)
664 return;
665
666 /* step 2: build and link the menu. we must use realloc to stop
667 * our memory fragmenting so we can test for sub-menus easily */
668 new_menu = (wimp_menu *)malloc(wimp_SIZEOF_MENU(entries));
669 if (!new_menu)
670 die("No memory to create menu.");
671
672 if (parent_entry) {
673 /* Fix up sub menu pointer */
674 parent_entry->sub_menu = new_menu;
675 } else {
676 /* Root menu => fill in definition struct */
677 definition->title_key = menu->title;
678 definition->current_encoding = 0;
679 definition->menu = new_menu;
680 }
681
682 /* this is fixed up in ro_gui_menu_translate() */
683 new_menu->title_data.indirected_text.text = NULL;
684
685 /* fill in menu flags */
686 ro_gui_menu_init_structure(new_menu, entries);
687
688 /* and then create the entries */
689 for (entry = 0; entry < entries; entry++) {
690 /* add the entry */
691 int id = matches[entry];
692
693 text = menu->entries[id].text;
694
695 /* fill in menu flags from specials at start of string */
696 new_menu->entries[entry].menu_flags = 0;
697 while (!isalnum(*text)) {
698 if (*text == '_')
699 new_menu->entries[entry].menu_flags |=
700 wimp_MENU_SEPARATE;
701 text++;
702 }
703
704 /* get messages key for menu entry */
705 menu_text = strrchr(text, '.');
706 if (!menu_text)
707 /* no '.' => top-level entry */
708 menu_text = text;
709 else
710 menu_text++; /* and move past the '.' */
711
712 /* fill in submenu data */
713 if (menu->entries[id].sub_window)
714 new_menu->entries[entry].sub_menu =
715 (wimp_menu *) (*menu->entries[id].sub_window);
716
717 /* this is fixed up in ro_gui_menu_translate() */
718 new_menu->entries[entry].data.indirected_text.text = NULL;
719
720 /* create definition entry */
721 definition_entry =
722 malloc(sizeof(struct menu_definition_entry));
723 if (!definition_entry)
724 die("Unable to create menu definition entry");
725 definition_entry->action = menu->entries[id].action;
726 definition_entry->menu_entry = &new_menu->entries[entry];
727 definition_entry->entry_key = menu_text;
728 definition_entry->next = definition->entries;
729 definition->entries = definition_entry;
730
731 /* recurse */
732 if (new_menu->entries[entry].sub_menu == wimp_NO_SUB_MENU) {
733 ro_gui_menu_define_menu_add(definition, menu,
734 depth + 1, &new_menu->entries[entry],
735 matches[entry], matches[entry + 1],
736 text, strlen(text));
737 }
738
739 /* give menu warnings */
740 if (new_menu->entries[entry].sub_menu != wimp_NO_SUB_MENU)
741 new_menu->entries[entry].menu_flags |=
742 wimp_MENU_GIVE_WARNING;
743 }
744 new_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED;
745 new_menu->entries[entries - 1].menu_flags |= wimp_MENU_LAST;
746}
747
748
749/**
750 * Initialise the basic state of a menu structure so all entries are
751 * indirected text with no flags, no submenu.
752 */
753void ro_gui_menu_init_structure(wimp_menu *menu, int entries)
754{
755 int i;
756
757 menu->title_fg = wimp_COLOUR_BLACK;
758 menu->title_bg = wimp_COLOUR_LIGHT_GREY;
759 menu->work_fg = wimp_COLOUR_BLACK;
760 menu->work_bg = wimp_COLOUR_WHITE;
761 menu->width = 200;
762 menu->height = wimp_MENU_ITEM_HEIGHT;
763 menu->gap = wimp_MENU_ITEM_GAP;
764
765 for (i = 0; i < entries; i++) {
766 menu->entries[i].menu_flags = 0;
767 menu->entries[i].sub_menu = wimp_NO_SUB_MENU;
768 menu->entries[i].icon_flags =
769 DEFAULT_FLAGS | wimp_ICON_INDIRECTED;
770 menu->entries[i].data.indirected_text.validation =
771 (char *)-1;
772 }
773 menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED;
774 menu->entries[i - 1].menu_flags |= wimp_MENU_LAST;
775}
776
777
778/**
779 * Finds the menu_definition corresponding to a wimp_menu.
780 *
781 * \param menu the menu to find the definition for
782 * \return the associated definition, or NULL if one could not be found
783 */
785{
786 struct menu_definition *definition;
787
788 if (!menu)
789 return NULL;
790
791 for (definition = ro_gui_menu_definitions; definition;
792 definition = definition->next)
793 if (definition->menu == menu)
794 return definition;
795 return NULL;
796}
797
798
799/**
800 * Finds the key associated with a menu entry translation.
801 *
802 * \param menu the menu to search
803 * \param translated the translated text
804 * \return the original message key, or NULL if one could not be found
805 */
807 const char *translated)
808{
809 struct menu_definition_entry *entry;
810 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
811
812 if (!definition)
813 return NULL;
814
815 for (entry = definition->entries; entry; entry = entry->next)
816 if (!strcmp(entry->menu_entry->data.indirected_text.text, translated))
817 return entry->entry_key;
818 return NULL;
819}
820
821
822/**
823 * Finds the menu_definition_entry corresponding to an action for a wimp_menu.
824 *
825 * \param menu the menu to search for an action within
826 * \param action the action to find
827 * \return the associated menu entry, or NULL if one could not be found
828 */
831{
832 struct menu_definition_entry *entry;
833 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
834
835 if (!definition)
836 return NULL;
837
838 for (entry = definition->entries; entry; entry = entry->next)
839 if (entry->action == action)
840 return entry;
841 return NULL;
842}
843
844
845/**
846 * Finds the action corresponding to a wimp_menu_entry for a wimp_menu.
847 *
848 * \param menu the menu to search for an action within
849 * \param menu_entry the menu_entry to find
850 * \return the associated action, or 0 if one could not be found
851 */
852menu_action ro_gui_menu_find_action(wimp_menu *menu, wimp_menu_entry *menu_entry)
853{
854 struct menu_definition_entry *entry;
855 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
856
857 if (!definition)
858 return NO_ACTION;
859
860 for (entry = definition->entries; entry; entry = entry->next) {
861 if (entry->menu_entry == menu_entry)
862 return entry->action;
863 }
864 return NO_ACTION;
865}
866
867
868/**
869 * Sets an action within a menu as having a specific ticked status.
870 *
871 * \param menu the menu containing the action
872 * \param action the action to tick/untick
873 * \param shaded whether to set the item as shaded
874 */
876 bool shaded)
877{
878 struct menu_definition_entry *entry;
879 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
880
881 if (!definition)
882 return;
883
884 /* we can't use find_entry as multiple actions may appear in one menu */
885 for (entry = definition->entries; entry; entry = entry->next)
886 if (entry->action == action) {
887 if (shaded)
888 entry->menu_entry->icon_flags |= wimp_ICON_SHADED;
889 else
890 entry->menu_entry->icon_flags &= ~wimp_ICON_SHADED;
891 }
892}
893
894
895/**
896 * Sets an action within a menu as having a specific ticked status.
897 *
898 * \param menu the menu containing the action
899 * \param action the action to tick/untick
900 * \param ticked whether to set the item as ticked
901 */
903 bool ticked)
904{
905 struct menu_definition_entry *entry =
907 if (entry) {
908 if (ticked)
909 entry->menu_entry->menu_flags |= wimp_MENU_TICKED;
910 else
911 entry->menu_entry->menu_flags &= ~wimp_MENU_TICKED;
912 }
913}
914
915
916/**
917 * Calculates a simple checksum for the current menu state
918 */
920{
921 wimp_selection menu_tree;
922 int i = 0, j, checksum = 0;
923 os_error *error;
924 wimp_menu *menu;
925
927 return 0;
928
929 error = xwimp_get_menu_state((wimp_menu_state_flags)0,
930 &menu_tree, 0, 0);
931 if (error) {
932 NSLOG(netsurf, INFO, "xwimp_get_menu_state: 0x%x: %s",
933 error->errnum, error->errmess);
934 ro_warn_user("MenuError", error->errmess);
935 return 0;
936 }
937
938 menu = current_menu;
939 do {
940 j = 0;
941 do {
942 if (menu->entries[j].icon_flags & wimp_ICON_SHADED)
943 checksum ^= (1 << (i + j * 2));
944 if (menu->entries[j].menu_flags & wimp_MENU_TICKED)
945 checksum ^= (2 << (i + j * 2));
946 } while (!(menu->entries[j++].menu_flags & wimp_MENU_LAST));
947
948 j = menu_tree.items[i++];
949 if (j != -1) {
950 menu = menu->entries[j].sub_menu;
951 if ((!menu) || (menu == wimp_NO_SUB_MENU) || (!IS_MENU(menu)))
952 break;
953 }
954 } while (j != -1);
955
956 return checksum;
957}
958
959/**
960 * Translate a menu's textual content into the system local encoding
961 *
962 * \param menu The menu to translate
963 * \return false if out of memory, true otherwise
964 */
966{
967 os_error *error;
968 int alphabet;
969 struct menu_definition_entry *entry;
970 char *translated;
971 nserror err;
972
973 /* read current alphabet */
974 error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet);
975 if (error) {
976 NSLOG(netsurf, INFO, "failed reading alphabet: 0x%x: %s",
977 error->errnum, error->errmess);
978 /* assume Latin1 */
979 alphabet = territory_ALPHABET_LATIN1;
980 }
981
982 if (menu->current_encoding == alphabet)
983 /* menu text is already in the correct encoding */
984 return true;
985
986 /* translate root menu title text */
987 free(menu->menu->title_data.indirected_text.text);
989 0, &translated);
990 if (err != NSERROR_OK) {
991 assert(err != NSERROR_BAD_ENCODING);
992 NSLOG(netsurf, INFO, "utf8_to_enc failed");
993 return false;
994 }
995
996 /* and fill in WIMP menu field */
997 menu->menu->title_data.indirected_text.text = translated;
998
999 /* now the menu entries */
1000 for (entry = menu->entries; entry; entry = entry->next) {
1001 wimp_menu *submenu = entry->menu_entry->sub_menu;
1002
1003 /* tranlate menu entry text */
1004 free(entry->menu_entry->data.indirected_text.text);
1006 0, &translated);
1007 if (err != NSERROR_OK) {
1008 assert(err != NSERROR_BAD_ENCODING);
1009 NSLOG(netsurf, INFO, "utf8_to_enc failed");
1010 return false;
1011 }
1012
1013 /* fill in WIMP menu fields */
1014 entry->menu_entry->data.indirected_text.text = translated;
1015 entry->menu_entry->data.indirected_text.validation =
1016 (char *) -1;
1017 entry->menu_entry->data.indirected_text.size =
1018 strlen(translated);
1019
1020 /* child menu title - this is the same as the text of
1021 * the parent menu entry, so just copy the pointer */
1022 if (submenu != wimp_NO_SUB_MENU && IS_MENU(submenu)) {
1023 submenu->title_data.indirected_text.text =
1024 translated;
1025 }
1026 }
1027
1028 /* finally, set the current encoding of the menu */
1029 menu->current_encoding = alphabet;
1030
1031 return true;
1032}
1033
void die(const char *error)
Cause an abnormal program termination.
Definition: misc.c:69
menu_action
Definition: scaffolding.h:77
RISC OS option setting (interface).
Cookie Manager (interface).
ssize_t search_web_iterate_providers(ssize_t iter, const char **name)
Iterate the search providers, returning their names.
Definition: searchweb.c:512
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_BAD_ENCODING
The character set is unknown.
Definition: errors.h:45
@ NSERROR_OK
No error.
Definition: errors.h:30
nserror utf8_to_local_encoding(const char *string, size_t len, char **result)
Definition: utf8.c:89
RISc OS global history interface.
Hotlist (interface).
#define NO_ACTION
Definition: idna.c:695
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
void ro_gui_menu_destroy(void)
Forcibly close any menu or transient dialogue box that is currently open.
Definition: menus.c:359
bool current_menu_open
Whether a menu is currently open.
Definition: menus.c:99
void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w)
Display a menu.
Definition: menus.c:282
void ro_gui_menu_init_structure(wimp_menu *menu, int entries)
Initialise the basic state of a menu structure so all entries are indirected text with no flags,...
Definition: menus.c:753
#define IS_MENU(menu)
Definition: menus.c:111
static wimp_menu * ro_gui_menu_init_search_provider(void)
Create menu structures.
Definition: menus.c:122
wimp_w current_menu_window
Window that owns the current menu.
Definition: menus.c:101
static void ro_gui_menu_define_menu_add(struct menu_definition *definition, const struct ns_menu *menu, int depth, wimp_menu_entry *parent_entry, int first, int last, const char *prefix, int prefix_length)
Create a wimp menu tree from ns_menu data.
Definition: menus.c:626
void ro_gui_menu_set_entry_ticked(wimp_menu *menu, menu_action action, bool ticked)
Sets an action within a menu as having a specific ticked status.
Definition: menus.c:902
static int ro_gui_menu_get_checksum(void)
Calculates a simple checksum for the current menu state.
Definition: menus.c:919
void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i)
Display a pop-up menu next to the specified icon.
Definition: menus.c:322
wimp_menu * image_quality_menu
The available menus.
Definition: menus.c:105
static bool ro_gui_menu_translate(struct menu_definition *menu)
Translate a menu's textual content into the system local encoding.
Definition: menus.c:965
void ro_gui_menu_init(void)
Definition: menus.c:185
const char * ro_gui_menu_find_menu_entry_key(wimp_menu *menu, const char *translated)
Finds the key associated with a menu entry translation.
Definition: menus.c:806
void ro_gui_menu_message_deleted(wimp_message_menus_deleted *deleted)
Handle Message_MenusDeleted, removing our current record of an open menu if it matches the deleted me...
Definition: menus.c:513
wimp_menu * languages_menu
Definition: menus.c:105
static struct menu_definition * ro_gui_menu_definitions
The currently defined menus to perform actions for.
Definition: menus.c:95
static struct menu_definition_entry * ro_gui_menu_find_entry(wimp_menu *menu, menu_action action)
Finds the menu_definition_entry corresponding to an action for a wimp_menu.
Definition: menus.c:829
static wimp_i current_menu_icon
Icon that owns the current menu (only valid for popup menus)
Definition: menus.c:103
void ro_gui_menu_refresh(wimp_menu *menu)
Update the current menu by sending it a Menu Prepare event through wimp_event and then reopening it i...
Definition: menus.c:546
void ro_gui_menu_warning(wimp_message_menu_warning *warning)
Handle Message_MenuWarning.
Definition: menus.c:452
void ro_gui_menu_set_entry_shaded(wimp_menu *menu, menu_action action, bool shaded)
Sets an action within a menu as having a specific ticked status.
Definition: menus.c:875
wimp_menu * ro_gui_menu_define_menu(const struct ns_menu *menu)
Creates a wimp_menu and adds it to the list to handle actions for.
Definition: menus.c:581
static void ro_gui_menu_closed(void)
Clean up after a menu has been closed, or forcibly close an open menu.
Definition: menus.c:524
wimp_menu * current_menu
The current menu being worked with (may not be open)
Definition: menus.c:97
wimp_menu * search_provider_menu
Definition: menus.c:105
static struct menu_definition * ro_gui_menu_find_menu(wimp_menu *menu)
Finds the menu_definition corresponding to a wimp_menu.
Definition: menus.c:784
#define DEFAULT_FLAGS
Definition: menus.c:90
void ro_gui_menu_selection(wimp_selection *selection)
Handle menu selection.
Definition: menus.c:397
wimp_menu * proxy_type_menu
Definition: menus.c:105
void ro_gui_menu_window_changed(wimp_w from, wimp_w to)
Allow the current menu window to change, if the window is deleted and recreated while a menu is activ...
Definition: menus.c:385
static menu_action ro_gui_menu_find_action(wimp_menu *menu, wimp_menu_entry *menu_entry)
Finds the action corresponding to a wimp_menu_entry for a wimp_menu.
Definition: menus.c:852
nserror messages_add_key_value(const char *key, const char *value)
Add a single message.
Definition: messages.c:205
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:256
Localised message support (interface).
Interface to riscos cookie viewing using riscos core window.
nserror ro_warn_user(const char *warning, const char *detail)
Display a warning for a serious problem (eg memory exhaustion).
Definition: gui.c:2082
Interactive help (interface).
File/object/selection saving (Interface).
Window toolbars (interface).
core web search facilities interface.
Interface to utility string handling.
Definition: menus.c:60
struct menu_definition_entry * next
next menu entry
Definition: menus.c:64
const char * entry_key
Messages key for entry text.
Definition: menus.c:63
wimp_menu_entry * menu_entry
corresponding menu entry
Definition: menus.c:62
menu_action action
menu action
Definition: menus.c:61
int current_encoding
Identifier for current text encoding of menu text (as per OS_Byte,71,127)
Definition: menus.c:70
wimp_menu * menu
corresponding menu
Definition: menus.c:68
struct menu_definition * next
next menu
Definition: menus.c:72
struct menu_definition_entry * entries
menu entries
Definition: menus.c:71
const char * title_key
Messages key for title text.
Definition: menus.c:69
menu_action action
associated action
Definition: menus.h:155
wimp_w * sub_window
sub-window if any
Definition: menus.h:156
const char * text
menu text (from messages)
Definition: menus.h:154
Definition: menus.h:159
const char * title
Definition: menus.h:160
struct ns_menu_entry entries[]
Definition: menus.h:161
Tinct SWI numbers and flags for version 0.11.
UCS conversion tables (interface) This is only used if nothing claims Service_International,...
URL Suggestion Menu (interface).
bool ro_gui_url_suggest_init(void)
Option reading and saving interface.
char from[32]
Encoding name to convert from.
Definition: utf8.c:143
char to[32]
Encoding name to convert to.
Definition: utf8.c:144
UTF-8 manipulation functions (interface).
void ro_gui_wimp_update_window_furniture(wimp_w w, wimp_window_flags bic_mask, wimp_window_flags xor_mask)
Sets whether a piece of window furniture is present for a window.
Definition: wimp.c:1016
General RISC OS WIMP/OS library functions (interface).
bool ro_gui_wimp_event_prepare_menu(wimp_w w, wimp_i i, wimp_menu *menu)
Trigger a window's Prepare Menu event.
Definition: wimp_event.c:1239
void ro_gui_wimp_event_register_submenu(wimp_w w)
Register a submenu as being opened.
Definition: wimp_event.c:1844
void ro_gui_wimp_event_menus_closed(wimp_w w, wimp_i i, wimp_menu *menu)
Handle menus being closed.
Definition: wimp_event.c:1807
bool ro_gui_wimp_event_submenu_warning(wimp_w w, wimp_i i, wimp_menu *menu, wimp_selection *selection, menu_action action)
Definition: wimp_event.c:1754
bool ro_gui_wimp_event_menu_selection(wimp_w w, wimp_i i, wimp_menu *menu, wimp_selection *selection, menu_action action)
Handles a menu selection event.
Definition: wimp_event.c:520
Automated RISC OS WIMP event handling (interface).
static nserror text(const struct redraw_context *ctx, const struct plot_font_style *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plot.c:978