mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-15 00:32:38 +03:00
c105738fa3
This changes the LOG macro to be varadic removing the need for all callsites to have double bracketing and allows for future improvement on how we use the logging macros. The callsites were changed with coccinelle and the changes checked by hand. Compile tested for several frontends but not all. A formatting annotation has also been added which allows the compiler to check the parameters and types passed to the logging.
1790 lines
45 KiB
C
1790 lines
45 KiB
C
/*
|
|
* Copyright 2004, 2005 Richard Wilson <info@tinct.net>
|
|
* Copyright 2010, 2011 Stephen Fryatt <stevef@netsurf-browser.org>
|
|
*
|
|
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
|
*
|
|
* NetSurf is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* NetSurf is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/** \file
|
|
* Window toolbars (implementation).
|
|
*/
|
|
|
|
#include <alloca.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include "oslib/dragasprite.h"
|
|
#include "oslib/os.h"
|
|
#include "oslib/osgbpb.h"
|
|
#include "oslib/osfile.h"
|
|
#include "oslib/osfind.h"
|
|
#include "oslib/osspriteop.h"
|
|
#include "oslib/wimpspriteop.h"
|
|
#include "oslib/squash.h"
|
|
#include "oslib/wimp.h"
|
|
#include "oslib/wimpextend.h"
|
|
#include "oslib/wimpspriteop.h"
|
|
|
|
#include "utils/log.h"
|
|
#include "utils/utils.h"
|
|
#include "utils/nsoption.h"
|
|
#include "content/content.h"
|
|
#include "desktop/plotters.h"
|
|
|
|
#include "riscos/cookies.h"
|
|
#include "riscos/dialog.h"
|
|
#include "riscos/global_history.h"
|
|
#include "riscos/gui.h"
|
|
#include "riscos/gui/button_bar.h"
|
|
#include "riscos/gui/throbber.h"
|
|
#include "riscos/gui/url_bar.h"
|
|
#include "riscos/hotlist.h"
|
|
#include "riscos/menus.h"
|
|
#include "riscos/save.h"
|
|
#include "riscos/theme.h"
|
|
#include "riscos/toolbar.h"
|
|
#include "riscos/treeview.h"
|
|
#include "riscos/url_complete.h"
|
|
#include "riscos/wimp.h"
|
|
#include "riscos/wimp_event.h"
|
|
#include "riscos/wimputils.h"
|
|
#include "riscos/window.h"
|
|
|
|
|
|
#define TOOLBAR_WIDGET_GUTTER 8
|
|
#define TOOLBAR_DEFAULT_WIDTH 16384
|
|
|
|
/* Toolbar rows used to index into the arrays of row-specific data.
|
|
*/
|
|
|
|
#define TOOLBAR_ROW_TOP 0
|
|
#define TOOLBAR_ROW_DIV1 1
|
|
#define TOOLBAR_ROW_EDIT 2
|
|
#define TOOLBAR_MAX_ROWS 3
|
|
|
|
/* The toolbar data structure.
|
|
*/
|
|
|
|
struct toolbar {
|
|
/** Bar details. */
|
|
struct theme_descriptor *theme;
|
|
theme_style style;
|
|
toolbar_flags flags;
|
|
|
|
int current_width, current_height;
|
|
int full_width, full_height;
|
|
int clip_width, clip_height;
|
|
|
|
/** Toolbar and parent window handles. */
|
|
wimp_w toolbar_handle;
|
|
wimp_w parent_handle;
|
|
|
|
/** Row locations and sizes. */
|
|
int row_y0[TOOLBAR_MAX_ROWS];
|
|
int row_y1[TOOLBAR_MAX_ROWS];
|
|
|
|
/** Details for the button bar. */
|
|
struct button_bar *buttons;
|
|
bool buttons_display;
|
|
os_coord buttons_size;
|
|
|
|
/** Details for the URL bar. */
|
|
struct url_bar *url;
|
|
bool url_display;
|
|
os_coord url_size;
|
|
|
|
/** Details for the throbber. */
|
|
struct throbber *throbber;
|
|
bool throbber_display;
|
|
bool throbber_right;
|
|
os_coord throbber_size;
|
|
|
|
/** Client callback data. */
|
|
const struct toolbar_callbacks *callbacks;
|
|
void *client_data;
|
|
|
|
/** Details for the toolbar editor. */
|
|
wimp_i editor_div1;
|
|
struct button_bar *editor;
|
|
os_coord editor_size;
|
|
|
|
bool editing;
|
|
|
|
/** Interactive help data. */
|
|
|
|
const char *help_prefix;
|
|
|
|
/** The next bar in the toolbar list. */
|
|
struct toolbar *next;
|
|
};
|
|
|
|
|
|
/* Global variables for the toolbar module.
|
|
*/
|
|
|
|
/** The list of defined toolbars. */
|
|
static struct toolbar *ro_toolbar_bars = NULL;
|
|
|
|
/** The Toolber Menu */
|
|
wimp_menu *toolbar_menu;
|
|
|
|
|
|
/* A basic window definition for the toolbar and status bar.
|
|
*/
|
|
|
|
static wimp_window ro_toolbar_window = {
|
|
{0, 0, 1, 1},
|
|
0,
|
|
0,
|
|
wimp_TOP,
|
|
wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | wimp_WINDOW_NO_BOUNDS |
|
|
wimp_WINDOW_FURNITURE_WINDOW |
|
|
wimp_WINDOW_IGNORE_XEXTENT | wimp_WINDOW_IGNORE_YEXTENT,
|
|
wimp_COLOUR_BLACK,
|
|
wimp_COLOUR_LIGHT_GREY,
|
|
wimp_COLOUR_LIGHT_GREY,
|
|
wimp_COLOUR_VERY_LIGHT_GREY,
|
|
wimp_COLOUR_DARK_GREY,
|
|
wimp_COLOUR_MID_LIGHT_GREY,
|
|
wimp_COLOUR_CREAM,
|
|
wimp_WINDOW_NEVER3D | 0x16u /* RISC OS 5.03+ */,
|
|
{0, 0, TOOLBAR_DEFAULT_WIDTH, 16384},
|
|
0,
|
|
wimp_BUTTON_DOUBLE_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT,
|
|
wimpspriteop_AREA,
|
|
1,
|
|
1,
|
|
{""},
|
|
0,
|
|
{ }
|
|
};
|
|
|
|
static char ro_toolbar_null_string[] = "";
|
|
static char ro_toolbar_line_validation[] = "R2";
|
|
|
|
/*
|
|
* Private function prototypes.
|
|
*/
|
|
|
|
static void ro_toolbar_update_current_widgets(struct toolbar *toolbar);
|
|
static void ro_toolbar_refresh_widget_dimensions(struct toolbar *toolbar);
|
|
static void ro_toolbar_reformat_widgets(struct toolbar *toolbar);
|
|
|
|
static void ro_toolbar_redraw(wimp_draw *redraw);
|
|
static bool ro_toolbar_click(wimp_pointer *pointer);
|
|
static bool ro_toolbar_keypress(wimp_key *key);
|
|
static bool ro_toolbar_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
|
|
wimp_pointer *pointer);
|
|
static void ro_toolbar_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
|
|
wimp_selection *selection, menu_action action);
|
|
static bool ro_toolbar_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
|
|
wimp_selection *selection, menu_action action);
|
|
static const char *ro_toolbar_get_help_suffix(wimp_w w, wimp_i i, os_coord *pos,
|
|
wimp_mouse_state buttons);
|
|
|
|
static void ro_toolbar_update_buttons(struct toolbar *toolbar);
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_init(void)
|
|
{
|
|
/* browser toolbar menu */
|
|
static const struct ns_menu toolbar_definition = {
|
|
"Toolbar", {
|
|
{ "Toolbars", NO_ACTION, 0 },
|
|
{ "Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
|
|
{ "Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 },
|
|
{ "Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 },
|
|
{ "EditToolbar", TOOLBAR_EDIT, 0 },
|
|
{NULL, 0, 0}
|
|
}
|
|
};
|
|
toolbar_menu = ro_gui_menu_define_menu(
|
|
&toolbar_definition);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
struct toolbar *ro_toolbar_create(struct theme_descriptor *descriptor,
|
|
wimp_w parent, theme_style style, toolbar_flags bar_flags,
|
|
const struct toolbar_callbacks *callbacks, void *client_data,
|
|
const char *help)
|
|
{
|
|
struct toolbar *toolbar;
|
|
|
|
/* Allocate memory for the bar and link it into the list of bars. */
|
|
|
|
toolbar = calloc(sizeof(struct toolbar), 1);
|
|
if (toolbar == NULL) {
|
|
LOG("No memory for malloc()");
|
|
warn_user("NoMemory", 0);
|
|
return NULL;
|
|
}
|
|
|
|
toolbar->next = ro_toolbar_bars;
|
|
ro_toolbar_bars = toolbar;
|
|
|
|
/* Store the supplied settings. */
|
|
|
|
toolbar->flags = bar_flags;
|
|
toolbar->theme = descriptor;
|
|
toolbar->style = style;
|
|
toolbar->parent_handle = parent;
|
|
toolbar->callbacks = callbacks;
|
|
toolbar->client_data = client_data;
|
|
|
|
/* Set up the internal widgets: initially, there are none. */
|
|
|
|
toolbar->buttons = NULL;
|
|
toolbar->buttons_display = false;
|
|
|
|
toolbar->url = NULL;
|
|
toolbar->url_display = false;
|
|
|
|
toolbar->throbber = NULL;
|
|
toolbar->throbber_display = false;
|
|
|
|
/* Set up the bar editor. */
|
|
|
|
toolbar->editor = NULL;
|
|
toolbar->editor_div1 = -1;
|
|
|
|
toolbar->editing = false;
|
|
|
|
toolbar->help_prefix = help;
|
|
|
|
return toolbar;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_add_buttons(struct toolbar *toolbar,
|
|
const struct button_bar_buttons buttons[], char *button_order)
|
|
{
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
if (toolbar->buttons != NULL)
|
|
return false;
|
|
|
|
toolbar->buttons = ro_gui_button_bar_create(toolbar->theme, buttons);
|
|
if (toolbar->buttons != NULL) {
|
|
toolbar->buttons_display = true;
|
|
ro_gui_button_bar_arrange_buttons(toolbar->buttons,
|
|
button_order);
|
|
}
|
|
|
|
toolbar->editor = ro_gui_button_bar_create(toolbar->theme, buttons);
|
|
if (toolbar->editor != NULL)
|
|
ro_gui_button_bar_hide(toolbar->editor, !toolbar->editing);
|
|
|
|
if (toolbar->buttons != NULL && toolbar->editor != NULL)
|
|
if (!ro_gui_button_bar_link_editor(toolbar->buttons,
|
|
toolbar->editor,
|
|
(void (*)(void *))
|
|
ro_toolbar_update_current_widgets,
|
|
toolbar))
|
|
return false;
|
|
|
|
return (toolbar->buttons == NULL || toolbar->editor == NULL) ?
|
|
false : true;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_add_throbber(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
if (toolbar->throbber != NULL)
|
|
return false;
|
|
|
|
toolbar->throbber = ro_gui_throbber_create(toolbar->theme);
|
|
|
|
if (toolbar->throbber != NULL)
|
|
toolbar->throbber_display = true;
|
|
|
|
return (toolbar->throbber == NULL) ? false : true;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_add_url(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
if (toolbar->url != NULL)
|
|
return false;
|
|
|
|
toolbar->url = ro_gui_url_bar_create(toolbar->theme);
|
|
|
|
if (toolbar->url != NULL)
|
|
toolbar->url_display = true;
|
|
|
|
return (toolbar->url == NULL) ? false : true;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_rebuild(struct toolbar *toolbar)
|
|
{
|
|
os_error *error;
|
|
wimp_icon_create icon;
|
|
wimp_w old_window = NULL;
|
|
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
/* Start to set up the toolbar window. */
|
|
|
|
ro_toolbar_window.sprite_area =
|
|
ro_gui_theme_get_sprites(toolbar->theme);
|
|
ro_toolbar_window.work_bg =
|
|
ro_gui_theme_get_style_element(toolbar->theme,
|
|
toolbar->style, THEME_ELEMENT_BACKGROUND);
|
|
|
|
/* Delete any existing toolbar window... */
|
|
|
|
if (toolbar->toolbar_handle != NULL) {
|
|
old_window = toolbar->toolbar_handle;
|
|
error = xwimp_delete_window(toolbar->toolbar_handle);
|
|
if (error)
|
|
LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
|
|
toolbar->toolbar_handle = NULL;
|
|
}
|
|
|
|
/* ...and create a new window. */
|
|
|
|
error = xwimp_create_window(&ro_toolbar_window,
|
|
&toolbar->toolbar_handle);
|
|
if (error) {
|
|
LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return false;
|
|
}
|
|
|
|
/* Set up the toolbar's event handlers. Only set the user activity-
|
|
* related callbacks if the bar isn't for display purposes. If the
|
|
* toolbar is being recreated, simply transfer the handlers across
|
|
* from the old, now-deleted window.
|
|
*/
|
|
|
|
if (old_window == NULL) {
|
|
ro_gui_wimp_event_register_redraw_window(
|
|
toolbar->toolbar_handle, ro_toolbar_redraw);
|
|
ro_gui_wimp_event_set_user_data(toolbar->toolbar_handle,
|
|
toolbar);
|
|
|
|
if (!(toolbar->flags & TOOLBAR_FLAGS_DISPLAY)) {
|
|
ro_gui_wimp_event_register_mouse_click(
|
|
toolbar->toolbar_handle,
|
|
ro_toolbar_click);
|
|
ro_gui_wimp_event_register_keypress(
|
|
toolbar->toolbar_handle,
|
|
ro_toolbar_keypress);
|
|
ro_gui_wimp_event_register_menu_prepare(
|
|
toolbar->toolbar_handle,
|
|
ro_toolbar_menu_prepare);
|
|
ro_gui_wimp_event_register_menu_warning(
|
|
toolbar->toolbar_handle,
|
|
ro_toolbar_menu_warning);
|
|
ro_gui_wimp_event_register_menu_selection(
|
|
toolbar->toolbar_handle,
|
|
ro_toolbar_menu_select);
|
|
ro_gui_wimp_event_register_menu(toolbar->toolbar_handle,
|
|
toolbar_menu, true, false);
|
|
ro_gui_wimp_event_register_help_suffix(
|
|
toolbar->toolbar_handle,
|
|
ro_toolbar_get_help_suffix);
|
|
}
|
|
} else {
|
|
ro_gui_wimp_event_transfer(old_window, toolbar->toolbar_handle);
|
|
}
|
|
|
|
/* The help prefix changes from edit to non-edit more. */
|
|
|
|
ro_gui_wimp_event_set_help_prefix(toolbar->toolbar_handle,
|
|
(toolbar->editing) ?
|
|
"HelpEditToolbar" : toolbar->help_prefix);
|
|
|
|
/* Place the widgets into the new bar, using the new theme.
|
|
*
|
|
* \TODO -- If any widgets fail to rebuild, then we currently just
|
|
* carry on without them. Not sure if the whole bar
|
|
* rebuild should fail here?
|
|
*/
|
|
|
|
if (toolbar->throbber != NULL) {
|
|
if (!ro_gui_throbber_rebuild(toolbar->throbber, toolbar->theme,
|
|
toolbar->style, toolbar->toolbar_handle,
|
|
toolbar->editing)) {
|
|
ro_gui_throbber_destroy(toolbar->throbber);
|
|
toolbar->throbber = NULL;
|
|
}
|
|
|
|
ro_gui_theme_get_throbber_data(toolbar->theme, NULL, NULL, NULL,
|
|
&toolbar->throbber_right, NULL);
|
|
}
|
|
|
|
if (toolbar->buttons != NULL) {
|
|
if (!ro_gui_button_bar_rebuild(toolbar->buttons, toolbar->theme,
|
|
toolbar->style, toolbar->toolbar_handle,
|
|
toolbar->editing)) {
|
|
ro_gui_button_bar_destroy(toolbar->buttons);
|
|
toolbar->buttons = NULL;
|
|
}
|
|
}
|
|
|
|
if (toolbar->editor != NULL) {
|
|
if (!ro_gui_button_bar_rebuild(toolbar->editor, toolbar->theme,
|
|
toolbar->style, toolbar->toolbar_handle,
|
|
toolbar->editing)) {
|
|
ro_gui_button_bar_destroy(toolbar->editor);
|
|
toolbar->editor = NULL;
|
|
}
|
|
}
|
|
|
|
if (toolbar->url != NULL) {
|
|
if (!ro_gui_url_bar_rebuild(toolbar->url, toolbar->theme,
|
|
toolbar->style, toolbar->toolbar_handle,
|
|
toolbar->flags & TOOLBAR_FLAGS_DISPLAY,
|
|
toolbar->editing)) {
|
|
ro_gui_url_bar_destroy(toolbar->url);
|
|
toolbar->url = NULL;
|
|
}
|
|
}
|
|
|
|
/* If this is an editor, add in a divider icon and the editor
|
|
* button bar.
|
|
*/
|
|
|
|
if (toolbar->editing) {
|
|
icon.w = toolbar->toolbar_handle;
|
|
icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
|
|
wimp_ICON_VCENTRED | wimp_ICON_BORDER |
|
|
(wimp_COLOUR_BLACK <<
|
|
wimp_ICON_FG_COLOUR_SHIFT) |
|
|
(wimp_COLOUR_VERY_LIGHT_GREY <<
|
|
wimp_ICON_BG_COLOUR_SHIFT);
|
|
icon.icon.extent.x0 = 0;
|
|
icon.icon.extent.x1 = 0;
|
|
icon.icon.extent.y1 = 0;
|
|
icon.icon.extent.y0 = 0;
|
|
icon.icon.data.indirected_text.text = ro_toolbar_null_string;
|
|
icon.icon.data.indirected_text.validation =
|
|
ro_toolbar_line_validation;
|
|
icon.icon.data.indirected_text.size = 1;
|
|
error = xwimp_create_icon(&icon, &toolbar->editor_div1);
|
|
if (error) {
|
|
LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
toolbar->editor_div1 = -1;
|
|
}
|
|
}
|
|
|
|
/* Establish the required dimensions to fit the widgets, then
|
|
* reflow the bar contents.
|
|
*/
|
|
|
|
ro_toolbar_refresh_widget_dimensions(toolbar);
|
|
|
|
ro_toolbar_process(toolbar, -1, true);
|
|
|
|
if (toolbar->parent_handle != NULL)
|
|
ro_toolbar_attach(toolbar, toolbar->parent_handle);
|
|
|
|
ro_toolbar_update_buttons(toolbar);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_attach(struct toolbar *toolbar, wimp_w parent)
|
|
{
|
|
wimp_outline outline;
|
|
wimp_window_state state;
|
|
os_error *error;
|
|
|
|
if (toolbar == NULL || toolbar->toolbar_handle == NULL)
|
|
return false;
|
|
|
|
toolbar->parent_handle = parent;
|
|
|
|
/* Only try to attach the toolbar if there's any of it visible to
|
|
* matter.
|
|
*/
|
|
|
|
if (toolbar->current_height > 0) {
|
|
outline.w = parent;
|
|
xwimp_get_window_outline(&outline);
|
|
state.w = parent;
|
|
xwimp_get_window_state(&state);
|
|
state.w = toolbar->toolbar_handle;
|
|
state.visible.x1 = outline.outline.x1 - 2;
|
|
state.visible.y0 = state.visible.y1 + 2 -
|
|
toolbar->current_height;
|
|
state.xscroll = 0;
|
|
state.yscroll = 0;
|
|
error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), parent,
|
|
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
|
|
<< wimp_CHILD_XORIGIN_SHIFT |
|
|
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
|
|
<< wimp_CHILD_YORIGIN_SHIFT |
|
|
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
|
|
<< wimp_CHILD_LS_EDGE_SHIFT |
|
|
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
|
|
<< wimp_CHILD_BS_EDGE_SHIFT |
|
|
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
|
|
<< wimp_CHILD_RS_EDGE_SHIFT |
|
|
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
|
|
<< wimp_CHILD_TS_EDGE_SHIFT);
|
|
if (error) {
|
|
LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
error = xwimp_close_window(toolbar->toolbar_handle);
|
|
if (error) {
|
|
LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_process(struct toolbar *toolbar, int width, bool reformat)
|
|
{
|
|
os_error *error;
|
|
wimp_outline outline;
|
|
wimp_window_state state;
|
|
os_box extent;
|
|
int old_height, old_width;
|
|
|
|
if (!toolbar)
|
|
return false;
|
|
|
|
old_height = toolbar->current_height;
|
|
old_width = toolbar->current_width;
|
|
|
|
/* Measure the parent window width if the caller has asked us to
|
|
* calculate the clip width ourselves. Otherwise, if a clip width
|
|
* has been specified, set the clip to that.
|
|
*/
|
|
|
|
if ((toolbar->parent_handle != NULL) && (width == -1)) {
|
|
outline.w = toolbar->parent_handle;
|
|
error = xwimp_get_window_outline(&outline);
|
|
if (error) {
|
|
LOG("xwimp_get_window_outline: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return false;
|
|
}
|
|
|
|
toolbar->clip_width = outline.outline.x1 -
|
|
outline.outline.x0 - 2;
|
|
toolbar->current_width = toolbar->clip_width;
|
|
} else if (width != -1) {
|
|
toolbar->clip_width = width;
|
|
toolbar->current_width = toolbar->clip_width;
|
|
}
|
|
|
|
/* Find the parent visible height to clip our toolbar height to
|
|
*/
|
|
|
|
if (toolbar->parent_handle != NULL) {
|
|
state.w = toolbar->parent_handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error) {
|
|
LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return false;
|
|
}
|
|
|
|
toolbar->clip_height = state.visible.y1 - state.visible.y0 + 2;
|
|
|
|
/* We can't obscure the height of the scroll bar as we
|
|
* lose the resize icon if we do.
|
|
*/
|
|
|
|
if (toolbar->clip_height >= toolbar->full_height)
|
|
toolbar->current_height = toolbar->full_height;
|
|
else
|
|
toolbar->current_height = toolbar->clip_height;
|
|
|
|
/* Resize the work area extent and update our position. */
|
|
|
|
if (old_height != toolbar->current_height) {
|
|
extent.x0 = 0;
|
|
extent.y0 = 0;
|
|
extent.x1 = TOOLBAR_DEFAULT_WIDTH;
|
|
extent.y1 = toolbar->current_height - 2;
|
|
error = xwimp_set_extent(toolbar->toolbar_handle,
|
|
&extent);
|
|
if (error) {
|
|
LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
}
|
|
|
|
ro_toolbar_attach(toolbar, toolbar->parent_handle);
|
|
}
|
|
} else {
|
|
toolbar->clip_height = toolbar->full_height;
|
|
toolbar->current_height = toolbar->full_height;
|
|
}
|
|
|
|
/* Reflow the widgets into the toolbar if the dimensions have
|
|
* changed or we have been asked to anyway. */
|
|
|
|
if (toolbar->current_width != old_width || reformat)
|
|
ro_toolbar_reformat_widgets(toolbar);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Update the widgets currently on view in a toolbar. This can be used
|
|
* generally, but is primarily offered to widgets as a way for them
|
|
* to force an update.
|
|
*
|
|
* \param *toolbar The toolbar to update.
|
|
*/
|
|
|
|
void ro_toolbar_update_current_widgets(struct toolbar *toolbar)
|
|
{
|
|
int old_height;
|
|
|
|
if (toolbar == NULL)
|
|
return;
|
|
|
|
old_height = toolbar->full_height;
|
|
|
|
ro_toolbar_refresh_widget_dimensions(toolbar);
|
|
ro_toolbar_reformat_widgets(toolbar);
|
|
|
|
/* If the toolbar height has changed, we need to tell the client. */
|
|
|
|
if (toolbar->full_height != old_height)
|
|
ro_toolbar_refresh(toolbar);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the minimum dimenstions required by the toolbar widgets after
|
|
* these have changed. The minimum dimensions are assumed not to change
|
|
* unless we change theme (ie. we rebuild the bar) or we knowingly
|
|
* alter a widget (eg. we add or remove button-bar buttons).
|
|
*
|
|
*
|
|
* \param *toolbar The toolbar to refresh.
|
|
*/
|
|
|
|
void ro_toolbar_refresh_widget_dimensions(struct toolbar *toolbar)
|
|
{
|
|
int width, height;
|
|
int row_width, row_height;
|
|
|
|
if (toolbar == NULL)
|
|
return;
|
|
|
|
/* Process the toolbar editor and any associated divider rows.
|
|
*/
|
|
|
|
if (toolbar->editor != NULL && toolbar->editing) {
|
|
width = 0;
|
|
height = 0;
|
|
ro_gui_button_bar_get_dims(toolbar->editor, &width, &height);
|
|
|
|
toolbar->editor_size.x = width;
|
|
toolbar->editor_size.y = height;
|
|
|
|
toolbar->row_y0[TOOLBAR_ROW_EDIT] = TOOLBAR_WIDGET_GUTTER;
|
|
toolbar->row_y1[TOOLBAR_ROW_EDIT] = TOOLBAR_WIDGET_GUTTER
|
|
+ height;
|
|
|
|
toolbar->row_y0[TOOLBAR_ROW_DIV1] = TOOLBAR_WIDGET_GUTTER +
|
|
toolbar->row_y1[TOOLBAR_ROW_EDIT];
|
|
toolbar->row_y1[TOOLBAR_ROW_DIV1] = 8 +
|
|
toolbar->row_y0[TOOLBAR_ROW_DIV1];
|
|
} else {
|
|
toolbar->editor_size.x = 0;
|
|
toolbar->editor_size.y = 0;
|
|
|
|
toolbar->row_y0[TOOLBAR_ROW_EDIT] = 0;
|
|
toolbar->row_y1[TOOLBAR_ROW_EDIT] = 0;
|
|
toolbar->row_y0[TOOLBAR_ROW_DIV1] = 0;
|
|
toolbar->row_y1[TOOLBAR_ROW_DIV1] = 0;
|
|
}
|
|
|
|
/* Process the top row icons. */
|
|
|
|
row_width = 0;
|
|
row_height = 0;
|
|
|
|
/* If the editor is active, any button bar if forced into view. */
|
|
|
|
if (toolbar->buttons != NULL &&
|
|
(toolbar->buttons_display || toolbar->editing)) {
|
|
width = 0;
|
|
height = 0;
|
|
ro_gui_button_bar_get_dims(toolbar->buttons, &width, &height);
|
|
|
|
row_width += width;
|
|
toolbar->buttons_size.x = width;
|
|
toolbar->buttons_size.y = height;
|
|
|
|
if (height > row_height)
|
|
row_height = height;
|
|
} else {
|
|
toolbar->buttons_size.x = 0;
|
|
toolbar->buttons_size.y = 0;
|
|
}
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display) {
|
|
width = 0;
|
|
height = 0;
|
|
ro_gui_url_bar_get_dims(toolbar->url, &width, &height);
|
|
|
|
if (row_width > 0)
|
|
row_width += TOOLBAR_WIDGET_GUTTER;
|
|
row_width += width;
|
|
|
|
toolbar->url_size.x = width;
|
|
toolbar->url_size.y = height;
|
|
|
|
if (height > row_height)
|
|
row_height = height;
|
|
} else {
|
|
toolbar->url_size.x = 0;
|
|
toolbar->url_size.y = 0;
|
|
}
|
|
|
|
if (toolbar->throbber != NULL && toolbar->throbber_display) {
|
|
width = 0;
|
|
height = 0;
|
|
ro_gui_throbber_get_dims(toolbar->throbber, &width, &height);
|
|
|
|
if (row_width > 0)
|
|
row_width += TOOLBAR_WIDGET_GUTTER;
|
|
row_width += width;
|
|
|
|
toolbar->throbber_size.x = width;
|
|
toolbar->throbber_size.y = height;
|
|
|
|
if (height > row_height)
|
|
row_height = height;
|
|
} else {
|
|
toolbar->throbber_size.x = 0;
|
|
toolbar->throbber_size.y = 0;
|
|
}
|
|
|
|
if (row_height > 0) {
|
|
toolbar->row_y0[TOOLBAR_ROW_TOP] = TOOLBAR_WIDGET_GUTTER +
|
|
toolbar->row_y1[TOOLBAR_ROW_DIV1];
|
|
toolbar->row_y1[TOOLBAR_ROW_TOP] = row_height +
|
|
toolbar->row_y0[TOOLBAR_ROW_TOP];
|
|
} else {
|
|
toolbar->row_y0[TOOLBAR_ROW_TOP] = 0;
|
|
toolbar->row_y1[TOOLBAR_ROW_TOP] = 0;
|
|
}
|
|
|
|
/* Establish the full dimensions of the bar.
|
|
*
|
|
* \TODO -- This currently assumes an "all or nothing" approach to
|
|
* the editor bar, and will need reworking once we have to
|
|
* worry about tab bars.
|
|
*/
|
|
|
|
if (toolbar->row_y1[TOOLBAR_ROW_TOP] > 0) {
|
|
toolbar->full_height = toolbar->row_y1[TOOLBAR_ROW_TOP] +
|
|
TOOLBAR_WIDGET_GUTTER;
|
|
} else {
|
|
toolbar->full_height = 0;
|
|
}
|
|
toolbar->full_width = 2 * TOOLBAR_WIDGET_GUTTER +
|
|
((row_width > toolbar->editor_size.x) ?
|
|
row_width : toolbar->editor_size.x);
|
|
}
|
|
|
|
|
|
/**
|
|
* Reformat (reflow) the widgets into the toolbar, based on the toolbar size
|
|
* and the previously calculated widget dimensions.
|
|
*
|
|
* \param *toolbar The toolbar to reformat.
|
|
*/
|
|
|
|
void ro_toolbar_reformat_widgets(struct toolbar *toolbar)
|
|
{
|
|
int left_margin, right_margin;
|
|
|
|
left_margin = TOOLBAR_WIDGET_GUTTER;
|
|
right_margin = toolbar->clip_width - TOOLBAR_WIDGET_GUTTER;
|
|
|
|
/* Flow the toolbar editor row, which will be a fixed with and
|
|
* may alter the right margin.
|
|
*/
|
|
|
|
if (toolbar->editor != NULL && toolbar->editing) {
|
|
if (right_margin < left_margin + toolbar->editor_size.x)
|
|
right_margin = left_margin + toolbar->editor_size.x;
|
|
|
|
ro_gui_button_bar_set_extent(toolbar->editor,
|
|
left_margin,
|
|
toolbar->row_y0[TOOLBAR_ROW_EDIT],
|
|
left_margin + toolbar->editor_size.x,
|
|
toolbar->row_y1[TOOLBAR_ROW_EDIT]);
|
|
|
|
if (toolbar->editor_div1 != -1)
|
|
xwimp_resize_icon(toolbar->toolbar_handle,
|
|
toolbar->editor_div1, -8,
|
|
toolbar->row_y0[TOOLBAR_ROW_DIV1],
|
|
toolbar->clip_width + 8,
|
|
toolbar->row_y1[TOOLBAR_ROW_DIV1]);
|
|
}
|
|
|
|
/* Flow the top row. */
|
|
|
|
if (toolbar->throbber != NULL && toolbar->throbber_display) {
|
|
if (toolbar->throbber_right) {
|
|
right_margin -= (toolbar->throbber_size.x +
|
|
TOOLBAR_WIDGET_GUTTER);
|
|
} else {
|
|
ro_gui_throbber_set_extent(toolbar->throbber,
|
|
left_margin,
|
|
toolbar->row_y0[TOOLBAR_ROW_TOP],
|
|
left_margin + toolbar->throbber_size.x,
|
|
toolbar->row_y1[TOOLBAR_ROW_TOP]);
|
|
left_margin += (toolbar->throbber_size.x +
|
|
TOOLBAR_WIDGET_GUTTER);
|
|
}
|
|
}
|
|
|
|
if (toolbar->buttons != NULL &&
|
|
(toolbar->buttons_display || toolbar->editing)) {
|
|
if (right_margin < left_margin + toolbar->buttons_size.x)
|
|
right_margin = left_margin + toolbar->buttons_size.x;
|
|
|
|
ro_gui_button_bar_set_extent(toolbar->buttons,
|
|
left_margin,
|
|
toolbar->row_y0[TOOLBAR_ROW_TOP],
|
|
left_margin + toolbar->buttons_size.x,
|
|
toolbar->row_y1[TOOLBAR_ROW_TOP]);
|
|
left_margin += (toolbar->buttons_size.x +
|
|
TOOLBAR_WIDGET_GUTTER);
|
|
}
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display) {
|
|
if (right_margin < left_margin + toolbar->url_size.x)
|
|
right_margin = left_margin + toolbar->url_size.x;
|
|
|
|
ro_gui_url_bar_set_extent(toolbar->url,
|
|
left_margin,
|
|
toolbar->row_y0[TOOLBAR_ROW_TOP],
|
|
right_margin,
|
|
toolbar->row_y1[TOOLBAR_ROW_TOP]);
|
|
|
|
left_margin = right_margin + TOOLBAR_WIDGET_GUTTER;
|
|
}
|
|
|
|
if (toolbar->throbber != NULL && toolbar->throbber_display &&
|
|
toolbar->throbber_right) {
|
|
left_margin = right_margin + TOOLBAR_WIDGET_GUTTER;
|
|
ro_gui_throbber_set_extent(toolbar->throbber,
|
|
left_margin,
|
|
toolbar->row_y0[TOOLBAR_ROW_TOP],
|
|
left_margin + toolbar->throbber_size.x,
|
|
toolbar->row_y1[TOOLBAR_ROW_TOP]);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_destroy(struct toolbar *toolbar)
|
|
{
|
|
struct toolbar *bar;
|
|
|
|
if (toolbar == NULL)
|
|
return;
|
|
|
|
LOG("Destroying toolbar 0x%x", (unsigned int)toolbar);
|
|
|
|
/* Destroy the widgets. */
|
|
|
|
if (toolbar->buttons != NULL)
|
|
ro_gui_button_bar_destroy(toolbar->buttons);
|
|
|
|
if (toolbar->editor != NULL)
|
|
ro_gui_button_bar_destroy(toolbar->editor);
|
|
|
|
if (toolbar->url != NULL)
|
|
ro_gui_url_bar_destroy(toolbar->url);
|
|
|
|
if (toolbar->throbber != NULL)
|
|
ro_gui_throbber_destroy(toolbar->throbber);
|
|
|
|
/* Delete the toolbar window. */
|
|
|
|
if (toolbar->toolbar_handle != NULL) {
|
|
xwimp_delete_window(toolbar->toolbar_handle);
|
|
ro_gui_wimp_event_finalise(toolbar->toolbar_handle);
|
|
}
|
|
|
|
/* Remove the bar from the list and free the memory.
|
|
*/
|
|
|
|
if (ro_toolbar_bars == toolbar) {
|
|
ro_toolbar_bars = toolbar->next;
|
|
} else {
|
|
for (bar = ro_toolbar_bars; bar != NULL && bar->next != toolbar;
|
|
bar = bar->next);
|
|
|
|
if (bar->next == toolbar)
|
|
bar->next = toolbar->next;
|
|
}
|
|
|
|
free(toolbar);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle redraw request events for a toolbar workarea.
|
|
*
|
|
* \param *redraw The redraw block for the event.
|
|
*/
|
|
|
|
void ro_toolbar_redraw(wimp_draw *redraw)
|
|
{
|
|
struct toolbar *toolbar;
|
|
osbool more;
|
|
os_error *error;
|
|
|
|
toolbar = (struct toolbar *)ro_gui_wimp_event_get_user_data(redraw->w);
|
|
|
|
assert(toolbar != NULL);
|
|
|
|
error = xwimp_redraw_window(redraw, &more);
|
|
if (error) {
|
|
LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return;
|
|
}
|
|
while (more) {
|
|
ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
|
|
ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
|
|
|
|
if (toolbar->buttons != NULL && toolbar->buttons_display)
|
|
ro_gui_button_bar_redraw(toolbar->buttons, redraw);
|
|
|
|
if (toolbar->editor != NULL && toolbar->editing)
|
|
ro_gui_button_bar_redraw(toolbar->editor, redraw);
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display)
|
|
ro_gui_url_bar_redraw(toolbar->url, redraw);
|
|
|
|
error = xwimp_get_rectangle(redraw, &more);
|
|
if (error) {
|
|
LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Process clicks on a toolbar, passing details on to clients where necessary.
|
|
*
|
|
* \param *pointer The wimp mouse click event.
|
|
* \return True if the event was handled; else false.
|
|
*/
|
|
|
|
bool ro_toolbar_click(wimp_pointer *pointer)
|
|
{
|
|
struct toolbar *toolbar;
|
|
union toolbar_action action;
|
|
wimp_window_state state;
|
|
os_error *error;
|
|
|
|
toolbar = (struct toolbar *)
|
|
ro_gui_wimp_event_get_user_data(pointer->w);
|
|
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
assert(pointer->w == toolbar->toolbar_handle);
|
|
|
|
state.w = toolbar->toolbar_handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error) {
|
|
LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return false;
|
|
}
|
|
|
|
/* If the click wasn't in the URL Bar's text field, then it will
|
|
* need to close any URL Complete window that is open.
|
|
*
|
|
* \TODO -- This should really move into the URL Bar module, as
|
|
* URL Complete is really an extension to that.
|
|
*/
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display &&
|
|
!ro_gui_url_bar_test_for_text_field_click(toolbar->url,
|
|
pointer))
|
|
ro_gui_url_complete_close();
|
|
|
|
/* Pass the click around the toolbar widgets. */
|
|
|
|
if (toolbar->buttons != NULL &&
|
|
(toolbar->buttons_display || toolbar->editing) &&
|
|
ro_gui_button_bar_click(toolbar->buttons, pointer,
|
|
&state, &action.button)) {
|
|
if (action.button != TOOLBAR_BUTTON_NONE &&
|
|
!toolbar->editing &&
|
|
toolbar->callbacks != NULL &&
|
|
toolbar->callbacks->user_action != NULL)
|
|
toolbar->callbacks->user_action(toolbar->client_data,
|
|
TOOLBAR_ACTION_BUTTON, action);
|
|
return true;
|
|
}
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display &&
|
|
ro_gui_url_bar_click(toolbar->url, pointer,
|
|
&state, &action.url)) {
|
|
if (action.url != TOOLBAR_URL_NONE &&
|
|
!toolbar->editing &&
|
|
toolbar->callbacks != NULL &&
|
|
toolbar->callbacks->user_action != NULL)
|
|
toolbar->callbacks->user_action(toolbar->client_data,
|
|
TOOLBAR_ACTION_URL, action);
|
|
return true;
|
|
}
|
|
|
|
if (toolbar->editor != NULL && toolbar->editing &&
|
|
ro_gui_button_bar_click(toolbar->editor, pointer,
|
|
&state, &action.button)) {
|
|
return true;
|
|
}
|
|
|
|
/* Nothing else has handled this, so try passing it to the
|
|
* URL Complete module.
|
|
*
|
|
* \TODO -- This should really move into the URL Bar module, as
|
|
* URL Complete is really an extension to that.
|
|
*/
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display &&
|
|
ro_gui_url_bar_test_for_text_field_click(toolbar->url,
|
|
pointer)) {
|
|
ro_gui_url_complete_start(toolbar);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Process keypresses in a toolbar, passing details on to clients where
|
|
* necessary.
|
|
*
|
|
* \param *key The wimp key press event.
|
|
* \return True if the event was handled; else false.
|
|
*/
|
|
|
|
bool ro_toolbar_keypress(wimp_key *key)
|
|
{
|
|
struct toolbar *toolbar;
|
|
|
|
toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(key->w);
|
|
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
/* Pass the keypress on to the client and stop if they handle it. */
|
|
|
|
if (toolbar->callbacks->key_press != NULL &&
|
|
toolbar->callbacks->key_press(toolbar->client_data, key))
|
|
return true;
|
|
|
|
/* If the caret is in the URL bar, ask the URL Complete module if it
|
|
* wants to handle the keypress.
|
|
*
|
|
* \TODO -- This should really move into the URL Bar module, as
|
|
* URL Complete is really an extension to that.
|
|
*/
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display &&
|
|
ro_gui_url_bar_test_for_text_field_keypress(
|
|
toolbar->url, key) &&
|
|
ro_gui_url_complete_keypress(toolbar, key->c))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Prepare the toolbar menu for (re-)opening
|
|
*
|
|
* \param w The window owning the menu.
|
|
* \param i The icon owning the menu.
|
|
* \param *menu The menu about to be opened.
|
|
* \param *pointer Pointer to the relevant wimp event block, or
|
|
* NULL for an Adjust click.
|
|
* \return true if the event was handled; else false.
|
|
*/
|
|
|
|
bool ro_toolbar_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
|
|
wimp_pointer *pointer)
|
|
{
|
|
struct toolbar *toolbar;
|
|
|
|
toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(w);
|
|
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
/* Pass the event on to potentially interested widgets. */
|
|
|
|
if (toolbar->url != NULL && ro_gui_url_bar_menu_prepare(toolbar->url,
|
|
i, menu, pointer))
|
|
return true;
|
|
|
|
/* Try to process the event as a toolbar menu. */
|
|
|
|
if (menu != toolbar_menu)
|
|
return false;
|
|
|
|
/* Shade menu entries according to the state of the window and object
|
|
* under the pointer.
|
|
*/
|
|
|
|
/* Toolbar (Sub)Menu */
|
|
|
|
ro_gui_menu_set_entry_shaded(menu, TOOLBAR_EDIT,
|
|
ro_toolbar_menu_edit_shade(toolbar));
|
|
ro_gui_menu_set_entry_ticked(menu, TOOLBAR_EDIT,
|
|
ro_toolbar_menu_edit_tick(toolbar));
|
|
|
|
ro_gui_menu_set_entry_shaded(menu, TOOLBAR_BUTTONS,
|
|
ro_toolbar_menu_option_shade(toolbar) ||
|
|
toolbar->buttons == NULL);
|
|
ro_gui_menu_set_entry_ticked(menu, TOOLBAR_BUTTONS,
|
|
ro_toolbar_menu_buttons_tick(toolbar) &&
|
|
toolbar->buttons != NULL);
|
|
|
|
ro_gui_menu_set_entry_shaded(menu, TOOLBAR_ADDRESS_BAR,
|
|
ro_toolbar_menu_edit_shade(toolbar) ||
|
|
toolbar->url == NULL);
|
|
ro_gui_menu_set_entry_ticked(menu, TOOLBAR_ADDRESS_BAR,
|
|
ro_toolbar_menu_url_tick(toolbar) &&
|
|
toolbar->url != NULL);
|
|
|
|
ro_gui_menu_set_entry_shaded(menu, TOOLBAR_THROBBER,
|
|
ro_toolbar_menu_edit_shade(toolbar) ||
|
|
toolbar->throbber == NULL);
|
|
ro_gui_menu_set_entry_ticked(menu, TOOLBAR_THROBBER,
|
|
ro_toolbar_menu_throbber_tick(toolbar) &&
|
|
toolbar->throbber != NULL);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle submenu warnings for the toolbar menu
|
|
*
|
|
* \param w The window owning the menu.
|
|
* \param i The icon owning the menu.
|
|
* \param *menu The menu to which the warning applies.
|
|
* \param *selection The wimp menu selection data.
|
|
* \param action The selected menu action.
|
|
*/
|
|
|
|
void ro_toolbar_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
|
|
wimp_selection *selection, menu_action action)
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle selections from the toolbar menu
|
|
*
|
|
* \param w The window owning the menu.
|
|
* \param i The icon owning the menu.
|
|
* \param *menu The menu from which the selection was made.
|
|
* \param *selection The wimp menu selection data.
|
|
* \param action The selected menu action.
|
|
* \return true if action accepted; else false.
|
|
*/
|
|
|
|
bool ro_toolbar_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
|
|
wimp_selection *selection, menu_action action)
|
|
{
|
|
struct toolbar *toolbar;
|
|
|
|
toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(w);
|
|
|
|
if (toolbar == NULL)
|
|
return false;
|
|
|
|
/* Pass the event on to potentially interested widgets. */
|
|
|
|
if (toolbar->url != NULL && ro_gui_url_bar_menu_select(toolbar->url,
|
|
i, menu, selection, action))
|
|
return true;
|
|
|
|
/* Try to process the event as a toolbar menu. */
|
|
|
|
if (menu != toolbar_menu)
|
|
return false;
|
|
|
|
switch (action) {
|
|
case TOOLBAR_BUTTONS:
|
|
ro_toolbar_set_display_buttons(toolbar,
|
|
!ro_toolbar_get_display_buttons(toolbar));
|
|
break;
|
|
case TOOLBAR_ADDRESS_BAR:
|
|
ro_toolbar_set_display_url(toolbar,
|
|
!ro_toolbar_get_display_url(toolbar));
|
|
if (ro_toolbar_get_display_url(toolbar))
|
|
ro_toolbar_take_caret(toolbar);
|
|
break;
|
|
case TOOLBAR_THROBBER:
|
|
ro_toolbar_set_display_throbber(toolbar,
|
|
!ro_toolbar_get_display_throbber(toolbar));
|
|
break;
|
|
case TOOLBAR_EDIT:
|
|
ro_toolbar_toggle_edit(toolbar);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Translate the contents of a message_HELP_REQUEST into a suffix for a
|
|
* NetSurf message token. The help system will then add this to whatever
|
|
* prefix the current toolbar has registered with WimpEvent.
|
|
*
|
|
* \param w The window handle under the mouse.
|
|
* \param i The icon handle under the mouse.
|
|
* \param *pos The mouse position.
|
|
* \param buttons The mouse button state.
|
|
* \return The required help token suffix.
|
|
*/
|
|
|
|
const char *ro_toolbar_get_help_suffix(wimp_w w, wimp_i i, os_coord *pos,
|
|
wimp_mouse_state buttons)
|
|
{
|
|
struct toolbar *toolbar;
|
|
wimp_window_state state;
|
|
os_error *error;
|
|
const char *suffix;
|
|
|
|
toolbar = (struct toolbar *) ro_gui_wimp_event_get_user_data(w);
|
|
|
|
if (toolbar == NULL || toolbar->toolbar_handle != w)
|
|
return NULL;
|
|
|
|
state.w = toolbar->toolbar_handle;
|
|
error = xwimp_get_window_state(&state);
|
|
if (error) {
|
|
LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
|
|
warn_user("WimpError", error->errmess);
|
|
return NULL;
|
|
}
|
|
|
|
/* Pass the help request around the toolbar widgets. */
|
|
|
|
if (toolbar->throbber != NULL && toolbar->throbber_display &&
|
|
ro_gui_throbber_help_suffix(toolbar->throbber, i,
|
|
pos, &state, buttons, &suffix))
|
|
return suffix;
|
|
|
|
if (toolbar->url != NULL && toolbar->url_display &&
|
|
ro_gui_url_bar_help_suffix(toolbar->url, i,
|
|
pos, &state, buttons, &suffix))
|
|
return suffix;
|
|
|
|
if (toolbar->buttons != NULL && toolbar->buttons_display &&
|
|
ro_gui_button_bar_help_suffix(toolbar->buttons, i,
|
|
pos, &state, buttons, &suffix))
|
|
return suffix;
|
|
|
|
return "";
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_update_client_data(struct toolbar *toolbar, void *client_data)
|
|
{
|
|
if (toolbar != NULL)
|
|
toolbar->client_data = client_data;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_update_all_buttons(void)
|
|
{
|
|
struct toolbar *bar;
|
|
|
|
bar = ro_toolbar_bars;
|
|
while (bar != NULL) {
|
|
ro_toolbar_update_buttons(bar);
|
|
|
|
bar = bar->next;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Update the state of a toolbar's buttons.
|
|
*
|
|
* \param toolbar the toolbar to update
|
|
*/
|
|
|
|
void ro_toolbar_update_buttons(struct toolbar *toolbar)
|
|
{
|
|
assert(toolbar != NULL);
|
|
|
|
if (toolbar->callbacks != NULL &&
|
|
toolbar->callbacks->update_buttons != NULL)
|
|
toolbar->callbacks->update_buttons(toolbar->client_data);
|
|
}
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_refresh(struct toolbar *toolbar)
|
|
{
|
|
assert(toolbar != NULL);
|
|
|
|
ro_toolbar_process(toolbar, -1, true);
|
|
if (toolbar->callbacks != NULL &&
|
|
toolbar->callbacks->change_size != NULL)
|
|
toolbar->callbacks->change_size(toolbar->client_data);
|
|
|
|
if (toolbar->toolbar_handle != NULL)
|
|
xwimp_force_redraw(toolbar->toolbar_handle, 0, 0,
|
|
toolbar->current_width,
|
|
toolbar->current_height);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_theme_update(void)
|
|
{
|
|
struct toolbar *bar, *next;
|
|
bool ok;
|
|
|
|
bar = ro_toolbar_bars;
|
|
while (bar != NULL) {
|
|
/* Take the next bar address now, as *bar may become invalid
|
|
* during the update process (if an update fails and
|
|
* ro_toolbar_destroy() is called) and we don't want to lose
|
|
* the link to the rest of the chain.
|
|
*/
|
|
|
|
next = bar->next;
|
|
|
|
/* Only process the bar if the theme is set to the default.
|
|
* Otherwise, it's up to the owner to do whatever they need
|
|
* to do for themselves.
|
|
*/
|
|
|
|
if (bar->theme == NULL) {
|
|
ok = ro_toolbar_rebuild(bar);
|
|
|
|
if (!ok)
|
|
ro_toolbar_destroy(bar);
|
|
} else {
|
|
ok = true;
|
|
}
|
|
|
|
if (bar->callbacks != NULL &&
|
|
bar->callbacks->theme_update != NULL)
|
|
bar->callbacks->theme_update(bar->client_data, ok);
|
|
|
|
bar = next;
|
|
}
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
struct toolbar *ro_toolbar_parent_window_lookup(wimp_w w)
|
|
{
|
|
struct toolbar *toolbar;
|
|
|
|
toolbar = ro_toolbar_bars;
|
|
while (toolbar != NULL && toolbar->parent_handle != w)
|
|
toolbar = toolbar->next;
|
|
|
|
return toolbar;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
struct toolbar *ro_toolbar_window_lookup(wimp_w w)
|
|
{
|
|
struct toolbar *toolbar;
|
|
|
|
toolbar = ro_toolbar_bars;
|
|
while (toolbar != NULL && toolbar->toolbar_handle != w)
|
|
toolbar = toolbar->next;
|
|
|
|
return toolbar;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
wimp_w ro_toolbar_get_parent_window(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar != NULL) ? toolbar->parent_handle : 0;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
wimp_w ro_toolbar_get_window(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar != NULL) ? toolbar->toolbar_handle : 0;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
int ro_toolbar_height(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar == NULL) ? 0 : toolbar->current_height;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
int ro_toolbar_full_height(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar == NULL) ? 0 : toolbar->full_height;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_start_throbbing(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar != NULL && toolbar->throbber != NULL)
|
|
ro_gui_throbber_animate(toolbar->throbber);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_stop_throbbing(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar != NULL && toolbar->throbber != NULL)
|
|
ro_gui_throbber_stop(toolbar->throbber);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_throb(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar != NULL && toolbar->throbber != NULL)
|
|
ro_gui_throbber_animate(toolbar->throbber);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_set_button_order(struct toolbar *toolbar, char order[])
|
|
{
|
|
if (toolbar == NULL || toolbar->buttons == NULL)
|
|
return false;
|
|
|
|
if (!ro_gui_button_bar_arrange_buttons(toolbar->buttons, order))
|
|
return false;
|
|
|
|
ro_toolbar_refresh_widget_dimensions(toolbar);
|
|
|
|
return ro_toolbar_process(toolbar, -1, true);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_set_button_shaded_state(struct toolbar *toolbar,
|
|
button_bar_action action, bool shaded)
|
|
{
|
|
if (toolbar == NULL || toolbar->buttons == NULL)
|
|
return;
|
|
|
|
ro_gui_button_bar_shade_button(toolbar->buttons, action, shaded);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_take_caret(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL || !toolbar->url_display)
|
|
return false;
|
|
|
|
return ro_gui_url_bar_take_caret(toolbar->url);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_set_url(struct toolbar *toolbar, const char *url,
|
|
bool is_utf8, bool set_caret)
|
|
{
|
|
if (toolbar != NULL && toolbar->url != NULL)
|
|
ro_gui_url_bar_set_url(toolbar->url, url, is_utf8, set_caret);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
const char *ro_toolbar_get_url(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL)
|
|
return NULL;
|
|
|
|
return ro_gui_url_bar_get_url(toolbar->url);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_update_all_hotlists(void)
|
|
{
|
|
struct toolbar *bar;
|
|
|
|
bar = ro_toolbar_bars;
|
|
while (bar != NULL) {
|
|
ro_toolbar_update_hotlist(bar);
|
|
|
|
bar = bar->next;
|
|
}
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_update_hotlist(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL)
|
|
return;
|
|
|
|
ro_gui_url_bar_update_hotlist(toolbar->url);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_get_url_field_extent(struct toolbar *toolbar, os_box *extent)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL)
|
|
return false;
|
|
|
|
if (extent == NULL)
|
|
return true;
|
|
|
|
return ro_gui_url_bar_get_url_extent(toolbar->url, extent);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_set_site_favicon(struct toolbar *toolbar,
|
|
struct hlcache_handle *h)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL)
|
|
return;
|
|
|
|
ro_gui_url_bar_set_site_favicon(toolbar->url, h);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_set_content_favicon(struct toolbar *toolbar,
|
|
struct gui_window *g)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL)
|
|
return;
|
|
|
|
ro_gui_url_bar_set_content_favicon(toolbar->url, g);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_update_urlsuggest(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL)
|
|
return;
|
|
|
|
ro_gui_url_bar_update_urlsuggest(toolbar->url);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_set_display_buttons(struct toolbar *toolbar, bool display)
|
|
{
|
|
if (toolbar == NULL || toolbar->buttons == NULL)
|
|
return;
|
|
|
|
toolbar->buttons_display = display;
|
|
ro_gui_button_bar_hide(toolbar->buttons, !display);
|
|
ro_toolbar_refresh_widget_dimensions(toolbar);
|
|
ro_toolbar_refresh(toolbar);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_set_display_url(struct toolbar *toolbar, bool display)
|
|
{
|
|
if (toolbar == NULL || toolbar->url == NULL)
|
|
return;
|
|
|
|
toolbar->url_display = display;
|
|
ro_gui_url_bar_hide(toolbar->url, !display);
|
|
ro_toolbar_refresh_widget_dimensions(toolbar);
|
|
ro_toolbar_refresh(toolbar);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
void ro_toolbar_set_display_throbber(struct toolbar *toolbar, bool display)
|
|
{
|
|
if (toolbar == NULL || toolbar->throbber == NULL)
|
|
return;
|
|
|
|
toolbar->throbber_display = display;
|
|
ro_gui_throbber_hide(toolbar->throbber, !display);
|
|
ro_toolbar_refresh_widget_dimensions(toolbar);
|
|
ro_toolbar_refresh(toolbar);
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_get_display_buttons(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar == NULL || toolbar->buttons == NULL) ?
|
|
false : toolbar->buttons_display;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_get_display_url(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar == NULL || toolbar->url == NULL) ?
|
|
false : toolbar->url_display;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_get_display_throbber(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar == NULL || toolbar->throbber == NULL) ?
|
|
false : toolbar->throbber_display;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_get_editing(struct toolbar *toolbar)
|
|
{
|
|
return (toolbar == NULL || !toolbar->editing) ? false : true;
|
|
}
|
|
|
|
|
|
/* This is an exported interface documented in toolbar.h */
|
|
|
|
bool ro_toolbar_toggle_edit(struct toolbar *toolbar)
|
|
{
|
|
if (toolbar == NULL || toolbar->editor == NULL)
|
|
return false;
|
|
|
|
toolbar->editing = !toolbar->editing;
|
|
|
|
ro_gui_button_bar_hide(toolbar->editor, !toolbar->editing);
|
|
ro_gui_button_bar_hide(toolbar->buttons,
|
|
!toolbar->buttons_display && !toolbar->editing);
|
|
|
|
if (!ro_toolbar_rebuild(toolbar)) {
|
|
ro_toolbar_destroy(toolbar);
|
|
return false;
|
|
}
|
|
|
|
ro_toolbar_refresh(toolbar);
|
|
|
|
/* If there's a callback registered and an edit has finished,
|
|
* tell out client what the new button state is.
|
|
*/
|
|
|
|
if (!toolbar->editing && toolbar->buttons != NULL &&
|
|
toolbar->callbacks != NULL &&
|
|
toolbar->callbacks->save_buttons != NULL) {
|
|
char *new_buttons;
|
|
new_buttons = ro_gui_button_bar_get_config(toolbar->buttons);
|
|
toolbar->callbacks->save_buttons(toolbar->client_data,
|
|
new_buttons);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|