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
42#include "riscos/dialog.h"
43#include "riscos/configure.h"
44#include "riscos/cookies.h"
45#include "riscos/gui.h"
47#include "riscos/help.h"
48#include "riscos/hotlist.h"
49#include "riscos/menus.h"
50#include "utils/nsoption.h"
51#include "riscos/save.h"
52#include "riscos/tinct.h"
53#include "riscos/toolbar.h"
54#include "riscos/url_suggest.h"
55#include "riscos/wimp.h"
56#include "riscos/wimp_event.h"
57#include "riscos/ucstables.h"
58
60 menu_action action; /**< menu action */
61 wimp_menu_entry *menu_entry; /**< corresponding menu entry */
62 const char *entry_key; /**< Messages key for entry text */
63 struct menu_definition_entry *next; /**< next menu entry */
64};
65
67 wimp_menu *menu; /**< corresponding menu */
68 const char *title_key; /**< Messages key for title text */
69 int current_encoding; /**< Identifier for current text encoding of menu text (as per OS_Byte,71,127) */
70 struct menu_definition_entry *entries; /**< menu entries */
71 struct menu_definition *next; /**< next menu */
72};
73
74static void ro_gui_menu_closed(void);
75static void ro_gui_menu_define_menu_add(struct menu_definition *definition,
76 const struct ns_menu *menu, int depth,
77 wimp_menu_entry *parent_entry,
78 int first, int last, const char *prefix, int prefix_length);
79static struct menu_definition *ro_gui_menu_find_menu(wimp_menu *menu);
80static struct menu_definition_entry *ro_gui_menu_find_entry(wimp_menu *menu,
82static menu_action ro_gui_menu_find_action(wimp_menu *menu,
83 wimp_menu_entry *menu_entry);
84static int ro_gui_menu_get_checksum(void);
85static bool ro_gui_menu_translate(struct menu_definition *menu);
86
87
88/* default menu item flags */
89#define DEFAULT_FLAGS (wimp_ICON_TEXT | wimp_ICON_FILLED | \
90 (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | \
91 (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT))
92
93/** The currently defined menus to perform actions for */
95/** The current menu being worked with (may not be open) */
96wimp_menu *current_menu;
97/** Whether a menu is currently open */
98bool current_menu_open = false;
99/** Window that owns the current menu */
101/** Icon that owns the current menu (only valid for popup menus) */
102static wimp_i current_menu_icon;
103/** The available menus */
105
106/* the values given in PRM 3-157 for how to check menus/windows are
107 * incorrect so we use a hack of checking if the sub-menu has bit 0
108 * set which is undocumented but true of window handles on
109 * all target OS versions */
110#define IS_MENU(menu) !((int)(menu) & 1)
111
112/**
113 * Create menu structures.
114 */
115
117{
118 /* image quality menu */
119 static const struct ns_menu images_definition = {
120 "Display", {
121 { "ImgStyle0", NO_ACTION, 0 },
122 { "ImgStyle1", NO_ACTION, 0 },
123 { "ImgStyle2", NO_ACTION, 0 },
124 { "ImgStyle3", NO_ACTION, 0 },
125 {NULL, 0, 0}
126 }
127 };
128 image_quality_menu = ro_gui_menu_define_menu(&images_definition);
129
130 /* proxy menu */
131 static const struct ns_menu proxy_type_definition = {
132 "ProxyType", {
133 { "ProxyNone", NO_ACTION, 0 },
134 { "ProxyNoAuth", NO_ACTION, 0 },
135 { "ProxyBasic", NO_ACTION, 0 },
136 { "ProxyNTLM", NO_ACTION, 0 },
137 {NULL, 0, 0}
138 }
139 };
140 proxy_type_menu = ro_gui_menu_define_menu(&proxy_type_definition);
141
142 /* special case menus */
144
145 /* Note: This table *must* be kept in sync with the LangNames file */
146 static const struct ns_menu lang_definition = {
147 "Languages", {
148 { "lang_af", NO_ACTION, 0 },
149 { "lang_bm", NO_ACTION, 0 },
150 { "lang_ca", NO_ACTION, 0 },
151 { "lang_cs", NO_ACTION, 0 },
152 { "lang_cy", NO_ACTION, 0 },
153 { "lang_da", NO_ACTION, 0 },
154 { "lang_de", NO_ACTION, 0 },
155 { "lang_en", NO_ACTION, 0 },
156 { "lang_es", NO_ACTION, 0 },
157 { "lang_et", NO_ACTION, 0 },
158 { "lang_eu", NO_ACTION, 0 },
159 { "lang_ff", NO_ACTION, 0 },
160 { "lang_fi", NO_ACTION, 0 },
161 { "lang_fr", NO_ACTION, 0 },
162 { "lang_ga", NO_ACTION, 0 },
163 { "lang_gl", NO_ACTION, 0 },
164 { "lang_ha", NO_ACTION, 0 },
165 { "lang_hr", NO_ACTION, 0 },
166 { "lang_hu", NO_ACTION, 0 },
167 { "lang_id", NO_ACTION, 0 },
168 { "lang_is", NO_ACTION, 0 },
169 { "lang_it", NO_ACTION, 0 },
170 { "lang_lt", NO_ACTION, 0 },
171 { "lang_lv", NO_ACTION, 0 },
172 { "lang_ms", NO_ACTION, 0 },
173 { "lang_mt", NO_ACTION, 0 },
174 { "lang_nl", NO_ACTION, 0 },
175 { "lang_no", NO_ACTION, 0 },
176 { "lang_pl", NO_ACTION, 0 },
177 { "lang_pt", NO_ACTION, 0 },
178 { "lang_rn", NO_ACTION, 0 },
179 { "lang_ro", NO_ACTION, 0 },
180 { "lang_rw", NO_ACTION, 0 },
181 { "lang_sk", NO_ACTION, 0 },
182 { "lang_sl", NO_ACTION, 0 },
183 { "lang_so", NO_ACTION, 0 },
184 { "lang_sq", NO_ACTION, 0 },
185 { "lang_sr", NO_ACTION, 0 },
186 { "lang_sv", NO_ACTION, 0 },
187 { "lang_sw", NO_ACTION, 0 },
188 { "lang_tr", NO_ACTION, 0 },
189 { "lang_uz", NO_ACTION, 0 },
190 { "lang_vi", NO_ACTION, 0 },
191 { "lang_wo", NO_ACTION, 0 },
192 { "lang_xs", NO_ACTION, 0 },
193 { "lang_yo", NO_ACTION, 0 },
194 { "lang_zu", NO_ACTION, 0 },
195 { NULL, 0, 0 }
196 }
197 };
198 languages_menu = ro_gui_menu_define_menu(&lang_definition);
199}
200
201
202/**
203 * Display a menu.
204 *
205 * \param *menu Pointer to the menu to be displayed.
206 * \param x The x position.
207 * \param y The y position.
208 * \param w The window that the menu belongs to.
209 */
210
211void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w)
212{
213 os_error *error;
214 struct menu_definition *definition;
215
216 /* translate menu, if necessary (this returns quickly
217 * if there's nothing to be done) */
218 definition = ro_gui_menu_find_menu(menu);
219 if (definition) {
220 if (!ro_gui_menu_translate(definition)) {
221 ro_warn_user("NoMemory", 0);
222 return;
223 }
224 }
225
226 /* store the menu characteristics */
229 current_menu_icon = wimp_ICON_WINDOW;
230
231 /* create the menu */
232 current_menu_open = true;
233 error = xwimp_create_menu(menu, x - 64, y);
234 if (error) {
235 NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
236 error->errnum, error->errmess);
237 ro_warn_user("MenuError", error->errmess);
239 }
240}
241
242
243/**
244 * Display a pop-up menu next to the specified icon.
245 *
246 * \param menu menu to open
247 * \param w window handle
248 * \param i icon handle
249 */
250
251void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i)
252{
253 wimp_window_state state;
254 wimp_icon_state icon_state;
255 os_error *error;
256
257 state.w = w;
258 icon_state.w = w;
259 icon_state.i = i;
260 error = xwimp_get_window_state(&state);
261 if (error) {
262 NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
263 error->errnum, error->errmess);
264 ro_warn_user("MenuError", error->errmess);
265 return;
266 }
267
268 error = xwimp_get_icon_state(&icon_state);
269 if (error) {
270 NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
271 error->errnum, error->errmess);
272 ro_warn_user("MenuError", error->errmess);
273 return;
274 }
275
277 state.visible.x0 + icon_state.icon.extent.x1 + 64,
278 state.visible.y1 + icon_state.icon.extent.y1 -
279 state.yscroll, w);
281}
282
283
284/**
285 * Forcibly close any menu or transient dialogue box that is currently open.
286 */
287
289{
290 os_error *error;
291
292 if (current_menu == NULL)
293 return;
294
295 error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
296 if (error) {
297 NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
298 error->errnum, error->errmess);
299 ro_warn_user("MenuError", error->errmess);
300 }
301
303}
304
305
306/**
307 * Allow the current menu window to change, if the window is deleted and
308 * recreated while a menu is active on an Adjust-click.
309 *
310 * \param from The original window handle.
311 * \param to The new replacement window handle.
312 */
313
315{
316
319}
320
321
322/**
323 * Handle menu selection.
324 */
325
326void ro_gui_menu_selection(wimp_selection *selection)
327{
328 int i; //, j;
329 wimp_menu_entry *menu_entry;
330 menu_action action;
331 wimp_pointer pointer;
332 os_error *error;
333 int previous_menu_icon = current_menu_icon;
334
335 /* if we are using gui_multitask then menu selection events
336 * may be delivered after the menu has been closed. As such,
337 * we simply ignore these events. */
338 if (!current_menu)
339 return;
340
341 assert(current_menu_window);
342
343 /* get the menu entry and associated action and definition */
344 menu_entry = &current_menu->entries[selection->items[0]];
345 for (i = 1; selection->items[i] != -1; i++)
346 menu_entry = &menu_entry->sub_menu->
347 entries[selection->items[i]];
348 action = ro_gui_menu_find_action(current_menu, menu_entry);
349
350 /* Deal with the menu action. If this manages to re-prepare the
351 * menu for re-opening, we test for and act on Adjust clicks.
352 */
353
356 return;
357
358 /* re-open the menu for Adjust clicks */
359 error = xwimp_get_pointer_info(&pointer);
360 if (error) {
361 NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
362 error->errnum, error->errmess);
363 ro_warn_user("WimpError", error->errmess);
365 return;
366 }
367
368 if (pointer.buttons != wimp_CLICK_ADJUST) {
370 return;
371 }
372
374 current_menu_icon = previous_menu_icon;
375}
376
377
378/**
379 * Handle Message_MenuWarning.
380 */
381void ro_gui_menu_warning(wimp_message_menu_warning *warning)
382{
383 int i;
384 menu_action action;
385 wimp_menu_entry *menu_entry;
386 os_error *error;
387
388 assert(current_menu);
389 assert(current_menu_window);
390
391 /* get the sub-menu of the warning */
392 if (warning->selection.items[0] == -1)
393 return;
394 menu_entry = &current_menu->entries[warning->selection.items[0]];
395 for (i = 1; warning->selection.items[i] != -1; i++)
396 menu_entry = &menu_entry->sub_menu->
397 entries[warning->selection.items[i]];
398 action = ro_gui_menu_find_action(current_menu, menu_entry);
399
400 /* Process the warning via Wimp_Event, then register the resulting
401 * submenu with the module.
402 */
403
405 current_menu_icon, current_menu, &(warning->selection),
406 action);
407
408 if (IS_MENU(menu_entry->sub_menu)) {
410 } else {
412 menu_entry->sub_menu);
413
414 /* If this is a dialogue box, remove the close and back icons.
415 */
416
418 menu_entry->sub_menu,
419 wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_BACK_ICON,
420 0);
421 }
422
423 /* open the sub-menu */
424
425 error = xwimp_create_sub_menu(menu_entry->sub_menu,
426 warning->pos.x, warning->pos.y);
427 if (error) {
428 NSLOG(netsurf, INFO, "xwimp_create_sub_menu: 0x%x: %s",
429 error->errnum, error->errmess);
430 ro_warn_user("MenuError", error->errmess);
431 }
432}
433
434
435/**
436 * Handle Message_MenusDeleted, removing our current record of an open menu
437 * if it matches the deleted menu handle.
438 *
439 * \param *deleted The message block.
440 */
441
442void ro_gui_menu_message_deleted(wimp_message_menus_deleted *deleted)
443{
444 if (deleted != NULL && deleted->menu == current_menu)
446}
447
448
449/**
450 * Clean up after a menu has been closed, or forcibly close an open menu.
451 */
452
453static void ro_gui_menu_closed(void)
454{
455 if (current_menu != NULL)
458
459 current_menu = NULL;
460 current_menu_window = NULL;
462 current_menu_open = false;
463}
464
465
466/**
467 * Update the current menu by sending it a Menu Prepare event through wimp_event
468 * and then reopening it if the contents has changed.
469 *
470 * \param *menu The menu to refresh: if 0, the current menu will be
471 * refreshed regardless, otherwise it will be refreshed
472 * only if it matches the supplied handle.
473 */
474
475void ro_gui_menu_refresh(wimp_menu *menu)
476{
477 int checksum = 0;
478
480 return;
481
482 checksum = ro_gui_menu_get_checksum();
483
486 return;
487
488 /* \TODO -- Call the menu's event handler here. */
489
490 if (checksum != ro_gui_menu_get_checksum()) {
491 os_error *error;
492 error = xwimp_create_menu(current_menu, 0, 0);
493 if (error) {
494 NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
495 error->errnum, error->errmess);
496 ro_warn_user("MenuError", error->errmess);
497 }
498 }
499}
500
501
502
503
504/**
505 * Creates a wimp_menu and adds it to the list to handle actions for.
506 *
507 * \param menu The data to create the menu with
508 * \return The menu created, or NULL on failure
509 */
510wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu)
511{
512 struct menu_definition *definition;
513 int entry;
514
515 definition = calloc(sizeof(struct menu_definition), 1);
516 if (!definition) {
517 die("No memory to create menu definition.");
518 return NULL; /* For the benefit of scan-build */
519 }
520
521 /* link in the menu to our list */
522 definition->next = ro_gui_menu_definitions;
523 ro_gui_menu_definitions = definition;
524
525 /* count number of menu entries */
526 for (entry = 0; menu->entries[entry].text; entry++)
527 /* do nothing */;
528
529 /* create our definitions */
530 ro_gui_menu_define_menu_add(definition, menu, 0, NULL,
531 0, entry, NULL, 0);
532
533 /* and translate menu into current encoding */
534 if (!ro_gui_menu_translate(definition))
535 die("No memory to translate menu.");
536
537 return definition->menu;
538}
539
540/**
541 * Create a wimp menu tree from ns_menu data.
542 * This function does *not* deal with the menu textual content - it simply
543 * creates and populates the appropriate structures. Textual content is
544 * generated by ro_gui_menu_translate_menu()
545 *
546 * \param definition Top level menu definition
547 * \param menu Menu declaration data
548 * \param depth Depth of menu we're currently building
549 * \param parent_entry Entry in parent menu, or NULL if root menu
550 * \param first First index in declaration data that is used by this menu
551 * \param last Last index in declaration data that is used by this menu
552 * \param prefix Prefix pf menu declaration string already seen
553 * \param prefix_length Length of prefix
554 */
556 const struct ns_menu *menu, int depth,
557 wimp_menu_entry *parent_entry, int first, int last,
558 const char *prefix, int prefix_length)
559{
560 int entry;
561 int entries = 0;
562 int matches[last - first + 1];
563 const char *text, *menu_text;
564 wimp_menu *new_menu;
565 struct menu_definition_entry *definition_entry;
566
567 /* step 1: store the matches for depth and subset string */
568 for (entry = first; entry < last; entry++) {
569 const char *match;
570 int cur_depth = 0;
571 match = menu->entries[entry].text;
572
573 /* skip specials at start of string */
574 while (!isalnum(*match))
575 match++;
576
577 /* attempt prefix match */
578 if ((prefix) && (strncmp(match, prefix, prefix_length)))
579 continue;
580
581 /* Find depth of this entry */
582 while (*match)
583 if (*match++ == '.')
584 cur_depth++;
585
586 if (depth == cur_depth)
587 matches[entries++] = entry;
588 }
589 matches[entries] = last;
590
591 /* no entries, so exit */
592 if (entries == 0)
593 return;
594
595 /* step 2: build and link the menu. we must use realloc to stop
596 * our memory fragmenting so we can test for sub-menus easily */
597 new_menu = (wimp_menu *)malloc(wimp_SIZEOF_MENU(entries));
598 if (!new_menu)
599 die("No memory to create menu.");
600
601 if (parent_entry) {
602 /* Fix up sub menu pointer */
603 parent_entry->sub_menu = new_menu;
604 } else {
605 /* Root menu => fill in definition struct */
606 definition->title_key = menu->title;
607 definition->current_encoding = 0;
608 definition->menu = new_menu;
609 }
610
611 /* this is fixed up in ro_gui_menu_translate() */
612 new_menu->title_data.indirected_text.text = NULL;
613
614 /* fill in menu flags */
615 ro_gui_menu_init_structure(new_menu, entries);
616
617 /* and then create the entries */
618 for (entry = 0; entry < entries; entry++) {
619 /* add the entry */
620 int id = matches[entry];
621
622 text = menu->entries[id].text;
623
624 /* fill in menu flags from specials at start of string */
625 new_menu->entries[entry].menu_flags = 0;
626 while (!isalnum(*text)) {
627 if (*text == '_')
628 new_menu->entries[entry].menu_flags |=
629 wimp_MENU_SEPARATE;
630 text++;
631 }
632
633 /* get messages key for menu entry */
634 menu_text = strrchr(text, '.');
635 if (!menu_text)
636 /* no '.' => top-level entry */
637 menu_text = text;
638 else
639 menu_text++; /* and move past the '.' */
640
641 /* fill in submenu data */
642 if (menu->entries[id].sub_window)
643 new_menu->entries[entry].sub_menu =
644 (wimp_menu *) (*menu->entries[id].sub_window);
645
646 /* this is fixed up in ro_gui_menu_translate() */
647 new_menu->entries[entry].data.indirected_text.text = NULL;
648
649 /* create definition entry */
650 definition_entry =
651 malloc(sizeof(struct menu_definition_entry));
652 if (!definition_entry)
653 die("Unable to create menu definition entry");
654 definition_entry->action = menu->entries[id].action;
655 definition_entry->menu_entry = &new_menu->entries[entry];
656 definition_entry->entry_key = menu_text;
657 definition_entry->next = definition->entries;
658 definition->entries = definition_entry;
659
660 /* recurse */
661 if (new_menu->entries[entry].sub_menu == wimp_NO_SUB_MENU) {
662 ro_gui_menu_define_menu_add(definition, menu,
663 depth + 1, &new_menu->entries[entry],
664 matches[entry], matches[entry + 1],
665 text, strlen(text));
666 }
667
668 /* give menu warnings */
669 if (new_menu->entries[entry].sub_menu != wimp_NO_SUB_MENU)
670 new_menu->entries[entry].menu_flags |=
671 wimp_MENU_GIVE_WARNING;
672 }
673 new_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED;
674 new_menu->entries[entries - 1].menu_flags |= wimp_MENU_LAST;
675}
676
677
678/**
679 * Initialise the basic state of a menu structure so all entries are
680 * indirected text with no flags, no submenu.
681 */
682void ro_gui_menu_init_structure(wimp_menu *menu, int entries)
683{
684 int i;
685
686 menu->title_fg = wimp_COLOUR_BLACK;
687 menu->title_bg = wimp_COLOUR_LIGHT_GREY;
688 menu->work_fg = wimp_COLOUR_BLACK;
689 menu->work_bg = wimp_COLOUR_WHITE;
690 menu->width = 200;
691 menu->height = wimp_MENU_ITEM_HEIGHT;
692 menu->gap = wimp_MENU_ITEM_GAP;
693
694 for (i = 0; i < entries; i++) {
695 menu->entries[i].menu_flags = 0;
696 menu->entries[i].sub_menu = wimp_NO_SUB_MENU;
697 menu->entries[i].icon_flags =
698 DEFAULT_FLAGS | wimp_ICON_INDIRECTED;
699 menu->entries[i].data.indirected_text.validation =
700 (char *)-1;
701 }
702 menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED;
703 menu->entries[i - 1].menu_flags |= wimp_MENU_LAST;
704}
705
706
707/**
708 * Finds the menu_definition corresponding to a wimp_menu.
709 *
710 * \param menu the menu to find the definition for
711 * \return the associated definition, or NULL if one could not be found
712 */
714{
715 struct menu_definition *definition;
716
717 if (!menu)
718 return NULL;
719
720 for (definition = ro_gui_menu_definitions; definition;
721 definition = definition->next)
722 if (definition->menu == menu)
723 return definition;
724 return NULL;
725}
726
727
728/**
729 * Finds the key associated with a menu entry translation.
730 *
731 * \param menu the menu to search
732 * \param translated the translated text
733 * \return the original message key, or NULL if one could not be found
734 */
736 const char *translated)
737{
738 struct menu_definition_entry *entry;
739 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
740
741 if (!definition)
742 return NULL;
743
744 for (entry = definition->entries; entry; entry = entry->next)
745 if (!strcmp(entry->menu_entry->data.indirected_text.text, translated))
746 return entry->entry_key;
747 return NULL;
748}
749
750
751/**
752 * Finds the menu_definition_entry corresponding to an action for a wimp_menu.
753 *
754 * \param menu the menu to search for an action within
755 * \param action the action to find
756 * \return the associated menu entry, or NULL if one could not be found
757 */
760{
761 struct menu_definition_entry *entry;
762 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
763
764 if (!definition)
765 return NULL;
766
767 for (entry = definition->entries; entry; entry = entry->next)
768 if (entry->action == action)
769 return entry;
770 return NULL;
771}
772
773
774/**
775 * Finds the action corresponding to a wimp_menu_entry for a wimp_menu.
776 *
777 * \param menu the menu to search for an action within
778 * \param menu_entry the menu_entry to find
779 * \return the associated action, or 0 if one could not be found
780 */
781menu_action ro_gui_menu_find_action(wimp_menu *menu, wimp_menu_entry *menu_entry)
782{
783 struct menu_definition_entry *entry;
784 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
785
786 if (!definition)
787 return NO_ACTION;
788
789 for (entry = definition->entries; entry; entry = entry->next) {
790 if (entry->menu_entry == menu_entry)
791 return entry->action;
792 }
793 return NO_ACTION;
794}
795
796
797/**
798 * Sets an action within a menu as having a specific ticked status.
799 *
800 * \param menu the menu containing the action
801 * \param action the action to tick/untick
802 * \param shaded whether to set the item as shaded
803 */
805 bool shaded)
806{
807 struct menu_definition_entry *entry;
808 struct menu_definition *definition = ro_gui_menu_find_menu(menu);
809
810 if (!definition)
811 return;
812
813 /* we can't use find_entry as multiple actions may appear in one menu */
814 for (entry = definition->entries; entry; entry = entry->next)
815 if (entry->action == action) {
816 if (shaded)
817 entry->menu_entry->icon_flags |= wimp_ICON_SHADED;
818 else
819 entry->menu_entry->icon_flags &= ~wimp_ICON_SHADED;
820 }
821}
822
823
824/**
825 * Sets an action within a menu as having a specific ticked status.
826 *
827 * \param menu the menu containing the action
828 * \param action the action to tick/untick
829 * \param ticked whether to set the item as ticked
830 */
832 bool ticked)
833{
834 struct menu_definition_entry *entry =
836 if (entry) {
837 if (ticked)
838 entry->menu_entry->menu_flags |= wimp_MENU_TICKED;
839 else
840 entry->menu_entry->menu_flags &= ~wimp_MENU_TICKED;
841 }
842}
843
844
845/**
846 * Calculates a simple checksum for the current menu state
847 */
849{
850 wimp_selection menu_tree;
851 int i = 0, j, checksum = 0;
852 os_error *error;
853 wimp_menu *menu;
854
856 return 0;
857
858 error = xwimp_get_menu_state((wimp_menu_state_flags)0,
859 &menu_tree, 0, 0);
860 if (error) {
861 NSLOG(netsurf, INFO, "xwimp_get_menu_state: 0x%x: %s",
862 error->errnum, error->errmess);
863 ro_warn_user("MenuError", error->errmess);
864 return 0;
865 }
866
867 menu = current_menu;
868 do {
869 j = 0;
870 do {
871 if (menu->entries[j].icon_flags & wimp_ICON_SHADED)
872 checksum ^= (1 << (i + j * 2));
873 if (menu->entries[j].menu_flags & wimp_MENU_TICKED)
874 checksum ^= (2 << (i + j * 2));
875 } while (!(menu->entries[j++].menu_flags & wimp_MENU_LAST));
876
877 j = menu_tree.items[i++];
878 if (j != -1) {
879 menu = menu->entries[j].sub_menu;
880 if ((!menu) || (menu == wimp_NO_SUB_MENU) || (!IS_MENU(menu)))
881 break;
882 }
883 } while (j != -1);
884
885 return checksum;
886}
887
888/**
889 * Translate a menu's textual content into the system local encoding
890 *
891 * \param menu The menu to translate
892 * \return false if out of memory, true otherwise
893 */
895{
896 os_error *error;
897 int alphabet;
898 struct menu_definition_entry *entry;
899 char *translated;
900 nserror err;
901
902 /* read current alphabet */
903 error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet);
904 if (error) {
905 NSLOG(netsurf, INFO, "failed reading alphabet: 0x%x: %s",
906 error->errnum, error->errmess);
907 /* assume Latin1 */
908 alphabet = territory_ALPHABET_LATIN1;
909 }
910
911 if (menu->current_encoding == alphabet)
912 /* menu text is already in the correct encoding */
913 return true;
914
915 /* translate root menu title text */
916 free(menu->menu->title_data.indirected_text.text);
918 0, &translated);
919 if (err != NSERROR_OK) {
920 assert(err != NSERROR_BAD_ENCODING);
921 NSLOG(netsurf, INFO, "utf8_to_enc failed");
922 return false;
923 }
924
925 /* and fill in WIMP menu field */
926 menu->menu->title_data.indirected_text.text = translated;
927
928 /* now the menu entries */
929 for (entry = menu->entries; entry; entry = entry->next) {
930 wimp_menu *submenu = entry->menu_entry->sub_menu;
931
932 /* tranlate menu entry text */
933 free(entry->menu_entry->data.indirected_text.text);
935 0, &translated);
936 if (err != NSERROR_OK) {
937 assert(err != NSERROR_BAD_ENCODING);
938 NSLOG(netsurf, INFO, "utf8_to_enc failed");
939 return false;
940 }
941
942 /* fill in WIMP menu fields */
943 entry->menu_entry->data.indirected_text.text = translated;
944 entry->menu_entry->data.indirected_text.validation =
945 (char *) -1;
946 entry->menu_entry->data.indirected_text.size =
947 strlen(translated);
948
949 /* child menu title - this is the same as the text of
950 * the parent menu entry, so just copy the pointer */
951 if (submenu != wimp_NO_SUB_MENU && IS_MENU(submenu)) {
952 submenu->title_data.indirected_text.text =
953 translated;
954 }
955 }
956
957 /* finally, set the current encoding of the menu */
958 menu->current_encoding = alphabet;
959
960 return true;
961}
962
void die(const char *error)
Cause an abnormal program termination.
Definition: misc.c:69
menu_action
Definition: scaffolding.h:77
@ NO_ACTION
Definition: scaffolding.h:80
RISC OS option setting (interface).
Cookie Manager (interface).
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 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:288
bool current_menu_open
Whether a menu is currently open.
Definition: menus.c:98
void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w)
Display a menu.
Definition: menus.c:211
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:682
#define IS_MENU(menu)
Definition: menus.c:110
wimp_w current_menu_window
Window that owns the current menu.
Definition: menus.c:100
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:555
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:831
static int ro_gui_menu_get_checksum(void)
Calculates a simple checksum for the current menu state.
Definition: menus.c:848
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:251
wimp_menu * image_quality_menu
The available menus.
Definition: menus.c:104
static bool ro_gui_menu_translate(struct menu_definition *menu)
Translate a menu's textual content into the system local encoding.
Definition: menus.c:894
void ro_gui_menu_init(void)
Create menu structures.
Definition: menus.c:116
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:735
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:442
wimp_menu * languages_menu
Definition: menus.c:104
static struct menu_definition * ro_gui_menu_definitions
The currently defined menus to perform actions for.
Definition: menus.c:94
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:758
static wimp_i current_menu_icon
Icon that owns the current menu (only valid for popup menus)
Definition: menus.c:102
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:475
void ro_gui_menu_warning(wimp_message_menu_warning *warning)
Handle Message_MenuWarning.
Definition: menus.c:381
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:804
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:510
static void ro_gui_menu_closed(void)
Clean up after a menu has been closed, or forcibly close an open menu.
Definition: menus.c:453
wimp_menu * current_menu
The current menu being worked with (may not be open)
Definition: menus.c:96
static struct menu_definition * ro_gui_menu_find_menu(wimp_menu *menu)
Finds the menu_definition corresponding to a wimp_menu.
Definition: menus.c:713
#define DEFAULT_FLAGS
Definition: menus.c:89
void ro_gui_menu_selection(wimp_selection *selection)
Handle menu selection.
Definition: menus.c:326
wimp_menu * proxy_type_menu
Definition: menus.c:104
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:314
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:781
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
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:2076
Interactive help (interface).
File/object/selection saving (Interface).
Window toolbars (interface).
Interface to utility string handling.
Definition: menus.c:59
struct menu_definition_entry * next
next menu entry
Definition: menus.c:63
const char * entry_key
Messages key for entry text.
Definition: menus.c:62
wimp_menu_entry * menu_entry
corresponding menu entry
Definition: menus.c:61
menu_action action
menu action
Definition: menus.c:60
int current_encoding
Identifier for current text encoding of menu text (as per OS_Byte,71,127)
Definition: menus.c:69
wimp_menu * menu
corresponding menu
Definition: menus.c:67
struct menu_definition * next
next menu
Definition: menus.c:71
struct menu_definition_entry * entries
menu entries
Definition: menus.c:70
const char * title_key
Messages key for title text.
Definition: menus.c:68
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