/* * Copyright 2016 Vincent Sanders * * 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 . */ /** * \file * RISC OS generic core window implementation. * * Provides interface for core renderers to a risc os drawing area. * * This module is an object that must be encapsulated. Client users * should embed a struct ro_corewindow at the beginning of their * context for this display surface, fill in relevant data and then * call ro_corewindow_init() * * The ro core window structure requires the callback for draw, key * and mouse operations. */ #include #include #include "utils/log.h" #include "netsurf/types.h" #include "netsurf/mouse.h" #include "netsurf/keypress.h" #include "riscos/wimp_event.h" #include "riscos/dialog.h" #include "riscos/gui.h" #include "riscos/toolbar.h" #include "riscos/mouse.h" #include "riscos/corewindow.h" #ifndef wimp_KEY_END #define wimp_KEY_END wimp_KEY_COPY #endif /** * Update a windows scrollbars. * * in the wimp this is done by setting the extent and calling window open */ static void update_scrollbars(struct ro_corewindow *ro_cw, wimp_open *open) { os_error *error; int extent_width; int extent_height; os_box extent; LOG("RO corewindow context %p", ro_cw); /* extent of content in not smaller than window so start there */ extent_width = open->visible.x1 - open->visible.x0; extent_height = open->visible.y0 - open->visible.y1; LOG("extent w:%d h:%d content w:%d h:%d origin h:%d", extent_width, extent_height, ro_cw->content_width, ro_cw->content_height, ro_cw->origin_y); if (ro_cw->content_width > extent_width) { extent_width = ro_cw->content_width; } if (extent_height > (ro_cw->origin_y + ro_cw->content_height)) { extent_height = ro_cw->origin_y + ro_cw->content_height; } LOG("extent w:%d h:%d", extent_width, extent_height); extent.x0 = 0; extent.y0 = extent_height; extent.x1 = extent_width; extent.y1 = 0; error = xwimp_set_extent(ro_cw->wh, &extent); if (error) { LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess); return; } error = xwimp_open_window(open); if (error) { LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); } } /** * wimp callback on redraw event */ static void ro_cw_redraw(wimp_draw *redraw) { struct ro_corewindow *ro_cw; osbool more; os_error *error; struct rect r; int origin_x; int origin_y; ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(redraw->w); error = xwimp_redraw_window(redraw, &more); while ((error == NULL) && (more)) { /* compute rectangle to redraw */ origin_x = redraw->box.x0 - redraw->xscroll; origin_y = redraw->box.y1 + ro_cw->origin_y - redraw->yscroll; r.x0 = (redraw->clip.x0 - origin_x) / 2; r.y0 = (origin_y - redraw->clip.y1) / 2; r.x1 = r.x0 + ((redraw->clip.x1 - redraw->clip.x0) / 2); r.y1 = r.y0 + ((redraw->clip.y1 - redraw->clip.y0) / 2); /* call the draw callback */ ro_cw->draw(ro_cw, origin_x, origin_y, &r); error = xwimp_get_rectangle(redraw, &more); } if (error != NULL) { LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess); } } static void ro_cw_scroll(wimp_scroll *scroll) { os_error *error; int page_x; int page_y; struct ro_corewindow *ro_cw; wimp_open open; ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(scroll->w); LOG("RO corewindow context %p", ro_cw); page_x = scroll->visible.x1 - scroll->visible.x0 - 32; page_y = scroll->visible.y1 - scroll->visible.y0 - 32; page_y += ro_cw->origin_y; open.w = scroll->w; open.visible = scroll->visible; open.next = scroll->next; switch (scroll->xmin) { case wimp_SCROLL_PAGE_LEFT: open.xscroll = scroll->xscroll - page_x; break; case wimp_SCROLL_COLUMN_LEFT: open.xscroll = scroll->xscroll - 32; break; case wimp_SCROLL_COLUMN_RIGHT: open.xscroll = scroll->xscroll + 32; break; case wimp_SCROLL_PAGE_RIGHT: open.xscroll = scroll->xscroll + page_x; break; default: open.xscroll = scroll->xscroll + ((page_x * (scroll->xmin>>2)) >> 2); break; } switch (scroll->ymin) { case wimp_SCROLL_PAGE_UP: open.yscroll = scroll->yscroll + page_y; break; case wimp_SCROLL_LINE_UP: open.yscroll = scroll->yscroll + 32; break; case wimp_SCROLL_LINE_DOWN: open.yscroll = scroll->yscroll - 32; break; case wimp_SCROLL_PAGE_DOWN: open.yscroll = scroll->yscroll - page_y; break; default: open.yscroll = scroll->yscroll + ((page_y * (scroll->ymin>>2)) >> 2); break; } error = xwimp_open_window(&open); if (error) { LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); } } /** * Track the mouse under Null Polls from the wimp, to support dragging. * * \param pointer Pointer to a Wimp Pointer block. * \param data NULL to allow use as a ro_mouse callback. */ static void ro_cw_mouse_at(wimp_pointer *pointer, void *data) { os_error *error; struct ro_corewindow *ro_cw; wimp_window_state state; int xpos, ypos; browser_mouse_state mouse; /* ignore menu clicks */ if (pointer->buttons & (wimp_CLICK_MENU)) { return; } ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(pointer->w); if (ro_cw == NULL) { LOG("no corewindow conext for window: 0x%x", (unsigned int)pointer->w); return; } LOG("RO corewindow context %p", ro_cw); /* Not a Menu click. */ state.w = pointer->w; error = xwimp_get_window_state(&state); if (error) { LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); return; } /* Convert the returned mouse coordinates into * NetSurf's internal units. */ xpos = ((pointer->pos.x - state.visible.x0) + state.xscroll) / 2; ypos = ((state.visible.y1 - pointer->pos.y) - state.yscroll + ro_cw->origin_y) / 2; /* if no drag in progress report hover */ if (ro_cw->drag_status == CORE_WINDOW_DRAG_NONE) { mouse = BROWSER_MOUSE_HOVER; } else { /* Start to process the mouse click. */ mouse = ro_gui_mouse_drag_state(pointer->buttons, wimp_BUTTON_DOUBLE_CLICK_DRAG); ro_cw->mouse(ro_cw, mouse, xpos, ypos); } if (!(mouse & BROWSER_MOUSE_DRAG_ON)) { ro_cw->mouse(ro_cw, BROWSER_MOUSE_HOVER, xpos, ypos); ro_cw->drag_status = CORE_WINDOW_DRAG_NONE; } ro_cw->toolbar_update(ro_cw); } /** * Process RISC OS User Drag Box events which relate to us: in effect, drags * started by ro_cw_drag_start(). * * \param drag Pointer to the User Drag Box Event block. * \param data NULL to allow use as a ro_mouse callback. */ static void ro_cw_drag_end(wimp_dragged *drag, void *data) { os_error *error; error = xwimp_drag_box((wimp_drag *) -1); if (error) { LOG("xwimp_drag_box: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); } error = xwimp_auto_scroll(0, NULL, NULL); if (error) { LOG("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); } } /** * Start a RISC OS drag event to reflect on screen what is happening * during the core tree drag. * * \param ro_cw The RO corewindow to which the drag is attached. * \param pointer The RO pointer event data block starting the drag. * \param state The RO window state block for the treeview window. */ static void ro_cw_drag_start(struct ro_corewindow *ro_cw, wimp_pointer *pointer, wimp_window_state *state) { os_error *error; wimp_drag drag; wimp_auto_scroll_info auto_scroll; drag.w = ro_cw->wh; drag.bbox.x0 = state->visible.x0; drag.bbox.y0 = state->visible.y0; drag.bbox.x1 = state->visible.x1; drag.bbox.y1 = state->visible.y1 - ro_toolbar_height(ro_cw->toolbar) - 2; switch (ro_cw->drag_status) { case CORE_WINDOW_DRAG_SELECTION: drag.type = wimp_DRAG_USER_RUBBER; drag.initial.x0 = pointer->pos.x; drag.initial.y0 = pointer->pos.y; drag.initial.x1 = pointer->pos.x; drag.initial.y1 = pointer->pos.y; break; case CORE_WINDOW_DRAG_MOVE: drag.type = wimp_DRAG_USER_POINT; drag.initial.x0 = pointer->pos.x - 4; drag.initial.y0 = pointer->pos.y - 48; drag.initial.x1 = pointer->pos.x + 48; drag.initial.y1 = pointer->pos.y + 4; break; default: /* No other drag types are supported. */ break; } LOG("Drag start..."); error = xwimp_drag_box_with_flags(&drag, wimp_DRAG_BOX_KEEP_IN_LINE | wimp_DRAG_BOX_CLIP); if (error) { LOG("xwimp_drag_box: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); } else { auto_scroll.w = ro_cw->wh; auto_scroll.pause_zone_sizes.x0 = 80; auto_scroll.pause_zone_sizes.y0 = 80; auto_scroll.pause_zone_sizes.x1 = 80; auto_scroll.pause_zone_sizes.y1 = 80 + ro_toolbar_height(ro_cw->toolbar); auto_scroll.pause_duration = 0; auto_scroll.state_change = (void *) 1; error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL, &auto_scroll, NULL); if (error) { LOG("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); } ro_mouse_drag_start(ro_cw_drag_end, ro_cw_mouse_at, NULL, NULL); } } /** * Handle Pointer Leaving Window events. * * These events are delivered as the termination callback handler from * ro_mouse's mouse tracking. * * \param leaving The Wimp_PointerLeavingWindow block. * \param data NULL data pointer. */ static void ro_cw_pointer_leaving(wimp_leaving *leaving, void *data) { struct ro_corewindow *ro_cw; ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(leaving->w); if (ro_cw == NULL) { LOG("no corewindow conext for window: 0x%x", (unsigned int)leaving->w); return; } ro_cw->mouse(ro_cw, BROWSER_MOUSE_LEAVE, 0, 0); } /** * Wimp callback on pointer entering window. * * The wimp has issued an event to the window because the pointer has * entered it. * * \param entering The entering event to be processed */ static void ro_cw_pointer_entering(wimp_entering *entering) { ro_mouse_track_start(ro_cw_pointer_leaving, ro_cw_mouse_at, NULL); } /** * Wimp callback on window open event. * * The wimp has issued an event to the window because an attempt has * been made to open or resize it. This requires the new dimensions to * be calculated and set within the wimp. * * \param open The open event to be processed */ static void ro_cw_open(wimp_open *open) { struct ro_corewindow *ro_cw; ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(open->w); update_scrollbars(ro_cw, open); } static bool ro_cw_mouse_click(wimp_pointer *pointer) { os_error *error; wimp_window_state state; int xpos, ypos; browser_mouse_state mouse = 0; bool handled = false; struct ro_corewindow *ro_cw; ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(pointer->w); LOG("RO corewindow context %p", ro_cw); state.w = ro_cw->wh; error = xwimp_get_window_state(&state); if (error) { LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); return false; } /* Convert the returned mouse coordinates into NetSurf's internal * units. */ xpos = ((pointer->pos.x - state.visible.x0) + state.xscroll) / 2; ypos = ((state.visible.y1 - pointer->pos.y) - state.yscroll + ro_cw->origin_y) / 2; if (pointer->buttons != wimp_CLICK_MENU) { mouse = ro_gui_mouse_click_state(pointer->buttons, wimp_BUTTON_DOUBLE_CLICK_DRAG); /* Give the window input focus on Select-clicks. This wouldn't * be necessary if the core used the RISC OS caret. */ if (mouse & BROWSER_MOUSE_CLICK_1) { xwimp_set_caret_position(ro_cw->wh, -1, -100, -100, 32, -1); } } /* call the mouse callback */ if (mouse != 0) { ro_cw->mouse(ro_cw, mouse, xpos, ypos); /* If it's a visible drag, start the RO side of the visible * effects. */ if ((ro_cw->drag_status == CORE_WINDOW_DRAG_SELECTION) || (ro_cw->drag_status == CORE_WINDOW_DRAG_MOVE)) { ro_cw_drag_start(ro_cw, pointer, &state); } ro_cw->toolbar_update(ro_cw); } /* Special actions for some mouse buttons. Adjust closes the dialog; * Menu opens a menu. For the latter, we assume that the owning module * will have attached a window menu to our parent window with the auto * flag unset (so that we can fudge the selection above). If it hasn't, * the call will quietly fail. * * \TODO -- Adjust-click close isn't a perfect copy of what the RO * version did: adjust clicks anywhere close the tree, and * selections persist. */ switch(pointer->buttons) { case wimp_CLICK_ADJUST: if (handled) { ro_gui_dialog_close(ro_cw->wh); } break; case wimp_CLICK_MENU: ro_gui_wimp_event_process_window_menu_click(pointer); break; } return true; } static bool ro_cw_keypress(wimp_key *key) { uint32_t c; struct ro_corewindow *ro_cw; nserror res; ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(key->w); LOG("RO corewindow context %p", ro_cw); c = (uint32_t) key->c; if ((unsigned)c < 0x20 || (0x7f <= c && c <= 0x9f) || (c & IS_WIMP_KEY)) { /* Munge control keys into unused control chars */ /* We can't map onto 1->26 (reserved for ctrl+ That leaves 27->31 and 128->159 */ switch (c & ~IS_WIMP_KEY) { case wimp_KEY_TAB: c = 9; break; case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break; /* cursor movement keys */ case wimp_KEY_HOME: case wimp_KEY_CONTROL | wimp_KEY_LEFT: c = NS_KEY_LINE_START; break; case wimp_KEY_END: if (os_version >= RISCOS5) c = NS_KEY_LINE_END; else c = NS_KEY_DELETE_RIGHT; break; case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = NS_KEY_LINE_END; break; case wimp_KEY_CONTROL | wimp_KEY_UP: c = NS_KEY_TEXT_START; break; case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = NS_KEY_TEXT_END; break; case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = NS_KEY_WORD_LEFT; break; case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = NS_KEY_WORD_RIGHT; break; case wimp_KEY_SHIFT | wimp_KEY_UP: c = NS_KEY_PAGE_UP; break; case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = NS_KEY_PAGE_DOWN; break; case wimp_KEY_LEFT: c = NS_KEY_LEFT; break; case wimp_KEY_RIGHT: c = NS_KEY_RIGHT; break; case wimp_KEY_UP: c = NS_KEY_UP; break; case wimp_KEY_DOWN: c = NS_KEY_DOWN; break; /* editing */ case wimp_KEY_CONTROL | wimp_KEY_END: c = NS_KEY_DELETE_LINE_END; break; case wimp_KEY_DELETE: if (ro_gui_ctrl_pressed()) c = NS_KEY_DELETE_LINE_START; else if (os_version < RISCOS5) c = NS_KEY_DELETE_LEFT; break; default: break; } } if (!(c & IS_WIMP_KEY)) { res = ro_cw->key(ro_cw, c); if (res == NSERROR_OK) { ro_cw->toolbar_update(ro_cw); return true; } } return false; } /** * Update a corewindow toolbar to a new size. * * \param ctx Context as passed to toolbar creation. */ static void cw_tb_size(void *ctx) { struct ro_corewindow *ro_cw; wimp_window_state state; os_error *error; ro_cw = (struct ro_corewindow *)ctx; ro_cw->origin_y = -(ro_toolbar_height(ro_cw->toolbar)); state.w = ro_cw->wh; error = xwimp_get_window_state(&state); if (error) { LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); return; } error = xwimp_force_redraw(ro_cw->wh, 0, state.visible.y0 - state.visible.y1, state.visible.x1 - state.visible.x0, 0); if (error) { LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess); return; } } /** * Update a corewindow toolbar to use a new theme. * * \param ctx Context as passed to toolbar creation. * \param exists true if the bar still exists; else false. */ static void cw_tb_theme(void *ctx, bool exists) { if (exists) { cw_tb_size(ctx); } } /** * Allow a corewindow toolbar button state to be updated. * * \param ctx Context as passed to toolbar creation. */ static void cw_tb_update(void *ctx) { struct ro_corewindow *ro_cw; ro_cw = (struct ro_corewindow *)ctx; ro_cw->toolbar_update(ro_cw); } /** * Respond to user actions (click) in a corewindow. * * \param ctx Context as passed to toolbar creation. * \param action_type type of action on toolbar * \param action data for action. */ static void cw_tb_click(void *ctx, toolbar_action_type action_type, union toolbar_action action) { struct ro_corewindow *ro_cw; ro_cw = (struct ro_corewindow *)ctx; if (action_type == TOOLBAR_ACTION_BUTTON) { ro_cw->toolbar_click(ro_cw, action.button); ro_cw->toolbar_update(ro_cw); } } /** * Save positions of core window toolbar buttons. * * \param ctx Context as passed to toolbar creation. * \param config The new button config string. */ static void cw_tb_save(void *ctx, char *config) { struct ro_corewindow *ro_cw; ro_cw = (struct ro_corewindow *)ctx; ro_cw->toolbar_save(ro_cw, config); } /** * riscos core window toolbar callbacks */ static const struct toolbar_callbacks corewindow_toolbar_callbacks = { .theme_update = cw_tb_theme, .change_size = cw_tb_size, .update_buttons = cw_tb_update, .user_action = cw_tb_click, .save_buttons = cw_tb_save, }; /** * callback from core to request an invalidation of a window area. * * The specified area of the window should now be considered * out of date. If the area is NULL the entire window must be * invalidated. * * \param[in] cw The core window to invalidate. * \param[in] r area to redraw or NULL for the entire window area. * \return NSERROR_OK on success or appropriate error code. */ static nserror ro_cw_invalidate(struct core_window *cw, const struct rect *r) { struct ro_corewindow *ro_cw = (struct ro_corewindow *)cw; os_error *error; wimp_window_info info; if (r == NULL) { info.w = ro_cw->wh; error = xwimp_get_window_info_header_only(&info); if (error) { LOG("xwimp_get_window_info_header_only: 0x%x: %s", error->errnum, error->errmess); return NSERROR_INVALID; } } else { /* convert the passed rectangle into RO window dimensions */ info.extent.x0 = 2 * r->x0; info.extent.y0 = (-2 * (r->y0 + (r->y1 - r->y0))) + ro_cw->origin_y; info.extent.x1 = 2 * (r->x0 + (r->x1 - r->x0)); info.extent.y1 = (-2 * r->y0) + ro_cw->origin_y; } error = xwimp_force_redraw(ro_cw->wh, info.extent.x0, info.extent.y0, info.extent.x1, info.extent.y1); if (error) { LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess); return NSERROR_INVALID; } return NSERROR_OK; } /** * Callback from the core to update the content area size. */ static void ro_cw_update_size(struct core_window *cw, int width, int height) { struct ro_corewindow *ro_cw = (struct ro_corewindow *)cw; wimp_open open; wimp_window_state state; os_error *error; LOG("content resize from w:%d h:%d to w:%d h:%d", ro_cw->content_width, ro_cw->content_height, width, height); ro_cw->content_width = width * 2; ro_cw->content_height = -(2 * height); state.w = ro_cw->wh; error = xwimp_get_window_state(&state); if (error) { LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); return; } /* only update the window if it is open */ if (state.flags & wimp_WINDOW_OPEN) { open.w = ro_cw->wh; open.visible = state.visible; open.xscroll = state.xscroll; open.yscroll = state.yscroll; open.next = state.next; update_scrollbars(ro_cw, &open); } } /** * Callback from the core to scroll the visible content. */ static void ro_cw_scroll_visible(struct core_window *cw, const struct rect *r) { //struct ro_corewindow *ro_cw = (struct ro_corewindow *)cw; } /** * Callback from the core to obtain the window viewport dimensions * * \param[in] cw the core window object * \param[out] width to be set to viewport width in px * \param[out] height to be set to viewport height in px */ static void ro_cw_get_window_dimensions(struct core_window *cw, int *width, int *height) { struct ro_corewindow *ro_cw = (struct ro_corewindow *)cw; os_error *error; wimp_window_state state; state.w = ro_cw->wh; error = xwimp_get_window_state(&state); if (error) { LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); return; } *width = (state.visible.x1 - state.visible.x0) / 2; *height = (state.visible.y1 - state.visible.y0) / 2; } /** * Callback from the core to update the drag status. */ static void ro_cw_drag_status(struct core_window *cw, core_window_drag_status ds) { struct ro_corewindow *ro_cw = (struct ro_corewindow *)cw; ro_cw->drag_status = ds; } struct core_window_callback_table ro_cw_cb_table = { .invalidate = ro_cw_invalidate, .update_size = ro_cw_update_size, .scroll_visible = ro_cw_scroll_visible, .get_window_dimensions = ro_cw_get_window_dimensions, .drag_status = ro_cw_drag_status }; /** * dummy toolbar click callback * */ static nserror dummy_toolbar_click(struct ro_corewindow *ro_cw, button_bar_action action) { return NSERROR_OK; } /** * dummy toolbar update callback */ static nserror dummy_toolbar_update(struct ro_corewindow *ro_cw) { return NSERROR_OK; } /** * dummy toolbar save callback */ static nserror dummy_toolbar_save(struct ro_corewindow *ro_cw, char *config) { return NSERROR_OK; } /* exported function documented ro/corewindow.h */ nserror ro_corewindow_init(struct ro_corewindow *ro_cw, const struct button_bar_buttons *tb_buttons, char *tb_order, theme_style tb_style, const char *tb_help) { /* setup the core window callback table */ ro_cw->cb_table = &ro_cw_cb_table; /* start with the content area being as small as possible */ ro_cw->content_width = -1; ro_cw->content_height = -1; ro_cw->origin_y = 0; /* no offset */ ro_cw->drag_status = CORE_WINDOW_DRAG_NONE; /* no drag */ /* Create toolbar. */ if (tb_buttons != NULL) { /* ensure toolbar callbacks are always valid so calls * do not have to be conditional */ if (ro_cw->toolbar_click == NULL) { ro_cw->toolbar_click = dummy_toolbar_click; } if (ro_cw->toolbar_save == NULL) { ro_cw->toolbar_save = dummy_toolbar_save; } if (ro_cw->toolbar_update == NULL) { ro_cw->toolbar_update = dummy_toolbar_update; } ro_cw->toolbar = ro_toolbar_create(NULL, ro_cw->wh, tb_style, TOOLBAR_FLAGS_NONE, &corewindow_toolbar_callbacks, ro_cw, tb_help); if (ro_cw->toolbar == NULL) { return NSERROR_INIT_FAILED; } ro_toolbar_add_buttons(ro_cw->toolbar, tb_buttons, tb_order); ro_toolbar_rebuild(ro_cw->toolbar); ro_cw->origin_y = -(ro_toolbar_height(ro_cw->toolbar)); } else { ro_cw->toolbar = NULL; /* no toolbar */ /* ensure callback functions are set to defaults when * no toolbar */ ro_cw->toolbar_click = dummy_toolbar_click; ro_cw->toolbar_save = dummy_toolbar_save; ro_cw->toolbar_update = dummy_toolbar_update; } /* setup context for event handlers */ ro_gui_wimp_event_set_user_data(ro_cw->wh, ro_cw); /* register wimp events. */ ro_gui_wimp_event_register_redraw_window(ro_cw->wh, ro_cw_redraw); ro_gui_wimp_event_register_scroll_window(ro_cw->wh, ro_cw_scroll); ro_gui_wimp_event_register_pointer_entering_window(ro_cw->wh, ro_cw_pointer_entering); ro_gui_wimp_event_register_open_window(ro_cw->wh, ro_cw_open); ro_gui_wimp_event_register_mouse_click(ro_cw->wh, ro_cw_mouse_click); ro_gui_wimp_event_register_keypress(ro_cw->wh, ro_cw_keypress); return NSERROR_OK; } /* exported interface documented in ro/corewindow.h */ nserror ro_corewindow_fini(struct ro_corewindow *ro_cw) { ro_gui_wimp_event_finalise(ro_cw->wh); /** \todo need to consider freeing of toolbar */ return NSERROR_OK; }