NetSurf
help.c
Go to the documentation of this file.
1/*
2 * Copyright 2004, 2005 Richard Wilson <info@tinct.net>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/** \file
20 * Interactive help (implementation).
21 */
22
23#include <oslib/wimp.h>
24#include <oslib/help.h>
25#include <oslib/taskmanager.h>
26
27#include "utils/nsoption.h"
28#include "utils/log.h"
29#include "utils/messages.h"
30#include "utils/utf8.h"
31#include "netsurf/mouse.h"
32#include "netsurf/window.h"
33
34#include "riscos/help.h"
35#include "riscos/wimp_event.h"
36#include "riscos/hotlist.h"
38#include "riscos/cookies.h"
39#include "riscos/wimp.h"
40#include "riscos/iconbar.h"
41#include "riscos/window.h"
42#include "riscos/ucstables.h"
43#include "riscos/gui.h"
44
45/* Recognised help keys
46 ====================
47 Help keys should be registered using the wimp_event system to be
48 recognised. The only special case help values are:
49
50 HelpIconbar Iconbar (no icon suffix is used)
51 HelpBrowser Browser window [*]
52 HelpHotlist Hotlist window [*]
53 HelpGHistory Global history window [*]
54 HelpCookies Cookies window [*]
55
56 HelpIconMenu Iconbar menu
57 HelpBrowserMenu Browser window menu
58 HelpHotlistMenu Hotlist window menu
59 HelpGHistoryMenu Global history window menu
60 HelpCookiesMenu Cookie window menu
61
62 The prefixes are followed by either the icon number (eg 'HelpToolbar7'),
63 or a series of numbers representing the menu structure (eg
64 'HelpBrowserMenu3-1-2').
65 If '<key><identifier>' is not available, then simply '<key>' is then
66 used. For example if 'HelpToolbar7' is not available then 'HelpToolbar'
67 is then tried.
68 If an item is greyed out then a suffix of 'g' is added (eg
69 'HelpToolbar7g'). For this to work, windows must have bit 4 of the
70 window flag byte set and the user must be running RISC OS 5.03 or
71 greater.
72 For items marked with an asterisk [*] a call must be made to determine
73 the required help text as the window does not contain any icons. An
74 example of this is the hotlist window where ro_gui_hotlist_help() is
75 called.
76*/
77
78
79static void ro_gui_interactive_help_broadcast(wimp_message *message,
80 char *token);
81static os_t help_time = 0;
82
83
84/**
85 * Attempts to process an interactive help message request
86 *
87 * \param message the request message
88 */
89void ro_gui_interactive_help_request(wimp_message *message)
90{
91 char message_token[32];
92 char menu_buffer[4];
93 wimp_selection menu_tree;
94 help_full_message_request *message_data;
95 wimp_w window;
96 wimp_i icon;
97 unsigned int index;
98 bool greyed = false;
99 wimp_menu *test_menu;
100 os_error *error;
101 const char *auto_text;
102 int i;
103
104 /* check we aren't turned off */
105 if (!nsoption_bool(interactive_help))
106 return;
107
108 /* only accept help requests */
109 if ((!message) || (message->action != message_HELP_REQUEST))
110 return;
111
112 /* remember the time of the request so we can track them */
113 xos_read_monotonic_time(&help_time);
114
115 /* set up our state */
116 message_token[0] = 0x00;
117 message_data = (help_full_message_request *)message;
118 window = message_data->w;
119 icon = message_data->i;
120
121 /* do the basic window checks */
122 auto_text = ro_gui_wimp_event_get_help_prefix(window);
123 if (auto_text != NULL) {
124 const char *auto_suffix = ro_gui_wimp_event_get_help_suffix(
125 window, icon, &message_data->pos,
126 message_data->buttons);
127
128 if (auto_suffix == NULL)
129 sprintf(message_token, "%s%i", auto_text, (int)icon);
130 else
131 sprintf(message_token, "%s%s", auto_text, auto_suffix);
132 } else if (window == wimp_ICON_BAR)
133 sprintf(message_token, "HelpIconbar");
134 else if (ro_gui_hotlist_check_window(message->data.data_xfer.w)) {
135 i = -1;
136 sprintf(message_token,
137 (i >= 0) ? "HelpTree%i" :"HelpHotlist%i", i);
139 message->data.data_xfer.w)) {
140 i = -1;
141 sprintf(message_token,
142 (i >= 0) ? "HelpTree%i" :"HelpGHistory%i", i);
143 } else if (ro_gui_cookies_check_window(message->data.data_xfer.w)) {
144 i = -1;
145 sprintf(message_token,
146 (i >= 0) ? "HelpTree%i" :"HelpCookies%i", i);
147 } else if (ro_gui_window_lookup(window) != NULL)
148 sprintf(message_token, "HelpBrowser%i", (int)icon);
149
150 /* if we've managed to find something so far then we broadcast it */
151 if (message_token[0]) {
152 if ((icon >= 0) &&
153 (ro_gui_get_icon_shaded_state(window, icon)))
154 strcat(message_token, "g");
156 (char *)message_token);
157 return;
158 }
159
160 /* if we are not on an icon, we can't be in a menu (which stops
161 * separators giving help for their parent) so we abort */
162 if (icon == wimp_ICON_WINDOW)
163 return;
164
165 /* get the current menu tree */
166 error = xwimp_get_menu_state(wimp_GIVEN_WINDOW_AND_ICON,
167 &menu_tree, window, icon);
168 if (error) {
169 NSLOG(netsurf, INFO, "xwimp_get_menu_state: 0x%x: %s",
170 error->errnum, error->errmess);
171 ro_warn_user("WimpError", error->errmess);
172 return;
173 }
174 if (menu_tree.items[0] == -1)
175 return;
176
177 /* get the menu prefix */
179 sprintf(message_token, "HelpIconMenu");
181 sprintf(message_token, "HelpBrowserMenu");
183 sprintf(message_token, "HelpHotlistMenu");
185 sprintf(message_token, "HelpGHistoryMenu");
187 sprintf(message_token, "HelpCookiesMenu");
188 else
189 return;
190
191 /* decode the menu */
192 index = 0;
193 test_menu = current_menu;
194 while (menu_tree.items[index] != -1) {
195 greyed |= test_menu->entries[menu_tree.items[index]].icon_flags
196 & wimp_ICON_SHADED;
197 test_menu = test_menu->entries[menu_tree.items[index]].sub_menu;
198 if (index == 0)
199 sprintf(menu_buffer, "%i", menu_tree.items[index]);
200 else
201 sprintf(menu_buffer, "-%i", menu_tree.items[index]);
202 strcat(message_token, menu_buffer);
203 index++;
204 }
205 if (greyed)
206 strcat(message_token, "g");
207 ro_gui_interactive_help_broadcast(message, (char *)message_token);
208}
209
210
211/**
212 * Broadcasts a help reply
213 *
214 * \param message the original request message
215 * \param token the token to look up
216 */
217static void ro_gui_interactive_help_broadcast(wimp_message *message,
218 char *token)
219{
220 const char *translated_token;
221 help_full_message_reply *reply;
222 char *local_token;
223 os_error *error;
224
225 /* start off with an empty reply */
226 reply = (help_full_message_reply *)message;
227 reply->reply[0] = '\0';
228
229 /* check if the message exists */
230 translated_token = messages_get(token);
231 if (translated_token == token) {
232 /* no default help for 'g' suffix */
233 if (token[strlen(token) - 1] != 'g') {
234 /* find the base key from the token */
235 char *base_token = token;
236 while (base_token[0] != 0x00) {
237 if ((base_token[0] == '-') ||
238 ((base_token[0] >= '0') &&
239 (base_token[0] <= '9')))
240 base_token[0] = 0x00;
241 else
242 ++base_token;
243 }
244 translated_token = messages_get(token);
245 }
246 }
247
248 /* copy our message string */
249 if (translated_token != token) {
250 /* convert to local encoding */
251 nserror err = utf8_to_local_encoding(translated_token, 0,
252 &local_token);
253 if (err != NSERROR_OK) {
254 /* badenc should never happen */
255 assert(err != NSERROR_BAD_ENCODING);
256 /* simply use UTF-8 string */
257 strncpy(reply->reply, translated_token, 235);
258 }
259 else {
260 strncpy(reply->reply, local_token, 235);
261 free(local_token);
262 }
263 reply->reply[235] = '\0';
264 }
265
266 /* broadcast the help reply */
267 reply->size = 256;
268 reply->action = message_HELP_REPLY;
269 reply->your_ref = reply->my_ref;
270 error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message *)reply,
271 reply->sender);
272 if (error) {
273 NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
274 error->errnum, error->errmess);
275 ro_warn_user("WimpError", error->errmess);
276 }
277}
278
279
280/**
281 * Checks if interactive help is running
282 *
283 * \return non-zero if interactive help is available, or 0 if not available
284 */
286{
287 taskmanager_task task;
288 int context = 0;
289 os_t time;
290
291 /* generic test: any help request within the last 100cs */
292 xos_read_monotonic_time(&time);
293 if ((help_time + 100) > time)
294 return true;
295
296 /* special cases: check known application names */
297 do {
298 os_error *error;
299 error = xtaskmanager_enumerate_tasks(context, &task,
300 sizeof(taskmanager_task), &context, 0);
301 if (error) {
302 NSLOG(netsurf, INFO,
303 "xtaskmanager_enumerate_tasks: 0x%x: %s",
304 error->errnum,
305 error->errmess);
306 ro_warn_user("MiscError", error->errmess);
307 }
308
309 /* we can't just use strcmp due to string termination issues */
310 if (!strncmp(task.name, "Help", 4) &&
311 (task.name[4] < 32))
312 return true;
313 else if (!strncmp(task.name, "Bubble Help", 11) &&
314 (task.name[11] < 32))
315 return true;
316 else if (!strncmp(task.name, "Floating Help", 13) &&
317 (task.name[13] < 32))
318 return true;
319 } while (context >= 0);
320 return false;
321}
322
323
324/**
325 * Launches interactive help.
326 */
328{
329 char *help_start;
330 wimp_t task = 0;
331 os_error *error;
332
333 /* don't launch a second copy of anything */
335 return;
336
337 /* launch <Help$Start> */
338 help_start = getenv("Help$Start");
339 if ((help_start) && (help_start[0])) {
340 error = xwimp_start_task("<Help$Start>", &task);
341 if (error) {
342 NSLOG(netsurf, INFO, "xwimp_start_tast: 0x%x: %s",
343 error->errnum, error->errmess);
344 ro_warn_user("WimpError", error->errmess);
345 return;
346 }
347 }
348
349 /* first attempt failed, launch !Help */
350 if (!task) {
351 error = xwimp_start_task("Resources:$.Apps.!Help", &task);
352 if (error) {
353 NSLOG(netsurf, INFO, "xwimp_start_tast: 0x%x: %s",
354 error->errnum, error->errmess);
355 ro_warn_user("WimpError", error->errmess);
356 return;
357 }
358 }
359
360 /* pretend we got a help request straight away */
361 if (task) {
362 error = xos_read_monotonic_time(&help_time);
363 if (error) {
364 NSLOG(netsurf, INFO,
365 "xwimp_read_monotonic_time: 0x%x: %s",
366 error->errnum,
367 error->errmess);
368 ro_warn_user("WimpError", error->errmess);
369 }
370 }
371}
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
bool ro_gui_global_history_check_menu(wimp_menu *menu)
check if menu handle is for the global history menu
bool ro_gui_global_history_check_window(wimp_w wh)
check if window handle is for the global history window
RISc OS global history interface.
bool ro_gui_hotlist_check_window(wimp_w wh)
Definition: hotlist.c:608
bool ro_gui_hotlist_check_menu(wimp_menu *menu)
Definition: hotlist.c:619
Hotlist (interface).
Browser window handling (interface).
bool ro_gui_iconbar_check_menu(wimp_menu *menu)
Check if a particular menu handle is the iconbar menu.
Definition: iconbar.c:261
Iconbar icon and menus (interface).
Core mouse and pointer states.
Interface to platform-specific graphical user interface window operations.
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
wimp_menu * current_menu
The current menu being worked with (may not be open)
Definition: menus.c:96
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).
bool ro_gui_cookies_check_window(wimp_w wh)
check if window handle is for the cookies window
Definition: cookies.c:500
bool ro_gui_cookies_check_menu(wimp_menu *menu)
check if menu handle is for the cookies menu
Definition: cookies.c:511
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:2217
bool ro_gui_interactive_help_available(void)
Checks if interactive help is running.
Definition: help.c:285
void ro_gui_interactive_help_start(void)
Launches interactive help.
Definition: help.c:327
void ro_gui_interactive_help_request(wimp_message *message)
Attempts to process an interactive help message request.
Definition: help.c:89
static void ro_gui_interactive_help_broadcast(wimp_message *message, char *token)
Broadcasts a help reply.
Definition: help.c:217
static os_t help_time
Definition: help.c:81
Interactive help (interface).
bool ro_gui_window_check_menu(wimp_menu *menu)
Check if a particular menu handle is a browser window menu.
Definition: window.c:4683
struct gui_window * ro_gui_window_lookup(wimp_w window)
Convert a RISC OS window handle to a gui_window.
Definition: window.c:4823
UCS conversion tables (interface) This is only used if nothing claims Service_International,...
Option reading and saving interface.
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:270
UTF-8 manipulation functions (interface).
bool ro_gui_get_icon_shaded_state(wimp_w w, wimp_i i)
Gets the shaded state of an icon.
Definition: wimp.c:535
General RISC OS WIMP/OS library functions (interface).
const char * ro_gui_wimp_event_get_help_prefix(wimp_w w)
Get the associated help prefix.
Definition: wimp_event.c:408
const char * ro_gui_wimp_event_get_help_suffix(wimp_w w, wimp_i i, os_coord *pos, wimp_mouse_state buttons)
Get the associated help suffix.
Definition: wimp_event.c:448
Automated RISC OS WIMP event handling (interface).