On 5 Mar, "Glen Walker" wrote in message <trinity-f7329e17-7ac3-43a7-9606-3b93c8395d59-1425555487183@3capp-mailcom-lxa11>: > Steve suggested I take a look at Bug 2171 > (http://bugs.netsurf-browser.org/mantis/view.php?id=2171) as a way of > getting to grips with the source code. > > I've been looking and scratching my head for a day or so.
When I suggested looking at ticket #2171, I also said that I'd put together my thoughts on how to go about fixing it -- but that it would have to wait for a day or two due to lack of time. This thread seems to have pre-empted that (and I've already explained those thoughts in another post), so I won't bother now. :-) However, I also thought that iconbar.c/h was a useful bit of code to look at in terms of the more general structure of the RISC OS front-end. Since I'd already written the best part of some notes on that, I've completed them and here they are for what use they may be. If people think it's a good idea, I'll try and transfer these to the Wiki along with the file list that I posted the other day. As ever, please ask questions... :-) The Iconbar ----------- NetSurf's iconbar icon and menu are quite good as a code example, as they're relatively recent in their current implementation and so show off the event-driven structure that's the preferred way to add new features (or upgrade old ones). All of the code lives in the iconbar.c/h files, inside workspace/netsurf/riscos. A quick check of iconbar.h reveals that it only presents two functions to the outside world: ro_gui_iconbar_initialise() and ro_gui_iconbar_check_menu(). It also shows that someone failed to comment the file properly (although the two functions are documented in iconbar.c). Most code modules in NetSurf have an initialise function, which in the front-end will be called by gui_init() to give them chance to set themselves up; iconbar.c is no exception. If we have a look at the definiton of ro_gui_iconbar_initialise() in iconbar.c, we'll find something that's very similar to what's in many of the RISC OS front-end's newer modules. The iconbar icon's a simple example, but the steps are generally the same. The first thing the code does is build the iconbar menu; this is the bit we're interested in for the fix: /* Build the iconbar menu */ static const struct ns_menu iconbar_definition = { "NetSurf", { { "Info", NO_ACTION, &dialog_info }, { "AppHelp", HELP_OPEN_CONTENTS, 0 }, { "Open", BROWSER_NAVIGATE_URL, 0 }, { "Open.OpenURL", BROWSER_NAVIGATE_URL, &dialog_openurl }, { "Open.HotlistShow", HOTLIST_SHOW, 0 }, { "Open.HistGlobal", HISTORY_SHOW_GLOBAL, 0 }, { "Open.ShowCookies", COOKIES_SHOW, 0 }, { "Choices", CHOICES_SHOW, 0 }, { "Quit", APPLICATION_QUIT, 0 }, {NULL, 0, 0} } }; ro_gui_iconbar_menu = ro_gui_menu_define_menu(&iconbar_definition); The definition is a two-stage process. The first is to define a struct ns_menu which contains the NetSurf definition of the menu. The second is to pass this definition to ro_gui_menu_define_menu(), which turns it into an OSLIb wimp_menu; in other words, a RISC OS menu definition that can be passed to the Wimp_CreateMenu SWI to display the menu. The RISC OS front-end uses OSLib for all its interaction with the OS. ro_gui_menu_define_menu() also adds the menu to menus.c's own list of menus, to enable selection decoding. The top-level structure of NetSurf's menu definition contains a token for the menu title and a list of entries. The entries each consist of three parts: - A .-separated list of tokens for the entries. Each . takes us down a submenu level, so the example above would create a top-level menu containing tokens "Info", "AppHelp", "Open", "Choices" and "Quit". "Open" would lead to a submenu with the title from token "Open", and entries "OpenURL", "HotlistShow", "HistGlobal" and "ShowCookies". A menu separator can be inserted by prefixing the string with _ (eg. "_Open.HistGlobal" to put a separator in the sumenu. - An action token. This is from the typedef enum menu_action defined in menus.h, and is used to refer to that menu entry throughout the front-end. Menu_Select events (see later) will return this code to report user choices. - A pointer to a dialogue box, or 0 for none. "Info" leads to dialog_info, which is NetSurf's standard RISC OS Program Information window. If a menu entry leads to a submenu or dialogue box, it will automatically have submenu warnings turned on (so it will generate Menu_warning events: see later). Next the code creates an iconbar icon: /* Create an iconbar icon. */ wimp_icon_create icon = { wimp_ICON_BAR_RIGHT, { { 0, 0, 68, 68 }, wimp_ICON_SPRITE | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED | (wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT), { "!netsurf" } } }; error = xwimp_create_icon(&icon, 0); if (error) { LOG(("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess)); die(error->errmess); } Here we create an OSLib wimp_icon_create structure, fill it with the necessary data, then pass it to Wimp_CreateIcon to make the bar icon. Note that the X-form of the SWI is used, and any errors are trapped and logged; this is how the front-end should call any SWI that could fail (and the code here is pretty standard throughout the front-end -- even if the use of die() is a bit extreme, as at this stage there's not much point exiting more gracefully since NetSurf's not even on the iconbar yet). The final thing that ro_gui_iconbar_initialise() does is set up some event handlers to process events (in this case mouse clicks and menu operations) relating to the iconbar icon and menu: /* Register handlers to look after clicks and menu actions. */ ro_gui_wimp_event_register_mouse_click(wimp_ICON_BAR, ro_gui_iconbar_click); ro_gui_wimp_event_register_menu(wimp_ICON_BAR, ro_gui_iconbar_menu, true, true); ro_gui_wimp_event_register_menu_selection(wimp_ICON_BAR, ro_gui_iconbar_menu_select); ro_gui_wimp_event_register_menu_warning(wimp_ICON_BAR, ro_gui_iconbar_menu_warning); These all use the dispatcher in wimp_event.c -- and again, it's standard stuff throughout the front-end. All of the handlers are defined as static functions within iconbar.c, meaning that none of the other bits of the front-end need to know about them. The first line uses ro_gui_wimp_event_register_mouse_click() to register ro_gui_iconbar_click(). This means that whenever there's a Mouse_Click event returned by Wimp_Poll that relates to NetSurf's iconbar icon, ro_gui_iconbar_click() will be called and passed the Wimp_Poll event block. The handler itself just contains a switch() statement that processes Select and Adjust clicks on the icon. RISC OS Menu Handling --------------------- The next three lines might be a bit less obvious, as they relate to how wimp_event.c handles and dispatches menu activity. Menu support in RISC OS is a bit convoluted, and is spread over a range of events and user messages. To simplify things, wimp_event.c deals with a lot of the Style Guide requirements of menus; it also creates some pseudo-events that it can pass on to clients. The call to ro_gui_wimp_event_register_menu() tells the event handler that we would like to register the menu created earlier as the menu for the wimp_ICON_BAR window. wimp_event.c allows a menu to be attached to any NetSurf window: if one is attached, then Menu clicks over that window don't get passed to the client's Mouse_Click event handler (so ro_gui_iconbar_click() won't get told about Menu clicks on the iconbar). What happens instead is that the event handler prepares, opens and handles selections from the menu on behalf of the client. Since RISC OS just views the iconbar as a funny window with the handle -2 (wimp_ICON_BAR in OSLib constant terms), we can quite happily register a menu with the iconbar icon by passing wimp_ICON_BAR as the window handle; wimp_event.c recognises the special window handle and gives us an iconbar menu instead of the more conventional one that it would otherwise provide. The final two lines register two more event handlers with wimp_event.c: ro_gui_iconbar_menu_select() and ro_gui_iconbar_menu_warning(). These are both pseudo-events that are made up to simplify the handling of menus in the RISC OS front-end. In fact, there are four pseudo-events made up by wimp_event.c to support menus: Menu_Prepare, Menu_Warning, Menu_Select and Menu_Close. - Menu_Prepare is sent out before a menu opens following a Menu click (or a click on a pop-up menu icon), or before it re-opens following an Adjust-click on an item in it. It could be used to build a menu on the fly, or to update ticks and shading. - Menu_Warning is sent out whenever a Message_MenuWarning is received from the Wimp for the menu. In NetSurf, this is whenever the user passes the mouse over a right-pointing arrow in a menu to display the submenu or dialogue box -- it's used to prepare the submenu or dialogue (tick menu items; set the dialogue content) before it appears on screen. - Menu_Select is sent out whenever a selection is made by the user. If the selection was made with Select, it will be followed by a Menu_Close event; if the selection was with Adjust, it will be followed by a Menu_Prepare event. - Menu_Close is sent out whenever a menu closes. This might be on a non-Adjust selection from the menu, or on receipt of Message_MenusClosed from the Wimp (when the user clicks away from the menu). Where applicable, these events report the menu_action codes from menus.h and included in the definition above. This makes it much easier to decode them than having to do the normal RISC OS thing of navigating down a wimp_selection list. Both menu event handlers simply use a long switch() statement to pick appropriate actions from the possible codes that can be returned. ro_gui_iconbar_check_menu() --------------------------- Interactive help (help.c/h) needs to know which menu's open at any given time to be able to return appropriate help details. This is actually surprisingly difficult to work out (in any RISC OS application), due to the "afterthought" nature of menus and their interactive help support. menus.c knows the handle of the menu that is open, but doesn't know who it belongs to. Ideally, each struct ns_menu would contain a menu name that could be used to index the help from; at present it doesn't, so help.c just calls ro_gui_iconbar_check_menu() and functions like it which are provided by all of the bits of the front-end that have their own menus defined. Once something admits to owning the menu, then the help can be sorted out. -- Steve Fryatt - Leeds, England http://www.stevefryatt.org.uk/