netsurf/riscos/help.c

309 lines
8.9 KiB
C

/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2004, 2005 Richard Wilson <info@tinct.net>
*/
/** \file
* Interactive help (implementation).
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "oslib/help.h"
#include "oslib/os.h"
#include "oslib/taskmanager.h"
#include "oslib/wimp.h"
#include "netsurf/riscos/global_history.h"
#include "netsurf/riscos/gui.h"
#include "netsurf/riscos/help.h"
#include "netsurf/riscos/theme.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/messages.h"
#include "netsurf/utils/log.h"
/* Recognised help keys
====================
HelpIconbar Iconbar (no icon suffix is used)
HelpAppInfo Application info window
HelpBrowser Browser window [*]
HelpHistory History window [*]
HelpObjInfo Object info window
HelpPageInfo Page info window
HelpSaveAs Save as window
HelpScaleView Scale view window
HelpStatus Status window
HelpToolbar Toolbar window
HelpHotlist Hotlist window [*]
HelpHotToolbar Hotlist window toolbar
HelpHotEntry Hotlist entry window
HelpHotFolder Hotlist entry window
HelpGHistory Global history window [*]
HelpGHistoryToolbar Global history window toolbar
HelpIconMenu Iconbar menu
HelpBrowserMenu Browser window menu
HelpHotlistMenu Hotlist window menu
The prefixes are followed by either the icon number (eg 'HelpToolbar7'), or a series
of numbers representing the menu structure (eg 'HelpBrowserMenu3-1-2').
If '<key><identifier>' is not available, then simply '<key>' is then used. For example
if 'HelpToolbar7' is not available then 'HelpToolbar' is then tried.
If an item is greyed out then a suffix of 'g' is added (eg 'HelpToolbar7g'). For this to
work, windows must have bit 4 of the window flag byte set and the user must be running
RISC OS 5.03 or greater.
For items marked with an asterisk [*] a call must be made to determine the required
help text as the window does not contain any icons. An example of this is the hotlist
window where ro_gui_hotlist_help() is called.
*/
static void ro_gui_interactive_help_broadcast(wimp_message *message, char *token);
static os_t help_time = 0;
/**
* Attempts to process an interactive help message request
*
* \param message the request message
*/
void ro_gui_interactive_help_request(wimp_message *message) {
char message_token[32];
char menu_buffer[4];
wimp_selection menu_tree;
help_full_message_request *message_data;
wimp_w window;
wimp_i icon;
struct gui_window *g;
unsigned int index;
bool greyed = false;
wimp_menu *test_menu;
/* Ensure we have a help request
*/
if ((!message) || (message->action != message_HELP_REQUEST)) return;
/* Remember the time of the request
*/
xos_read_monotonic_time(&help_time);
/* Initialise the basic token to a null byte
*/
message_token[0] = 0x00;
/* Get the message data
*/
message_data = (help_full_message_request *)message;
window = message_data->w;
icon = message_data->i;
/* Do the basic window checks
*/
if (window == (wimp_w)-2) {
sprintf(message_token, "HelpIconbar");
} else if (window == dialog_info) {
sprintf(message_token, "HelpAppInfo%i", (int)icon);
} else if (window == history_window) {
sprintf(message_token, "HelpHistory%i", (int)icon);
} else if (window == dialog_objinfo) {
sprintf(message_token, "HelpObjInfo%i", (int)icon);
} else if (window == dialog_pageinfo) {
sprintf(message_token, "HelpPageInfo%i", (int)icon);
} else if (window == dialog_saveas) {
sprintf(message_token, "HelpSaveAs%i", (int)icon);
} else if (window == dialog_zoom) {
sprintf(message_token, "HelpScaleView%i", (int)icon);
} else if (window == dialog_folder) {
sprintf(message_token, "HelpHotFolder%i", (int)icon);
} else if (window == dialog_entry) {
sprintf(message_token, "HelpHotEntry%i", (int)icon);
} else if ((hotlist_tree) && (window == (wimp_w)hotlist_tree->handle)) {
sprintf(message_token, "HelpHotlist%i",
ro_gui_hotlist_help(message_data->pos.x,
message_data->pos.y));
} else if ((hotlist_tree) && (hotlist_tree->toolbar) &&
(window == hotlist_tree->toolbar->toolbar_handle)) {
sprintf(message_token, "HelpHotToolbar%i", (int)icon);
} else if ((global_history_tree) && (window == (wimp_w)global_history_tree->handle)) {
sprintf(message_token, "HelpGHistory%i",
ro_gui_global_history_help(message_data->pos.x,
message_data->pos.y));
} else if ((global_history_tree) && (global_history_tree->toolbar) &&
(window == global_history_tree->toolbar->toolbar_handle)) {
sprintf(message_token, "HelpGHistoryToolbar%i", (int)icon);
} else if ((g = ro_gui_window_lookup(window)) != NULL) {
sprintf(message_token, "HelpBrowser%i", (int)icon);
} else if ((g = ro_gui_toolbar_lookup(window)) != NULL) {
sprintf(message_token, "HelpToolbar%i", (int)icon);
} else if ((g = ro_gui_status_lookup(window)) != NULL) {
sprintf(message_token, "HelpStatus%i", (int)icon);
}
/* If we've managed to find something so far then we broadcast it
*/
if (message_token[0] != 0x00) {
/* Check to see if we are greyed out
*/
if ((icon >= 0) && (ro_gui_get_icon_shaded_state(window, icon))) {
strcat(message_token, "g");
}
/* Broadcast out message
*/
ro_gui_interactive_help_broadcast(message, &message_token[0]);
return;
}
/* If we are not on an icon, we can't be in a menu (which stops separators
giving help for their parent) so we abort. You don't even want to think
about the awful hack I was considering before I realised this...
*/
if (icon == (wimp_i)-1) return;
/* As a last resort, check for menu help.
*/
if (xwimp_get_menu_state((wimp_menu_state_flags)1,
&menu_tree,
window, icon)) return;
if (menu_tree.items[0] == -1) return;
/* Set the prefix
*/
if (current_menu == iconbar_menu) {
sprintf(message_token, "HelpIconMenu");
} else if (current_menu == browser_menu) {
sprintf(message_token, "HelpBrowserMenu");
} else if (current_menu == hotlist_menu) {
sprintf(message_token, "HelpHotlistMenu");
} else {
return;
}
/* Decode the menu
*/
index = 0;
test_menu = current_menu;
while (menu_tree.items[index] != -1) {
/* Check if we're greyed out
*/
greyed |= test_menu->entries[menu_tree.items[index]].icon_flags & wimp_ICON_SHADED;
test_menu = test_menu->entries[menu_tree.items[index]].sub_menu;
/* Continue adding the entries
*/
if (index == 0) {
sprintf(menu_buffer, "%i", menu_tree.items[index]);
} else {
sprintf(menu_buffer, "-%i", menu_tree.items[index]);
}
strcat(message_token, menu_buffer);
index++;
}
if (greyed) strcat(message_token, "g");
/* Finally, broadcast the menu help
*/
ro_gui_interactive_help_broadcast(message, &message_token[0]);
}
/**
* Broadcasts a help reply
*
* \param message the original request message
* \param token the token to look up
*/
static void ro_gui_interactive_help_broadcast(wimp_message *message, char *token) {
const char *translated_token;
help_full_message_reply *reply;
char *base_token;
/* Start off with an empty reply
*/
reply = (help_full_message_reply *)message;
reply->reply[0] = '\0';
/* Check if the message exists
*/
translated_token = messages_get(token);
if (translated_token == token) {
/* We must never provide default help for a 'g' suffix.
*/
if (token[strlen(token) - 1] != 'g') {
/* Find the key from the token.
*/
base_token = token;
while (base_token[0] != 0x00) {
if ((base_token[0] == '-') ||
((base_token[0] >= '0') && (base_token[0] <= '9'))) {
base_token[0] = 0x00;
} else {
++base_token;
}
}
/* Check if the base key exists and use an empty string if not
*/
translated_token = messages_get(token);
}
}
/* Copy our message string
*/
if (translated_token != token) {
reply->reply[235] = 0;
strncpy(reply->reply, translated_token, 235);
}
/* Broadcast the help reply
*/
reply->size = 256;
reply->action = message_HELP_REPLY;
reply->your_ref = reply->my_ref;
wimp_send_message(wimp_USER_MESSAGE, (wimp_message *)reply, reply->sender);
}
/**
* Checks if interactive help is running
*
* \return non-zero if interactive help is available, or 0 if not available
*/
int ro_gui_interactive_help_available() {
taskmanager_task task;
int context = 0;
char *end;
os_t time;
/* Check if we've received a help request in the last 1.0s to test for generic
interactive help applications
*/
xos_read_monotonic_time(&time);
if ((help_time + 100) > time) return true;
/* Attempt to find the task 'Help'
*/
do {
if (xtaskmanager_enumerate_tasks(context, &task, sizeof(taskmanager_task),
&context, &end)) return 0;
/* We can't just use strcmp due to string termination issues.
*/
if (strncmp(task.name, "Help", 4) == 0) {
if (task.name[4] < 32) return true;
} else if (strncmp(task.name, "Floating Help", 13) == 0) {
if (task.name[13] < 32) return true;
}
} while (context >= 0);
/* Return failure
*/
return 0;
}