/peek-build/src/netsurf/riscos/window.c
C | 3468 lines | 2449 code | 479 blank | 540 comment | 481 complexity | fc8bb1d57c292c3e32af2212245e1337 MD5 | raw file
1/* 2 * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net> 3 * Copyright 2004 James Bursa <bursa@users.sourceforge.net> 4 * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk> 5 * Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk> 6 * Copyright 2005 Richard Wilson <info@tinct.net> 7 * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net> 8 * 9 * This file is part of NetSurf, http://www.netsurf-browser.org/ 10 * 11 * NetSurf is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; version 2 of the License. 14 * 15 * NetSurf is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program. If not, see <http://www.gnu.org/licenses/>. 22 */ 23 24/** \file 25 * Browser window handling (implementation). 26 */ 27 28#include <assert.h> 29#include <ctype.h> 30#include <inttypes.h> 31#include <math.h> 32#include <stdio.h> 33#include <stdbool.h> 34#include <time.h> 35#include <string.h> 36#include "oslib/colourtrans.h" 37#include "oslib/osbyte.h" 38#include "oslib/osfile.h" 39#include "oslib/osspriteop.h" 40#include "oslib/wimp.h" 41#include "oslib/wimpspriteop.h" 42#include "utils/config.h" 43#include "content/content.h" 44#include "content/hlcache.h" 45#include "content/urldb.h" 46#include "css/css.h" 47#include "desktop/browser.h" 48#include "desktop/frames.h" 49#include "desktop/mouse.h" 50#include "desktop/plotters.h" 51#include "desktop/textinput.h" 52#include "desktop/tree.h" 53#include "desktop/gui.h" 54#include "render/box.h" 55#include "render/form.h" 56#include "riscos/bitmap.h" 57#include "riscos/buffer.h" 58#include "riscos/dialog.h" 59#include "riscos/global_history.h" 60#include "riscos/gui.h" 61#include "riscos/gui/status_bar.h" 62#include "riscos/menus.h" 63#include "riscos/options.h" 64#include "riscos/oslib_pre7.h" 65#include "riscos/save.h" 66#include "riscos/sprite.h" 67#include "riscos/theme.h" 68#include "riscos/thumbnail.h" 69#include "riscos/url_complete.h" 70#include "riscos/wimp.h" 71#include "riscos/wimp_event.h" 72#include "riscos/wimputils.h" 73#include "utils/log.h" 74#include "utils/talloc.h" 75#include "utils/url.h" 76#include "utils/utf8.h" 77#include "utils/utils.h" 78#include "utils/messages.h" 79 80#ifndef wimp_KEY_END 81#define wimp_KEY_END wimp_KEY_COPY 82#endif 83 84#ifndef wimp_WINDOW_GIVE_SHADED_ICON_INFO 85 /* RISC OS 5+. Requires OSLib trunk. */ 86#define wimp_WINDOW_GIVE_SHADED_ICON_INFO ((wimp_extra_window_flags) 0x10u) 87#endif 88 89#define SCROLL_VISIBLE_PADDING 32 90 91/** Remembers which iconised sprite numbers are in use */ 92static bool iconise_used[64]; 93static int iconise_next = 0; 94 95/** Whether a pressed mouse button has become a drag */ 96static bool mouse_drag; 97 98/** List of all browser windows. */ 99static struct gui_window *window_list = 0; 100/** GUI window which is being redrawn. Valid only during redraw. */ 101struct gui_window *ro_gui_current_redraw_gui; 102 103static float scale_snap_to[] = {0.10, 0.125, 0.25, 0.333, 0.5, 0.75, 104 1.0, 105 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 12.0, 16.0}; 106#define SCALE_SNAP_TO_SIZE (sizeof scale_snap_to) / (sizeof(float)) 107 108 109 110/** An entry in ro_gui_pointer_table. */ 111struct ro_gui_pointer_entry { 112 bool wimp_area; /** The pointer is in the Wimp's sprite area. */ 113 char sprite_name[16]; 114 int xactive; 115 int yactive; 116}; 117 118/** Map from gui_pointer_shape to pointer sprite data. Must be ordered as 119 * enum gui_pointer_shape. */ 120struct ro_gui_pointer_entry ro_gui_pointer_table[] = { 121 { true, "ptr_default", 0, 0 }, 122 { false, "ptr_point", 6, 0 }, 123 { false, "ptr_caret", 4, 9 }, 124 { false, "ptr_menu", 6, 4 }, 125 { false, "ptr_ud", 6, 7 }, 126 { false, "ptr_ud", 6, 7 }, 127 { false, "ptr_lr", 7, 6 }, 128 { false, "ptr_lr", 7, 6 }, 129 { false, "ptr_ld", 7, 7 }, 130 { false, "ptr_ld", 7, 7 }, 131 { false, "ptr_rd", 7, 7 }, 132 { false, "ptr_rd", 6, 7 }, 133 { false, "ptr_cross", 7, 7 }, 134 { false, "ptr_move", 8, 0 }, 135 { false, "ptr_wait", 7, 10 }, 136 { false, "ptr_help", 0, 0 }, 137 { false, "ptr_nodrop", 0, 0 }, 138 { false, "ptr_nt_allwd", 10, 10 }, 139 { false, "ptr_progress", 0, 0 }, 140}; 141 142 143static void ro_gui_window_remove_update_boxes(struct gui_window *g); 144static void gui_window_set_extent(struct gui_window *g, int width, int height); 145static void ro_gui_window_open(wimp_open *open); 146static void ro_gui_window_close(wimp_w w); 147static void ro_gui_window_redraw(wimp_draw *redraw); 148static bool ro_gui_window_click(wimp_pointer *mouse); 149static bool ro_gui_window_keypress(wimp_key *key); 150static void ro_gui_window_launch_url(struct gui_window *g, const char *url); 151static void ro_gui_window_clone_options(struct browser_window *new_bw, 152 struct browser_window *old_bw); 153static browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons); 154static bool ro_gui_window_import_text(struct gui_window *g, 155 const char *filename, bool toolbar); 156 157struct update_box { 158 int x0; 159 int y0; 160 int x1; 161 int y1; 162 bool use_buffer; 163 struct gui_window *g; 164 union content_msg_data data; 165 struct update_box *next; 166}; 167 168struct update_box *pending_updates; 169#define MARGIN 4 170 171 172/** 173 * Create and open a new browser window. 174 * 175 * \param bw browser_window structure to update 176 * \param clone the browser window to clone options from, or NULL for default 177 * \return gui_window, or 0 on error and error reported 178 */ 179 180struct gui_window *gui_create_browser_window(struct browser_window *bw, 181 struct browser_window *clone, bool new_tab) 182{ 183 int screen_width, screen_height, win_width, win_height, scroll_width; 184 static int window_count = 2; 185 wimp_window window; 186 wimp_window_state state; 187 os_error *error; 188 bool open_centred = true; 189 struct gui_window *g; 190 struct browser_window *top; 191 192 g = malloc(sizeof *g); 193 if (!g) { 194 warn_user("NoMemory", 0); 195 return 0; 196 } 197 g->bw = bw; 198 g->toolbar = 0; 199 g->status_bar = 0; 200 g->old_width = 0; 201 g->old_height = 0; 202 g->update_extent = true; 203 strcpy(g->title, "NetSurf"); 204 g->throbber = 0; 205 g->throbtime = 0; 206 g->iconise_icon = -1; 207 208 /* Set the window position */ 209 if (bw->parent) { 210 window.visible.x0 = 0; 211 window.visible.x1 = 64; 212 window.visible.y0 = 0; 213 window.visible.y1 = 64; 214 open_centred = false; 215 } else if (clone && clone->window && option_window_size_clone) { 216 for (top = clone; top->parent; top = top->parent); 217 state.w = top->window->window; 218 error = xwimp_get_window_state(&state); 219 if (error) { 220 LOG(("xwimp_get_window_state: 0x%x: %s", 221 error->errnum, error->errmess)); 222 warn_user("WimpError", error->errmess); 223 } 224 window.visible.x0 = state.visible.x0; 225 window.visible.x1 = state.visible.x1; 226 window.visible.y0 = state.visible.y0 - 48; 227 window.visible.y1 = state.visible.y1 - 48; 228 open_centred = false; 229 } else { 230 ro_gui_screen_size(&screen_width, &screen_height); 231 232 /* Check if we have a preferred position */ 233 if ((option_window_screen_width != 0) && 234 (option_window_screen_height != 0)) { 235 win_width = (option_window_width * screen_width) / 236 option_window_screen_width; 237 win_height = (option_window_height * screen_height) / 238 option_window_screen_height; 239 window.visible.x0 = (option_window_x * screen_width) / 240 option_window_screen_width; 241 window.visible.y0 = (option_window_y * screen_height) / 242 option_window_screen_height; 243 if (option_window_stagger) { 244 window.visible.y0 += 96 - 245 (48 * (window_count % 5)); 246 } 247 open_centred = false; 248 if (win_width < 100) 249 win_width = 100; 250 if (win_height < 100) 251 win_height = 100; 252 } else { 253 254 /* Base how we define the window height/width 255 on the compile time options set */ 256 win_width = screen_width * 3 / 4; 257 if (1600 < win_width) 258 win_width = 1600; 259 win_height = win_width * 3 / 4; 260 261 window.visible.x0 = (screen_width - win_width) / 2; 262 window.visible.y0 = ((screen_height - win_height) / 2) + 263 96 - (48 * (window_count % 5)); 264 } 265 window.visible.x1 = window.visible.x0 + win_width; 266 window.visible.y1 = window.visible.y0 + win_height; 267 } 268 269 /* General flags for a non-movable, non-resizable, no-title bar window */ 270 window.xscroll = 0; 271 window.yscroll = 0; 272 window.next = wimp_TOP; 273 window.flags = wimp_WINDOW_MOVEABLE | 274 wimp_WINDOW_NEW_FORMAT | 275 wimp_WINDOW_VSCROLL | 276 wimp_WINDOW_HSCROLL | 277 wimp_WINDOW_IGNORE_XEXTENT | 278 wimp_WINDOW_IGNORE_YEXTENT | 279 wimp_WINDOW_SCROLL_REPEAT; 280 window.title_fg = wimp_COLOUR_BLACK; 281 window.title_bg = wimp_COLOUR_LIGHT_GREY; 282 window.work_fg = wimp_COLOUR_LIGHT_GREY; 283 window.work_bg = wimp_COLOUR_TRANSPARENT; 284 window.scroll_outer = wimp_COLOUR_DARK_GREY; 285 window.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY; 286 window.highlight_bg = wimp_COLOUR_CREAM; 287 window.extra_flags = wimp_WINDOW_USE_EXTENDED_SCROLL_REQUEST | 288 wimp_WINDOW_GIVE_SHADED_ICON_INFO; 289 window.extent.x0 = 0; 290 window.extent.y0 = -(window.visible.y1 - window.visible.y0); 291 window.extent.x1 = window.visible.x1 - window.visible.x0; 292 window.extent.y1 = 0; 293 window.title_flags = wimp_ICON_TEXT | 294 wimp_ICON_INDIRECTED | 295 wimp_ICON_HCENTRED; 296 window.work_flags = wimp_BUTTON_CLICK_DRAG << 297 wimp_ICON_BUTTON_TYPE_SHIFT; 298 window.sprite_area = wimpspriteop_AREA; 299 window.xmin = 1; 300 window.ymin = 1; 301 window.title_data.indirected_text.text = g->title; 302 window.title_data.indirected_text.validation = (char *) -1; 303 window.title_data.indirected_text.size = 255; 304 window.icon_count = 0; 305 306 /* Add in flags for our window type */ 307 switch (bw->browser_window_type) { 308 case BROWSER_WINDOW_FRAMESET: 309 window.flags &= ~(wimp_WINDOW_VSCROLL | 310 wimp_WINDOW_HSCROLL); 311 window.title_fg = 0xff; 312 break; 313 case BROWSER_WINDOW_IFRAME: 314 window.flags |= wimp_WINDOW_NO_BOUNDS; 315 case BROWSER_WINDOW_FRAME: 316 if (bw->scrolling == SCROLLING_NO) 317 window.flags &= ~(wimp_WINDOW_VSCROLL | 318 wimp_WINDOW_HSCROLL); 319 if (bw->scrolling == SCROLLING_AUTO) 320 window.flags &= ~wimp_WINDOW_HSCROLL; 321 if (!bw->border) 322 window.title_fg = 0xff; 323 else { 324 /* set the correct border colour */ 325 unsigned int col; 326 col = bw->border_colour & 0xffffff; 327 sprintf(g->validation, "C%.6x", col); 328 window.extra_flags |= wimp_WINDOW_USE_TITLE_VALIDATION_STRING; 329 window.title_data.indirected_text.validation = g->validation; 330 } 331 break; 332 case BROWSER_WINDOW_NORMAL: 333 window.flags |= wimp_WINDOW_SIZE_ICON | 334 wimp_WINDOW_BACK_ICON | 335 wimp_WINDOW_CLOSE_ICON | 336 wimp_WINDOW_TITLE_ICON | 337 wimp_WINDOW_TOGGLE_ICON; 338 break; 339 } 340 341 if (open_centred) { 342 scroll_width = ro_get_vscroll_width(NULL); 343 window.visible.x0 -= scroll_width; 344 } 345 346 error = xwimp_create_window(&window, &g->window); 347 if (error) { 348 LOG(("xwimp_create_window: 0x%x: %s", 349 error->errnum, error->errmess)); 350 warn_user("WimpError", error->errmess); 351 free(g); 352 return 0; 353 } 354 355 /* Link into window list */ 356 g->prev = 0; 357 g->next = window_list; 358 if (window_list) 359 window_list->prev = g; 360 window_list = g; 361 window_count++; 362 363 /* Add in a toolbar and status bar */ 364 if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) { 365 g->status_bar = ro_gui_status_bar_create(g->window, option_toolbar_status_width); 366 g->toolbar = ro_gui_theme_create_toolbar(NULL, THEME_BROWSER_TOOLBAR); 367 ro_gui_theme_attach_toolbar(g->toolbar, g->window); 368 } else { 369 g->toolbar = NULL; 370 } 371 372 /* Set the window options */ 373 bw->window = g; 374 ro_gui_window_clone_options(bw, clone); 375 ro_gui_prepare_navigate(g); 376 377 /* Register event handlers */ 378 ro_gui_wimp_event_set_user_data(g->window, g); 379 ro_gui_wimp_event_register_open_window(g->window, ro_gui_window_open); 380 ro_gui_wimp_event_register_close_window(g->window, ro_gui_window_close); 381 ro_gui_wimp_event_register_redraw_window(g->window, ro_gui_window_redraw); 382 ro_gui_wimp_event_register_keypress(g->window, ro_gui_window_keypress); 383 if (g->toolbar) 384 ro_gui_wimp_event_register_keypress(g->toolbar->toolbar_handle, 385 ro_gui_window_keypress); 386 ro_gui_wimp_event_register_mouse_click(g->window, ro_gui_window_click); 387 388 /* Open the window at the top of the stack */ 389 state.w = g->window; 390 error = xwimp_get_window_state(&state); 391 if (error) { 392 LOG(("xwimp_get_window_state: 0x%x: %s", 393 error->errnum, error->errmess)); 394 warn_user("WimpError", error->errmess); 395 return g; 396 } 397 398 state.next = wimp_TOP; 399 if (bw->parent) { 400 top = browser_window_owner(bw); 401 error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), 402 top->window->window, 403 wimp_CHILD_LINKS_PARENT_WORK_AREA 404 << wimp_CHILD_XORIGIN_SHIFT | 405 wimp_CHILD_LINKS_PARENT_WORK_AREA 406 << wimp_CHILD_YORIGIN_SHIFT); 407 if (error) { 408 LOG(("xwimp_open_window_nested: 0x%x: %s", 409 error->errnum, error->errmess)); 410 warn_user("WimpError", error->errmess); 411 } 412 } 413 414 ro_gui_window_open(PTR_WIMP_OPEN(&state)); 415 416 /* Claim the caret for top-level windows */ 417 if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) { 418 if (g->toolbar && g->toolbar->display_url) { 419 error = xwimp_set_caret_position( 420 g->toolbar->toolbar_handle, 421 ICON_TOOLBAR_URL, -1, -1, -1, 0); 422 ro_gui_url_complete_start(g); 423 if (error) { 424 LOG(("xwimp_set_caret_position: 0x%x: %s", 425 error->errnum, error->errmess)); 426 warn_user("WimpError", error->errmess); 427 } 428 } else 429 gui_window_place_caret(g, -100, -100, 0); 430 } 431 return g; 432} 433 434 435/** 436 * Close a browser window and free any related resources. 437 * 438 * \param g gui_window to destroy 439 */ 440 441void gui_window_destroy(struct gui_window *g) 442{ 443 os_error *error; 444 wimp_w w; 445 446 assert(g); 447 448 /* stop any tracking */ 449 if (gui_track_gui_window == g) { 450 gui_track_gui_window = NULL; 451 gui_current_drag_type = GUI_DRAG_NONE; 452 } 453 454 /* remove from list */ 455 if (g->prev) 456 g->prev->next = g->next; 457 else 458 window_list = g->next; 459 if (g->next) 460 g->next->prev = g->prev; 461 462 /* destroy toolbar */ 463 if (g->toolbar) 464 ro_gui_theme_destroy_toolbar(g->toolbar); 465 if (g->status_bar) 466 ro_gui_status_bar_destroy(g->status_bar); 467 468 w = g->window; 469 ro_gui_url_complete_close(NULL, 0); 470 ro_gui_dialog_close_persistent(w); 471 if (current_menu_window == w) 472 ro_gui_menu_closed(true); 473 ro_gui_window_remove_update_boxes(g); 474 475 /* delete window */ 476 error = xwimp_delete_window(w); 477 if (error) { 478 LOG(("xwimp_delete_window: 0x%x: %s", 479 error->errnum, error->errmess)); 480 warn_user("WimpError", error->errmess); 481 } 482 ro_gui_wimp_event_finalise(w); 483 484 free(g); 485} 486 487 488/** 489 * Set the title of a browser window. 490 * 491 * \param g gui_window to update 492 * \param title new window title, copied 493 */ 494 495void gui_window_set_title(struct gui_window *g, const char *title) 496{ 497 int scale_disp; 498 499 assert(g); 500 assert(title); 501 502 if (g->bw->scale != 1.0) { 503 scale_disp = g->bw->scale * 100; 504 if (ABS((float)scale_disp - g->bw->scale * 100) >= 0.05) 505 snprintf(g->title, sizeof g->title, "%s (%.1f%%)", 506 title, g->bw->scale * 100); 507 else 508 snprintf(g->title, sizeof g->title, "%s (%i%%)", 509 title, scale_disp); 510 } else { 511 strncpy(g->title, title, sizeof g->title); 512 } 513 514 /* only top-level parents have titlebars */ 515 if (!g->bw->parent) 516 ro_gui_set_window_title(g->window, g->title); 517} 518 519 520/** 521 * Force a redraw of part of the contents of a browser window. 522 * 523 * \param g gui_window to redraw 524 * \param x0 rectangle to redraw 525 * \param y0 rectangle to redraw 526 * \param x1 rectangle to redraw 527 * \param y1 rectangle to redraw 528 */ 529 530void gui_window_redraw(struct gui_window *g, int x0, int y0, int x1, int y1) 531{ 532 os_error *error; 533 534 assert(g); 535 536 error = xwimp_force_redraw(g->window, x0 * 2, -y1 * 2, x1 * 2, -y0 * 2); 537 if (error) { 538 LOG(("xwimp_force_redraw: 0x%x: %s", 539 error->errnum, error->errmess)); 540 warn_user("WimpError", error->errmess); 541 } 542} 543 544 545/** 546 * Force a redraw of the entire contents of a browser window. 547 * 548 * \param g gui_window to redraw 549 */ 550void gui_window_redraw_window(struct gui_window *g) 551{ 552 wimp_window_info info; 553 os_error *error; 554 555 assert(g); 556 info.w = g->window; 557 error = xwimp_get_window_info_header_only(&info); 558 if (error) { 559 LOG(("xwimp_get_window_info_header_only: 0x%x: %s", 560 error->errnum, error->errmess)); 561 warn_user("WimpError", error->errmess); 562 return; 563 } 564 error = xwimp_force_redraw(g->window, info.extent.x0, info.extent.y0, 565 info.extent.x1, info.extent.y1); 566 if (error) { 567 LOG(("xwimp_force_redraw: 0x%x: %s", 568 error->errnum, error->errmess)); 569 warn_user("WimpError", error->errmess); 570 } 571} 572 573 574/** 575 * Redraw an area of a window. 576 * 577 * \param g gui_window 578 * \param data content_msg_data union with filled in redraw data 579 */ 580 581void gui_window_update_box(struct gui_window *g, 582 const union content_msg_data *data) 583{ 584 hlcache_handle *h = g->bw->current_content; 585 bool use_buffer; 586 int x0, y0, x1, y1; 587 struct update_box *cur; 588 589 if (!h) 590 return; 591 592 x0 = floorf(data->redraw.x * 2 * g->bw->scale); 593 y0 = -ceilf((data->redraw.y + data->redraw.height) * 2 * g->bw->scale); 594 x1 = ceilf((data->redraw.x + data->redraw.width) * 2 * g->bw->scale) + 1; 595 y1 = -floorf(data->redraw.y * 2 * g->bw->scale) + 1; 596 use_buffer = 597 (g->option.buffer_everything || g->option.buffer_animations); 598 599 /* try to optimise buffered redraws */ 600 if (use_buffer) { 601 for (cur = pending_updates; cur != NULL; cur = cur->next) { 602 if ((cur->g != g) || (!cur->use_buffer)) 603 continue; 604 if ((((cur->x0 - x1) < MARGIN) || ((cur->x1 - x0) < MARGIN)) && 605 (((cur->y0 - y1) < MARGIN) || ((cur->y1 - y0) < MARGIN))) { 606 cur->x0 = min(cur->x0, x0); 607 cur->y0 = min(cur->y0, y0); 608 cur->x1 = max(cur->x1, x1); 609 cur->y1 = max(cur->y1, y1); 610 return; 611 } 612 613 } 614 } 615 cur = malloc(sizeof(struct update_box)); 616 if (!cur) { 617 LOG(("No memory for malloc.")); 618 warn_user("NoMemory", 0); 619 return; 620 } 621 cur->x0 = x0; 622 cur->y0 = y0; 623 cur->x1 = x1; 624 cur->y1 = y1; 625 cur->next = pending_updates; 626 pending_updates = cur; 627 cur->g = g; 628 cur->use_buffer = use_buffer; 629 cur->data = *data; 630} 631 632 633/** 634 * Get the scroll position of a browser window. 635 * 636 * \param g gui_window 637 * \param sx receives x ordinate of point at top-left of window 638 * \param sy receives y ordinate of point at top-left of window 639 * \return true iff successful 640 */ 641 642bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) 643{ 644 wimp_window_state state; 645 os_error *error; 646 int toolbar_height = 0; 647 648 assert(g); 649 650 state.w = g->window; 651 error = xwimp_get_window_state(&state); 652 if (error) { 653 LOG(("xwimp_get_window_state: 0x%x: %s", 654 error->errnum, error->errmess)); 655 warn_user("WimpError", error->errmess); 656 return false; 657 } 658 659 if (g->toolbar) 660 toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); 661 *sx = state.xscroll / (2 * g->bw->scale); 662 *sy = -(state.yscroll - toolbar_height) / (2 * g->bw->scale); 663 return true; 664} 665 666 667/** 668 * Set the scroll position of a browser window. 669 * 670 * \param g gui_window to scroll 671 * \param sx point to place at top-left of window 672 * \param sy point to place at top-left of window 673 */ 674 675void gui_window_set_scroll(struct gui_window *g, int sx, int sy) 676{ 677 wimp_window_state state; 678 os_error *error; 679 680 assert(g); 681 682 state.w = g->window; 683 error = xwimp_get_window_state(&state); 684 if (error) { 685 LOG(("xwimp_get_window_state: 0x%x: %s", 686 error->errnum, error->errmess)); 687 warn_user("WimpError", error->errmess); 688 return; 689 } 690 691 state.xscroll = sx * 2 * g->bw->scale; 692 state.yscroll = -sy * 2 * g->bw->scale; 693 if (g->toolbar) 694 state.yscroll += ro_gui_theme_toolbar_full_height(g->toolbar); 695 ro_gui_window_open(PTR_WIMP_OPEN(&state)); 696} 697 698 699/** 700 * Scrolls the specified area of a browser window into view. 701 * 702 * \param g gui_window to scroll 703 * \param x0 left point to ensure visible 704 * \param y0 bottom point to ensure visible 705 * \param x1 right point to ensure visible 706 * \param y1 top point to ensure visible 707 */ 708void gui_window_scroll_visible(struct gui_window *g, int x0, int y0, int x1, int y1) 709{ 710 wimp_window_state state; 711 os_error *error; 712 int cx0, cy0, width, height; 713 int padding_available; 714 int toolbar_height = 0; 715 int correction; 716 717 assert(g); 718 719 state.w = g->window; 720 error = xwimp_get_window_state(&state); 721 if (error) { 722 LOG(("xwimp_get_window_state: 0x%x: %s", 723 error->errnum, error->errmess)); 724 warn_user("WimpError", error->errmess); 725 return; 726 } 727 728 if (g->toolbar) 729 toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); 730 731 x0 = x0 * 2 * g->bw->scale; 732 y0 = y0 * 2 * g->bw->scale; 733 x1 = x1 * 2 * g->bw->scale; 734 y1 = y1 * 2 * g->bw->scale; 735 736 cx0 = state.xscroll; 737 cy0 = -state.yscroll + toolbar_height; 738 width = state.visible.x1 - state.visible.x0; 739 height = state.visible.y1 - state.visible.y0 - toolbar_height; 740 741 /* make sure we're visible */ 742 correction = (x1 - cx0 - width); 743 if (correction > 0) 744 cx0 += correction; 745 correction = (y1 - cy0 - height); 746 if (correction > 0) 747 cy0 += correction; 748 if (x0 < cx0) 749 cx0 = x0; 750 if (y0 < cy0) 751 cy0 = y0; 752 753 /* try to give a SCROLL_VISIBLE_PADDING border of space around us */ 754 padding_available = (width - x1 + x0) / 2; 755 if (padding_available > 0) { 756 if (padding_available > SCROLL_VISIBLE_PADDING) 757 padding_available = SCROLL_VISIBLE_PADDING; 758 correction = (cx0 + width - x1); 759 if (correction < padding_available) 760 cx0 += padding_available; 761 correction = (x0 - cx0); 762 if (correction < padding_available) 763 cx0 -= padding_available; 764 } 765 padding_available = (height - y1 + y0) / 2; 766 if (padding_available > 0) { 767 if (padding_available > SCROLL_VISIBLE_PADDING) 768 padding_available = SCROLL_VISIBLE_PADDING; 769 correction = (cy0 + height - y1); 770 if (correction < padding_available) 771 cy0 += padding_available; 772 correction = (y0 - cy0); 773 if (correction < padding_available) 774 cy0 -= padding_available; 775 } 776 777 state.xscroll = cx0; 778 state.yscroll = -cy0 + toolbar_height; 779 ro_gui_window_open(PTR_WIMP_OPEN(&state)); 780} 781 782 783/** 784 * Opens a frame at a specified position. 785 * 786 * \param g child gui_window to open 787 * \param x0 left point to open at 788 * \param y0 bottom point to open at 789 * \param x1 right point to open at 790 * \param y1 top point to open at 791 */ 792void gui_window_position_frame(struct gui_window *g, int x0, int y0, int x1, int y1) 793{ 794 wimp_window_state state; 795 os_error *error; 796 int px0, py1; 797 struct browser_window *bw; 798 struct browser_window *parent; 799 struct browser_window *top; 800 float scale = 1.0; 801 802 assert(g); 803 bw = g->bw; 804 assert(bw); 805 parent = bw->parent; 806 assert(parent); 807 top = browser_window_owner(bw); 808 809 /* store position for children */ 810 if (parent->browser_window_type == BROWSER_WINDOW_IFRAME) { 811 bw->x0 = x0; 812 bw->y0 = y0; 813 bw->x1 = x1; 814 bw->y1 = y1; 815 } else { 816 bw->x0 = x0 = parent->x0 + x0; 817 bw->y0 = y0 = parent->y0 + y0; 818 bw->x1 = x1 = parent->x0 + x1; 819 bw->y1 = y1 = parent->y0 + y1; 820 } 821 822 /* only scale iframe locations */ 823 if (bw->browser_window_type == BROWSER_WINDOW_IFRAME) 824 scale = g->bw->scale; 825 826 /* get the position of the top level window */ 827 state.w = top->window->window; 828 error = xwimp_get_window_state(&state); 829 if (error) { 830 LOG(("xwimp_get_window_state: 0x%x: %s", 831 error->errnum, error->errmess)); 832 warn_user("WimpError", error->errmess); 833 return; 834 } 835 px0 = state.visible.x0 - state.xscroll; 836 py1 = state.visible.y1 - state.yscroll; 837 838 /* get our current window state */ 839 state.w = g->window; 840 error = xwimp_get_window_state(&state); 841 if (error) { 842 LOG(("xwimp_get_window_state: 0x%x: %s", 843 error->errnum, error->errmess)); 844 warn_user("WimpError", error->errmess); 845 return; 846 } 847 if (!g->bw->border) { 848 x0 -= 1; 849 y0 -= 1; 850 x1 += 1; 851 y1 += 1; 852 } 853 854 x1 = x1 * 2 * scale; 855 y1 = y1 * 2 * scale; 856 857 /* scrollbars must go inside */ 858 if (state.flags & wimp_WINDOW_HSCROLL) { 859 y1 -= ro_get_hscroll_height(NULL); 860 if (g->bw->border) 861 y1 += 2; 862 } 863 if (state.flags & wimp_WINDOW_VSCROLL) { 864 x1 -= ro_get_vscroll_width(NULL); 865 if (g->bw->border) 866 x1 += 2; 867 } 868 state.visible.x0 = px0 + x0 * 2 * scale; 869 state.visible.y0 = py1 - y1; 870 state.visible.x1 = px0 + x1; 871 state.visible.y1 = py1 - y0 * 2 * scale; 872 g->update_extent = true; 873 ro_gui_window_open(PTR_WIMP_OPEN(&state)); 874} 875 876 877/** 878 * Find the current dimensions of a browser window's content area. 879 * 880 * \param g gui_window to measure 881 * \param width receives width of window 882 * \param height receives height of window 883 * \param scaled whether to return scaled values 884 */ 885 886void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, bool scaled) 887{ 888 /* use the cached window sizes */ 889 *width = g->old_width / 2; 890 *height = g->old_height / 2; 891 if (scaled) { 892 *width /= g->bw->scale; 893 *height /= g->bw->scale; 894 } 895} 896 897 898/** 899 * Update the extent of the inside of a browser window to that of the current content. 900 * 901 * \param g gui_window to update the extent of 902 */ 903 904void gui_window_update_extent(struct gui_window *g) 905{ 906 os_error *error; 907 wimp_window_state state; 908 bool update; 909 unsigned int flags; 910 int scroll = 0; 911 912 assert(g); 913 914 state.w = g->window; 915 error = xwimp_get_window_state(&state); 916 if (error) { 917 LOG(("xwimp_get_window_state: 0x%x: %s", 918 error->errnum, error->errmess)); 919 warn_user("WimpError", error->errmess); 920 return; 921 } 922 923 /* scroll on toolbar height change */ 924 if (g->toolbar) { 925 scroll = ro_gui_theme_height_change(g->toolbar); 926 state.yscroll -= scroll; 927 } 928 929 /* only allow a further reformat if we've gained/lost scrollbars */ 930 flags = state.flags & (wimp_WINDOW_HSCROLL | wimp_WINDOW_VSCROLL); 931 update = g->bw->reformat_pending; 932 g->update_extent = true; 933 ro_gui_window_open(PTR_WIMP_OPEN(&state)); 934 935 state.w = g->window; 936 error = xwimp_get_window_state(&state); 937 if (error) { 938 LOG(("xwimp_get_window_state: 0x%x: %s", 939 error->errnum, error->errmess)); 940 warn_user("WimpError", error->errmess); 941 return; 942 } 943 if (flags == (state.flags & (wimp_WINDOW_HSCROLL | wimp_WINDOW_VSCROLL))) 944 g->bw->reformat_pending = update; 945 if ((scroll != 0) && (g->bw->children)) 946 browser_window_recalculate_frameset(g->bw); 947} 948 949 950/** 951 * Set the status bar of a browser window. 952 * 953 * \param g gui_window to update 954 * \param text new status text 955 */ 956 957void gui_window_set_status(struct gui_window *g, const char *text) 958{ 959 if (g->status_bar) 960 ro_gui_status_bar_set_text(g->status_bar, text); 961} 962 963 964/** 965 * Change mouse pointer shape 966 */ 967 968void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) 969{ 970 static gui_pointer_shape curr_pointer = GUI_POINTER_DEFAULT; 971 struct ro_gui_pointer_entry *entry; 972 os_error *error; 973 974 if (shape == curr_pointer) 975 return; 976 977 assert(shape < sizeof ro_gui_pointer_table / 978 sizeof ro_gui_pointer_table[0]); 979 980 entry = &ro_gui_pointer_table[shape]; 981 982 if (entry->wimp_area) { 983 /* pointer in the Wimp's sprite area */ 984 error = xwimpspriteop_set_pointer_shape(entry->sprite_name, 985 1, entry->xactive, entry->yactive, 0, 0); 986 if (error) { 987 LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s", 988 error->errnum, error->errmess)); 989 warn_user("WimpError", error->errmess); 990 } 991 } else { 992 /* pointer in our own sprite area */ 993 error = xosspriteop_set_pointer_shape(osspriteop_USER_AREA, 994 gui_sprites, 995 (osspriteop_id) entry->sprite_name, 996 1, entry->xactive, entry->yactive, 0, 0); 997 if (error) { 998 LOG(("xosspriteop_set_pointer_shape: 0x%x: %s", 999 error->errnum, error->errmess)); 1000 warn_user("WimpError", error->errmess); 1001 } 1002 } 1003 1004 curr_pointer = shape; 1005} 1006 1007 1008/** 1009 * Remove the mouse pointer from the screen 1010 */ 1011 1012void gui_window_hide_pointer(struct gui_window *g) 1013{ 1014 os_error *error; 1015 1016 error = xwimpspriteop_set_pointer_shape(NULL, 0x30, 0, 0, 0, 0); 1017 if (error) { 1018 LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s", 1019 error->errnum, error->errmess)); 1020 warn_user("WimpError", error->errmess); 1021 } 1022} 1023 1024 1025/** 1026 * Set the contents of a window's address bar. 1027 * 1028 * \param g gui_window to update 1029 * \param url new url for address bar 1030 */ 1031 1032void gui_window_set_url(struct gui_window *g, const char *url) 1033{ 1034 wimp_caret caret; 1035 os_error *error; 1036 const char *toolbar_url; 1037 1038 if (!g->toolbar) 1039 return; 1040 1041 ro_gui_set_icon_string(g->toolbar->toolbar_handle, 1042 ICON_TOOLBAR_URL, url, true); 1043 ro_gui_force_redraw_icon(g->toolbar->toolbar_handle, 1044 ICON_TOOLBAR_FAVICON); 1045 1046 /* if the caret is in the address bar, move it to the end */ 1047 error = xwimp_get_caret_position(&caret); 1048 if (error) { 1049 LOG(("xwimp_get_caret_position: 0x%x: %s", 1050 error->errnum, error->errmess)); 1051 warn_user("WimpError", error->errmess); 1052 return; 1053 } 1054 1055 if (!(caret.w == g->toolbar->toolbar_handle && 1056 caret.i == ICON_TOOLBAR_URL)) 1057 return; 1058 1059 toolbar_url = ro_gui_get_icon_string(g->toolbar->toolbar_handle, 1060 ICON_TOOLBAR_URL); 1061 error = xwimp_set_caret_position(g->toolbar->toolbar_handle, 1062 ICON_TOOLBAR_URL, 0, 0, -1, (int)strlen(toolbar_url)); 1063 if (error) { 1064 LOG(("xwimp_set_caret_position: 0x%x: %s", 1065 error->errnum, error->errmess)); 1066 warn_user("WimpError", error->errmess); 1067 } 1068 ro_gui_url_complete_start(g); 1069} 1070 1071 1072/** 1073 * Update the interface to reflect start of page loading. 1074 * 1075 * \param g window with start of load 1076 */ 1077 1078void gui_window_start_throbber(struct gui_window *g) 1079{ 1080 ro_gui_menu_objects_moved(); 1081 ro_gui_prepare_navigate(g); 1082 xos_read_monotonic_time(&g->throbtime); 1083 g->throbber = 0; 1084} 1085 1086 1087 1088/** 1089 * Update the interface to reflect page loading stopped. 1090 * 1091 * \param g window with start of load 1092 */ 1093 1094void gui_window_stop_throbber(struct gui_window *g) 1095{ 1096 char throb_buf[12]; 1097 ro_gui_prepare_navigate(g); 1098 g->throbber = 0; 1099 if (g->toolbar) { 1100 strcpy(throb_buf, "throbber0"); 1101 ro_gui_set_icon_string(g->toolbar->toolbar_handle, 1102 ICON_TOOLBAR_THROBBER, throb_buf, true); 1103 if ((g->toolbar->descriptor) && (g->toolbar->descriptor->throbber_redraw)) 1104 ro_gui_force_redraw_icon(g->toolbar->toolbar_handle, 1105 ICON_TOOLBAR_THROBBER); 1106 } 1107} 1108 1109/** 1110 * set favicon 1111 */ 1112void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon) 1113{ 1114} 1115 1116/** 1117* set gui display of a retrieved favicon representing the search provider 1118* \param ico may be NULL for local calls; then access current cache from 1119* search_web_ico() 1120*/ 1121void gui_window_set_search_ico(hlcache_handle *ico) 1122{ 1123} 1124 1125/** 1126 * Place the caret in a browser window. 1127 * 1128 * \param g window with caret 1129 * \param x coordinates of caret 1130 * \param y coordinates of caret 1131 * \param height height of caret 1132 */ 1133 1134void gui_window_place_caret(struct gui_window *g, int x, int y, int height) 1135{ 1136 os_error *error; 1137 1138 error = xwimp_set_caret_position(g->window, -1, 1139 x * 2 * g->bw->scale, 1140 -(y + height) * 2 * g->bw->scale, 1141 height * 2 * g->bw->scale, -1); 1142 if (error) { 1143 LOG(("xwimp_set_caret_position: 0x%x: %s", 1144 error->errnum, error->errmess)); 1145 warn_user("WimpError", error->errmess); 1146 } 1147} 1148 1149 1150/** 1151 * Remove the caret, if present. 1152 * 1153 * \param g window with caret 1154 */ 1155 1156void gui_window_remove_caret(struct gui_window *g) 1157{ 1158 wimp_caret caret; 1159 os_error *error; 1160 1161 error = xwimp_get_caret_position(&caret); 1162 if (error) { 1163 LOG(("xwimp_get_caret_position: 0x%x: %s", 1164 error->errnum, error->errmess)); 1165 warn_user("WimpError", error->errmess); 1166 return; 1167 } 1168 1169 if (caret.w != g->window) 1170 /* we don't have the caret: do nothing */ 1171 return; 1172 1173 /* hide caret, but keep input focus */ 1174 gui_window_place_caret(g, -100, -100, 0); 1175} 1176 1177 1178/** 1179 * Called when the gui_window has new content. 1180 * 1181 * \param g the gui_window that has new content 1182 */ 1183 1184void gui_window_new_content(struct gui_window *g) 1185{ 1186 ro_gui_menu_objects_moved(); 1187 ro_gui_prepare_navigate(g); 1188 ro_gui_dialog_close_persistent(g->window); 1189} 1190 1191 1192/** 1193 * Starts drag scrolling of a browser window 1194 * 1195 * \param gw gui window 1196 */ 1197 1198bool gui_window_scroll_start(struct gui_window *g) 1199{ 1200 wimp_window_info_base info; 1201 wimp_pointer pointer; 1202 os_error *error; 1203 wimp_drag drag; 1204 int height; 1205 int width; 1206 1207 error = xwimp_get_pointer_info(&pointer); 1208 if (error) { 1209 LOG(("xwimp_get_pointer_info 0x%x : %s", 1210 error->errnum, error->errmess)); 1211 warn_user("WimpError", error->errmess); 1212 return false; 1213 } 1214 1215 info.w = g->window; 1216 error = xwimp_get_window_info_header_only((wimp_window_info*)&info); 1217 if (error) { 1218 LOG(("xwimp_get_window_state: 0x%x : %s", 1219 error->errnum, error->errmess)); 1220 warn_user("WimpError", error->errmess); 1221 return false; 1222 } 1223 1224 width = info.extent.x1 - info.extent.x0; 1225 height = info.extent.y1 - info.extent.y0; 1226 1227 drag.type = wimp_DRAG_USER_POINT; 1228 drag.bbox.x1 = pointer.pos.x + info.xscroll; 1229 drag.bbox.y0 = pointer.pos.y + info.yscroll; 1230 drag.bbox.x0 = drag.bbox.x1 - (width - (info.visible.x1 - info.visible.x0)); 1231 drag.bbox.y1 = drag.bbox.y0 + (height - (info.visible.y1 - info.visible.y0)); 1232 1233 if (g->toolbar) { 1234 int tbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); 1235 drag.bbox.y0 -= tbar_height; 1236 drag.bbox.y1 -= tbar_height; 1237 } 1238 1239 error = xwimp_drag_box(&drag); 1240 if (error) { 1241 LOG(("xwimp_drag_box: 0x%x : %s", 1242 error->errnum, error->errmess)); 1243 warn_user("WimpError", error->errmess); 1244 return false; 1245 } 1246 1247 gui_track_gui_window = g; 1248 gui_current_drag_type = GUI_DRAG_SCROLL; 1249 return true; 1250} 1251 1252 1253/** 1254 * Platform-dependent part of starting a box scrolling operation, 1255 * for frames and textareas. 1256 * 1257 * \param x0 minimum x ordinate of box relative to mouse pointer 1258 * \param y0 minimum y ordinate 1259 * \param x1 maximum x ordinate 1260 * \param y1 maximum y ordinate 1261 * \return true iff succesful 1262 */ 1263 1264bool gui_window_box_scroll_start(struct gui_window *g, int x0, int y0, int x1, int y1) 1265{ 1266 wimp_pointer pointer; 1267 os_error *error; 1268 wimp_drag drag; 1269 1270 error = xwimp_get_pointer_info(&pointer); 1271 if (error) { 1272 LOG(("xwimp_get_pointer_info 0x%x : %s", 1273 error->errnum, error->errmess)); 1274 warn_user("WimpError", error->errmess); 1275 return false; 1276 } 1277 1278 drag.type = wimp_DRAG_USER_POINT; 1279 drag.bbox.x0 = pointer.pos.x + (int)(x0 * 2 * g->bw->scale); 1280 drag.bbox.y0 = pointer.pos.y + (int)(y0 * 2 * g->bw->scale); 1281 drag.bbox.x1 = pointer.pos.x + (int)(x1 * 2 * g->bw->scale); 1282 drag.bbox.y1 = pointer.pos.y + (int)(y1 * 2 * g->bw->scale); 1283 1284 error = xwimp_drag_box(&drag); 1285 if (error) { 1286 LOG(("xwimp_drag_box: 0x%x : %s", 1287 error->errnum, error->errmess)); 1288 warn_user("WimpError", error->errmess); 1289 return false; 1290 } 1291 1292 gui_current_drag_type = GUI_DRAG_SCROLL; 1293 return true; 1294} 1295 1296 1297/** 1298 * Starts drag resizing of a browser frame 1299 * 1300 * \param gw gui window 1301 */ 1302 1303bool gui_window_frame_resize_start(struct gui_window *g) 1304{ 1305 wimp_pointer pointer; 1306 os_error *error; 1307 wimp_drag drag; 1308 int x0, y0, x1, y1; 1309 int row = -1, col = -1, i, toolbar_height = 0; 1310 struct browser_window *top, *bw, *parent; 1311 wimp_window_state state; 1312 1313 /* get the maximum drag box (collapse all surrounding frames */ 1314 bw = g->bw; 1315 parent = bw->parent; 1316 x0 = bw->x0; 1317 y0 = bw->y0; 1318 x1 = bw->x1; 1319 y1 = bw->y1; 1320 for (i = 0; i < (parent->cols * parent->rows); i++) { 1321 if (&parent->children[i] == bw) { 1322 col = i % parent->cols; 1323 row = i / parent->cols; 1324 } 1325 } 1326 assert((row >= 0) && (col >= 0)); 1327 1328 if (bw->drag_resize_left) 1329 x0 = parent->children[row * parent->cols + (col - 1)].x0; 1330 if (bw->drag_resize_right) 1331 x1 = parent->children[row * parent->cols + (col + 1)].x1; 1332 if (bw->drag_resize_up) 1333 y0 = parent->children[(row - 1) * parent->cols + col].y0; 1334 if (bw->drag_resize_down) 1335 y1 = parent->children[(row + 1) * parent->cols + col].y1; 1336 1337 /* convert to screen co-ordinates */ 1338 top = browser_window_owner(bw); 1339 if (top->window->toolbar) 1340 toolbar_height = ro_gui_theme_toolbar_full_height(top->window->toolbar); 1341 state.w = top->window->window; 1342 error = xwimp_get_window_state(&state); 1343 if (error) { 1344 LOG(("xwimp_get_window_state: 0x%x: %s", 1345 error->errnum, error->errmess)); 1346 warn_user("WimpError", error->errmess); 1347 return false; 1348 } 1349 x0 = state.visible.x0 + x0 * 2; 1350 y0 = state.visible.y1 - y0 * 2 - toolbar_height; 1351 x1 = state.visible.x0 + x1 * 2 - 1; 1352 y1 = state.visible.y1 - y1 * 2 - toolbar_height - 1; 1353 1354 /* get the pointer position */ 1355 error = xwimp_get_pointer_info(&pointer); 1356 if (error) { 1357 LOG(("xwimp_get_pointer_info 0x%x : %s", 1358 error->errnum, error->errmess)); 1359 warn_user("WimpError", error->errmess); 1360 return false; 1361 } 1362 1363 /* stop dragging in directions we can't extend */ 1364 if (!(bw->drag_resize_left || bw->drag_resize_right)) { 1365 x0 = pointer.pos.x; 1366 x1 = pointer.pos.x; 1367 } 1368 if (!(bw->drag_resize_up || bw->drag_resize_down)) { 1369 y0 = pointer.pos.y; 1370 y1 = pointer.pos.y; 1371 } 1372 1373 /* start the drag */ 1374 drag.type = wimp_DRAG_USER_POINT; 1375 drag.bbox.x0 = x0; 1376 drag.bbox.y0 = y1; 1377 drag.bbox.x1 = x1; 1378 drag.bbox.y1 = y0; 1379 1380 error = xwimp_drag_box(&drag); 1381 if (error) { 1382 LOG(("xwimp_drag_box: 0x%x : %s", 1383 error->errnum, error->errmess)); 1384 warn_user("WimpError", error->errmess); 1385 return false; 1386 } 1387 1388 /* we may not be the window the pointer is currently over */ 1389 gui_track_gui_window = bw->window; 1390 gui_current_drag_type = GUI_DRAG_FRAME; 1391 return true; 1392} 1393 1394 1395/** 1396 * Save the specified content as a link. 1397 * 1398 * \param g gui_window containing the content 1399 * \param c the content to save 1400 */ 1401void gui_window_save_link(struct gui_window *g, const char *url, 1402 const char *title) 1403{ 1404 ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, url, title); 1405 ro_gui_dialog_open_persistent(g->window, dialog_saveas, true); 1406} 1407 1408 1409/** 1410 * Set the scale setting of a window 1411 * 1412 * \param g gui window 1413 * \param scale scale value (1.0 == normal scale) 1414 */ 1415 1416void gui_window_set_scale(struct gui_window *g, float scale) 1417{ 1418 ro_gui_dialog_update_zoom(g); 1419} 1420 1421 1422/** 1423 * Redraws the content for all windows. 1424 */ 1425 1426void ro_gui_window_redraw_all(void) 1427{ 1428 struct gui_window *g; 1429 for (g = window_list; g; g = g->next) 1430 gui_window_redraw_window(g); 1431} 1432 1433/** 1434 * Handle a Redraw_Window_Request for a browser window. 1435 */ 1436 1437void ro_gui_window_redraw(wimp_draw *redraw) 1438{ 1439 osbool more; 1440 struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w); 1441 float scale = g->bw->scale; 1442 hlcache_handle *h = g->bw->current_content; 1443 os_error *error; 1444 1445 /* Handle no content quickly 1446 */ 1447 if (!h) { 1448 ro_gui_user_redraw(redraw, true, os_COLOUR_WHITE); 1449 return; 1450 } 1451 1452 /* We can't render locked content as it is being in the process of 1453 being transformed. We won't update anything (i.e. leaving 1454 window area as is) instead of showing random data in case of 1455 buffered redraw. */ 1456 if (content_is_locked(h)) 1457 return; 1458 1459 plot = ro_plotters; 1460 ro_plot_set_scale(scale); 1461 ro_gui_current_redraw_gui = g; 1462 current_redraw_browser = g->bw; 1463 1464 /* HTML rendering handles scale itself */ 1465 if (content_get_type(h) == CONTENT_HTML) 1466 scale = 1; 1467 1468 error = xwimp_redraw_window(redraw, &more); 1469 if (error) { 1470 LOG(("xwimp_redraw_window: 0x%x: %s", 1471 error->errnum, error->errmess)); 1472 warn_user("WimpError", error->errmess); 1473 return; 1474 } 1475 while (more) { 1476 int clip_x0, clip_y0, clip_x1, clip_y1; 1477 1478 /* OS's redraw request coordinates are in screen coordinates, 1479 * with an origin at the bottom left of the screen. 1480 * Find the coordinate of the top left of the document in terms 1481 * of OS screen coordinates. 1482 * NOTE: OS units are 2 per px. */ 1483 ro_plot_origin_x = redraw->box.x0 - redraw->xscroll; 1484 ro_plot_origin_y = redraw->box.y1 - redraw->yscroll; 1485 1486 /* Convert OS redraw rectangle request coordinates into NetSurf 1487 * coordinates. NetSurf coordinates have origin at top left of 1488 * document and units are in px. */ 1489 clip_x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */ 1490 clip_y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */ 1491 clip_x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */ 1492 clip_y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */ 1493 1494 if (ro_gui_current_redraw_gui->option.buffer_everything) 1495 ro_gui_buffer_open(redraw); 1496 1497 /* Set up NetSurf's plotters with current clip rectangle */ 1498 plot.clip(clip_x0, clip_y0, clip_x1, clip_y1); 1499 1500 if (content_get_type(h) != CONTENT_HTML) 1501 plot.rectangle(clip_x0, clip_y0, clip_x1, clip_y1, 1502 plot_style_fill_white); 1503 1504 /* Redraw the clip rectangle area of the content */ 1505 content_redraw(h, 0, 0, 1506 content_get_width(h) * scale, 1507 content_get_height(h) * scale, 1508 clip_x0, clip_y0, clip_x1, clip_y1, 1509 g->bw->scale, 1510 0xFFFFFF); 1511 1512 if (ro_gui_current_redraw_gui->option.buffer_everything) 1513 ro_gui_buffer_close(); 1514 1515 /* Check to see if there are more rectangles to draw and 1516 * get next one */ 1517 error = xwimp_get_rectangle(redraw, &more); 1518 /* RISC OS 3.7 returns an error here if enough buffer was 1519 claimed to cause a new dynamic area to be created. It 1520 doesn't actually stop anything working, so we mask it out 1521 for now until a better fix is found. This appears to be a 1522 bug in RISC OS. */ 1523 if (error && !(ro_gui_current_redraw_gui-> 1524 option.buffer_everything && 1525 error->errnum == error_WIMP_GET_RECT)) { 1526 LOG(("xwimp_get_rectangle: 0x%x: %s", 1527 error->errnum, error->errmess)); 1528 warn_user("WimpError", error->errmess); 1529 ro_gui_current_redraw_gui = NULL; 1530 current_redraw_browser = NULL; 1531 return; 1532 } 1533 } 1534 ro_gui_current_redraw_gui = NULL; 1535 current_redraw_browser = NULL; 1536} 1537 1538 1539 1540/** 1541 * Remove all pending update boxes for a window 1542 * 1543 * \param g gui_window 1544 */ 1545void ro_gui_window_remove_update_boxes(struct gui_window *g) { 1546 struct update_box *cur; 1547 1548 for (cur = pending_updates; cur != NULL; cur = cur->next) { 1549 if (cur->g == g) 1550 cur->g = NULL; 1551 } 1552} 1553 1554 1555/** 1556 * Redraw any pending update boxes. 1557 */ 1558void ro_gui_window_update_boxes(void) { 1559 hlcache_handle *h; 1560 osbool more; 1561 bool clear_background = false; 1562 bool use_buffer; 1563 wimp_draw update; 1564 int clip_x0, clip_y0, clip_x1, clip_y1; 1565 os_error *error; 1566 struct update_box *cur; 1567 struct gui_window *g; 1568 const union content_msg_data *data; 1569 1570 for (cur = pending_updates; cur != NULL; cur = cur->next) { 1571 g = cur->g; 1572 if (!g) 1573 continue; 1574 h = g->bw->current_content; 1575 data = &cur->data; 1576 use_buffer = cur->use_buffer; 1577 if (!h) 1578 continue; 1579 1580 update.w = g->window; 1581 update.box.x0 = cur->x0; 1582 update.box.y0 = cur->y0; 1583 update.box.x1 = cur->x1; 1584 update.box.y1 = cur->y1; 1585 1586 error = xwimp_update_window(&update, &more); 1587 if (error) { 1588 LOG(("xwimp_update_window: 0x%x: %s", 1589 error->errnum, error->errmess)); 1590 warn_user("WimpError", error->errmess); 1591 continue; 1592 } 1593 1594 /* Set the current redraw gui_window to get options from */ 1595 ro_gui_current_redraw_gui = g; 1596 current_redraw_browser = g->bw; 1597 1598 plot = ro_plotters; 1599 ro_plot_origin_x = update.box.x0 - update.xscroll; 1600 ro_plot_origin_y = update.box.y1 - update.yscroll; 1601 ro_plot_set_scale(g->bw->scale); 1602 1603 /* We should clear the background, except for HTML. */ 1604 if (content_get_type(h) != CONTENT_HTML) 1605 clear_background = true; 1606 1607 while (more) { 1608 clip_x0 = (update.clip.x0 - ro_plot_origin_x) / 2; 1609 clip_y0 = (ro_plot_origin_y - update.clip.y1) / 2; 1610 clip_x1 = (update.clip.x1 - ro_plot_origin_x) / 2; 1611 clip_y1 = (ro_plot_origin_y - update.clip.y0) / 2; 1612 1613 if (use_buffer) 1614 ro_gui_buffer_open(&update); 1615 1616 if (clear_background) { 1617 error = xcolourtrans_set_gcol( 1618 os_COLOUR_WHITE, 1619 colourtrans_SET_BG_GCOL, 1620 os_ACTION_OVERWRITE, 0, 1621 0); 1622 if (error) { 1623 LOG(("xcolourtrans_set_gcol: " 1624 "0x%x: %s", 1625 error->errnum, 1626 error->errmess)); 1627 warn_user("MiscError", 1628 error->errmess); 1629 } 1630 os_clg(); 1631 } 1632 1633 content_redraw(h, 0, 0, 1634 content_get_width(h), 1635 content_get_height(h), 1636 clip_x0, clip_y0, 1637 clip_x1, clip_y1, 1638 g->bw->scale, 1639 0xFFFFFF); 1640 1641 if (use_buffer) 1642 ro_gui_buffer_close(); 1643 error = xwimp_get_rectangle(&update, &more); 1644 /* RISC OS 3.7 returns an error here if enough buffer 1645 * was claimed to cause a new dynamic area to be 1646 * created. It doesn't actually stop anything working, 1647 * so we mask it out for now until a better fix is 1648 * found. This appears to be a bug in RISC OS. */ 1649 if (error && !(use_buffer && 1650 error->errnum == error_WIMP_GET_RECT)) { 1651 LOG(("xwimp_get_rectangle: 0x%x: %s", 1652 error->errnum, error->errmess)); 1653 warn_user("WimpError", error->errmess); 1654 ro_gui_current_redraw_gui = NULL; 1655 current_redraw_browser = NULL; 1656 continue; 1657 } 1658 } 1659 1660 /* Reset the current redraw gui_window to prevent 1661 * thumbnails from retaining options */ 1662 ro_gui_current_redraw_gui = NULL; 1663 current_redraw_browser = NULL; 1664 } 1665 while (pending_updates) { 1666 cur = pending_updates; 1667 pending_updates = pending_updates->next; 1668 free(cur); 1669 } 1670 1671} 1672 1673 1674/** 1675 * Launch a new url in the given window. 1676 * 1677 * \param g gui_window to update 1678 * \param url url to be launched 1679 */ 1680 1681void ro_gui_window_launch_url(struct gui_window *g, const char *url) 1682{ 1683 url_func_result res; 1684 char *url_norm; 1685 1686 ro_gui_url_complete_close(NULL, 0); 1687 res = url_normalize(url, &url_norm); 1688 if (res == URL_FUNC_OK) { 1689 gui_window_set_url(g, url_norm); 1690 browser_window_go(g->bw, url_norm, 0, true); 1691 global_history_add_recent(url_norm); 1692 free(url_norm); 1693 } 1694} 1695 1696 1697/** 1698 * Forces all windows to be set to the current theme 1699 */ 1700void ro_gui_window_update_theme(void) { 1701 struct gui_window *g; 1702 for (g = window_list; g; g = g->next) { 1703 if (g->toolbar) { 1704 if (g->toolbar->editor) 1705 if (!ro_gui_theme_update_toolbar(NULL, g->toolbar->editor)) 1706 g->toolbar->editor = NULL; 1707 if (!ro_gui_theme_update_toolbar(NULL, g->toolbar)) { 1708 ro_gui_theme_destroy_toolbar(g->toolbar); 1709 g->toolbar = NULL; 1710 } 1711 ro_gui_theme_toolbar_editor_sync(g->toolbar); 1712 gui_window_update_extent(g); 1713 } 1714 } 1715} 1716 1717 1718/** 1719 * Updates a windows extent. 1720 * 1721 * \param g the gui_window to update 1722 * \param width the minimum width, or -1 to use window width 1723 * \param height the minimum height, or -1 to use window height 1724 */ 1725 1726void gui_window_set_extent(struct gui_window *g, int width, int height) 1727{ 1728 int screen_width; 1729 int toolbar_height = 0; 1730 hlcache_handle *h; 1731 wimp_window_state state; 1732 os_error *error; 1733 1734 h = g->bw->current_content; 1735 if (g->toolbar) 1736 toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); 1737 1738 /* get the current state */ 1739 if ((height == -1) || (width == -1)) { 1740 state.w = g->window; 1741 error = xwimp_get_window_state(&state); 1742 if (error) { 1743 LOG(("xwimp_get_window_state: 0x%x: %s", 1744 error->errnum, error->errmess)); 1745 warn_user("WimpError", error->errmess); 1746 return; 1747 } 1748 if (width == -1) 1749 width = state.visible.x1 - state.visible.x0; 1750 if (height == -1) { 1751 height = state.visible.y1 - state.visible.y0; 1752 height -= toolbar_height; 1753 } 1754 } 1755 1756 /* the top-level framed window is a total pain. to get it to maximise 1757 * to the top of the screen we need to fake it having a suitably large 1758 * extent */ 1759 if (g->bw->children && 1760 (g->bw->browser_window_type == BROWSER_WINDOW_NORMAL)) { 1761 ro_gui_screen_size(&screen_width, &height); 1762 if (g->toolbar) 1763 height -= ro_gui_theme_toolbar_full_height(g->toolbar); 1764 height -= ro_get_hscroll_height(g->window); 1765 height -= ro_get_title_height(g->window); 1766 } 1767 if (h) { 1768 width = max(width, content_get_width(h) * 2 * g->bw->scale); 1769 height = max(height, content_get_height(h) * 2 * g->bw->scale); 1770 } 1771 os_box extent = { 0, -height, width, toolbar_height }; 1772 error = xwimp_set_extent(g->window, &extent); 1773 if (error) { 1774 LOG(("xwimp_set_extent: 0x%x: %s", 1775 error->errnum, error->errmess)); 1776 warn_user("WimpError", error->errmess); 1777 return; 1778 } 1779} 1780 1781 1782/** 1783 * Open a window using the given wimp_open, handling toolbars and resizing. 1784 */ 1785 1786void ro_gui_window_open(wimp_open *open) 1787{ 1788 struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(open->w); 1789 int width = open->visible.x1 - open->visible.x0; 1790 int height = open->visible.y1 - open->visible.y0; 1791 int size, fheight, fwidth, toolbar_height = 0; 1792 bool no_vscroll, no_hscroll; 1793 float new_scale = 0; 1794 hlcache_handle *h; 1795 wimp_window_state state; 1796 os_error *error; 1797 wimp_w parent; 1798 bits linkage; 1799 1800 if (open->next == wimp_TOP && g->iconise_icon >= 0) { 1801 /* window is no longer iconised, release its sprite number */ 1802 iconise_used[g->iconise_icon] = false; 1803 g->iconise_icon = -1; 1804 } 1805 1806 h = g->bw->current_content; 1807 1808 /* get the current flags/nesting state */ 1809 state.w = g->window; 1810 error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage); 1811 if (error) { 1812 LOG(("xwimp_get_window_state: 0x%x: %s", 1813 error->errnum, error->errmess)); 1814 warn_user("WimpError", error->errmess); 1815 return; 1816 } 1817 1818 /* account for toolbar height, if present */ 1819 if (g->toolbar) 1820 toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); 1821 height -= toolbar_height; 1822 1823 /* work with the state from now on so we can modify flags */ 1824 state.visible = open->visible; 1825 state.xscroll = open->xscroll; 1826 state.yscroll = open->yscroll; 1827 state.next = open->next; 1828 1829 /* handle 'auto' scroll bars' and non-fitting scrollbar removal */ 1830 if ((g->bw->scrolling == SCROLLING_AUTO) || 1831 (g->bw->scrolling == SCROLLING_YES)) { 1832 /* windows lose scrollbars when containing a frameset */ 1833 no_hscroll = (g->bw->children && 1834 (g->bw->browser_window_type != 1835 BROWSER_WINDOW_NORMAL)); 1836 no_vscroll = g->bw->children; 1837 1838 /* hscroll */ 1839 size = ro_get_hscroll_height(NULL); 1840 if (g->bw->border) 1841 size -= 2; 1842 fheight = height; 1843 if (state.flags & wimp_WINDOW_HSCROLL) 1844 fheight += size; 1845 if ((!no_hscroll) && 1846 ((fheight > size) || 1847 (g->bw->browser_window_type == 1848 BROWSER_WINDOW_NORMAL)) && 1849 ((h && width < content_get_width(h) * 1850 2 * g->bw->scale) || 1851 (g->bw->browser_window_type == 1852 BROWSER_WINDOW_NORMAL))) { 1853 if (!(state.flags & wimp_WINDOW_HSCROLL)) { 1854 height -= size; 1855 state.visible.y0 += size; 1856 if (h) { 1857 g->bw->reformat_pending = true; 1858 browser_reformat_pending = true; 1859 } 1860 } 1861 state.flags |= wimp_WINDOW_HSCROLL; 1862 } else { 1863 if (state.flags & wimp_WINDOW_HSCROLL) { 1864 height += size; 1865 state.visible.y0 -= size; 1866 if (h) { 1867 g->bw->reformat_pending = true; 1868 browser_reformat_pending = true; 1869 } 1870 } 1871 state.flags &= ~wimp_WINDOW_HSCROLL; 1872 } 1873 1874 /* vscroll */ 1875 size = ro_get_vscroll_width(NULL); 1876 if (g->bw->border) 1877 size -= 2; 1878 fwidth = width; 1879 if (state.flags & wimp_WINDOW_VSCROLL) 1880 fwidth += size; 1881 if ((!no_vscroll) && 1882 ((fwidth > size) || 1883 (g->bw->browser_window_type == 1884 BROWSER_WINDOW_NORMAL)) && 1885 ((h && height < content_get_height(h) * 1886 2 * g->bw->scale) || 1887 (g->bw->scrolling == SCROLLING_YES))) { 1888 if (!(state.flags & wimp_WINDOW_VSCROLL)) { 1889 width -= size; 1890 state.visible.x1 -= size; 1891 if (h) { 1892 g->bw->reformat_pending = true; 1893 browser_reformat_pending = true; 1894 } 1895 } 1896 state.flags |= wimp_WINDOW_VSCROLL; 1897 } else { 1898 if (state.flags & wimp_WINDOW_VSCROLL) { 1899 width += size; 1900 state.visible.x1 += size; 1901 if (h) { 1902 g->bw->reformat_pending = true; 1903 browser_reformat_pending = true; 1904 } 1905 } 1906 state.flags &= ~wimp_WINDOW_VSCROLL; 1907 } 1908 } 1909 1910 /* reformat or change extent if necessary */ 1911 if ((h) && (g->old_width != width || g->old_height != height)) { 1912 /* Ctrl-resize of a top-level window scales the content size */ 1913 if ((g->old_width > 0) && (g->old_width != width) && 1914 (!g->bw->parent) && 1915 (ro_gui_ctrl_pressed())) 1916 new_scale = (g->bw->scale * width) / g->old_width; 1917 g->bw->reformat_pending = true; 1918 browser_reformat_pending = true; 1919 } 1920 if (g->update_extent || g->old_width != width || 1921 g->old_height != height) { 1922 g->old_width = width; 1923 g->old_height = height; 1924 g->update_extent = false; 1925 gui_window_set_extent(g, width, height); 1926 } 1927 1928 /* first resize stops any flickering by making the URL window on top */ 1929 ro_gui_url_complete_resize(g, PTR_WIMP_OPEN(&state)); 1930 1931 error = xwimp_open_window_nested_with_flags(&state, parent, linkage); 1932 if (error) { 1933 LOG(("xwimp_open_window: 0x%x: %s", 1934 error->errnum, error->errmess)); 1935 warn_user("WimpError", error->errmess); 1936 return; 1937 } 1938 1939 /* update the toolbar */ 1940 if (g->status_bar) 1941 ro_gui_status_bar_resize(g->status_bar); 1942 if (g->toolbar) { 1943 ro_gui_theme_process_toolbar(g->toolbar, -1); 1944 /* second resize updates to the new URL bar width */ 1945 ro_gui_url_complete_resize(g, open); 1946 } 1947 1948 /* set the new scale from a ctrl-resize. this must be done at the end as 1949 * it may cause a frameset recalculation based on the new window size. 1950 */ 1951 if (new_scale > 0) 1952 browser_window_set_scale(g->bw, new_scale, true); 1953} 1954 1955 1956/** 1957 * Handle wimp closing event 1958 */ 1959void ro_gui_window_close(wimp_w w) { 1960 struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(w); 1961 wimp_pointer pointer; 1962 os_error *error; 1963 char *temp_name, *r; 1964 char *filename; 1965 hlcache_handle *h = NULL; 1966 bool destroy; 1967 1968 error = xwimp_get_pointer_info(&pointer); 1969 if (error) { 1970 LOG(("xwimp_get_pointer_info: 0x%x: %s", 1971 error->errnum, error->errmess)); 1972 warn_user("WimpError", error->errmess); 1973 return; 1974 } 1975 if (g->bw) 1976 h = g->bw->current_content; 1977 if (pointer.buttons & wimp_CLICK_ADJUST) { 1978 destroy = !ro_gui_shift_pressed(); 1979 filename = (h && content_get_url(h)) ? 1980 url_to_path(content_get_url(h)) : NULL; 1981 if (filename) { 1982 temp_name = malloc(strlen(filename) + 32); 1983 if (temp_name) { 1984 sprintf(temp_name, "Filer_OpenDir %s", 1985 filename); 1986 r = temp_name + strlen(temp_name); 1987 while (r > temp_name) { 1988 if (*r == '.') { 1989 *r = '\0'; 1990 break; 1991 } 1992 r--; 1993 } 1994 error = xos_cli(temp_name); 1995 if (error) { 1996 LOG(("xos_cli: 0x%x: %s", 1997 error->errnum, 1998 error->errmess)); 1999 warn_user("MiscError", error->errmess); 2000 return; 2001 } 2002 free(temp_name); 2003 } 2004 free(filename); 2005 } else { 2006 /* this is pointless if we are about to close the 2007 * window */ 2008 if (!destroy) 2009 ro_gui_menu_handle_action(w, 2010 BROWSER_NAVIGATE_UP, true); 2011 } 2012 } 2013 else 2014 destroy = true; 2015 2016 if (destroy) 2017 browser_window_destroy(g->bw); 2018} 2019 2020 2021/** 2022 * Destroy all browser windows. 2023 */ 2024 2025void ro_gui_window_quit(void) 2026{ 2027 struct gui_window *cur; 2028 2029 while (window_list) { 2030 cur = window_list; 2031 window_list = window_list->next; 2032 2033 /* framesets and iframes are destroyed by their parents */ 2034 if (!cur->bw->parent) 2035 browser_window_destroy(cur->bw); 2036 } 2037} 2038 2039 2040/** 2041 * Animate the "throbbers" of all browser windows. 2042 */ 2043 2044void ro_gui_throb(void) 2045{ 2046 os_t t; 2047 struct gui_window *g, *top_g; 2048 struct browser_window *top; 2049 char throb_buf[12]; 2050 2051 xos_read_monotonic_time(&t); 2052 2053 for (g = window_list; g; g = g->next) { 2054 if (!g->bw->throbbing) 2055 continue; 2056 for (top = g->bw; top->parent; top = top->parent); 2057 top_g = top->window; 2058 if (!top_g->toolbar || !top_g->toolbar->display_throbber || 2059 !top_g->toolbar->descriptor || 2060 !top_g->toolbar->descriptor->theme || 2061 (t < top_g->throbtime + 10)) 2062 continue; 2063 top_g->throbtime = t; 2064 top_g->throbber++; 2065 if (top_g->toolbar->descriptor->theme->throbber_frames < top_g->throbber) 2066 top_g->throbber = 1; 2067 sprintf(throb_buf, "throbber%i", top_g->throbber); 2068 ro_gui_set_icon_string(top_g->toolbar->toolbar_handle, 2069 ICON_TOOLBAR_THROBBER, throb_buf, true); 2070 if (top_g->toolbar->descriptor->throbber_redraw) 2071 ro_gui_force_redraw_icon(top_g->toolbar->toolbar_handle, 2072 ICON_TOOLBAR_THROBBER); 2073 } 2074} 2075 2076 2077/** 2078 * Convert a RISC OS window handle to a gui_window. 2079 * 2080 * \param w RISC OS window handle 2081 * \return pointer to a structure if found, 0 otherwise 2082 */ 2083 2084struct gui_window *ro_gui_window_lookup(wimp_w window) 2085{ 2086 struct gui_window *g; 2087 for (g = window_list; g; g = g->next) 2088 if (g->window == window) 2089 return g; 2090 return 0; 2091} 2092 2093 2094/** 2095 * Convert a toolbar RISC OS window handle to a gui_window. 2096 * 2097 * \param w RISC OS window handle of a toolbar 2098 * \return pointer to a structure if found, 0 otherwise 2099 */ 2100 2101struct gui_window *ro_gui_toolbar_lookup(wimp_w window) 2102{ 2103 struct gui_window *g; 2104 for (g = window_list; g; g = g->next) { 2105 if ((g->toolbar) && ((g->toolbar->toolbar_handle == window) || 2106 ((g->toolbar->editor) && 2107 (g->toolbar->editor->toolbar_handle == window)))) 2108 return g; 2109 } 2110 return 0; 2111} 2112 2113 2114/** 2115 * Handle pointer movements in a browser window. 2116 * 2117 * \param g browser window that the pointer is in 2118 * \param pointer new mouse position 2119 */ 2120 2121void ro_gui_window_mouse_at(struct gui_window *g, wimp_pointer *pointer) 2122{ 2123 os_coord pos; 2124 2125 if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) 2126 browser_window_mouse_track(g->bw, 2127 ro_gui_mouse_drag_state(pointer->buttons), 2128 pos.x, pos.y); 2129} 2130 2131 2132/** 2133 * Process Mouse_Click events in a toolbar. 2134 */ 2135 2136bool ro_gui_toolbar_click(wimp_pointer *pointer) 2137{ 2138 struct gui_window *g = ro_gui_toolbar_lookup(pointer->w); 2139 struct browser_window *new_bw; 2140 2141 /* toolbars in the options window have no gui_window */ 2142 if (!g) 2143 return true; 2144 2145 /* try to close url-completion */ 2146 ro_gui_url_complete_close(g, pointer->i); 2147 2148 /* Handle Menu clicks */ 2149 if (pointer->buttons == wimp_CLICK_MENU) { 2150 ro_gui_menu_create(browser_toolbar_menu, pointer->pos.x, 2151 pointer->pos.y, g->window); 2152 return true; 2153 } 2154 2155 /* Handle toolbar edits */ 2156 if ((g->toolbar->editor) && (pointer->i < ICON_TOOLBAR_URL)) { 2157 ro_gui_theme_toolbar_editor_click(g->toolbar, pointer); 2158 return true; 2159 } 2160 2161 /* Handle the buttons appropriately */ 2162 switch (pointer->i) { 2163 case ICON_TOOLBAR_BACK: 2164 if (pointer->buttons == wimp_CLICK_ADJUST) { 2165 new_bw = browser_window_create(NULL, 2166 g->bw, NULL, false, false); 2167 ro_gui_menu_handle_action( 2168 new_bw->window->window, 2169 BROWSER_NAVIGATE_BACK, true); 2170 } else { 2171 ro_gui_menu_handle_action(g->window, 2172 BROWSER_NAVIGATE_BACK, true); 2173 } 2174 break; 2175 2176 case ICON_TOOLBAR_FORWARD: 2177 if (pointer->buttons == wimp_CLICK_ADJUST) { 2178 new_bw = browser_window_create(NULL, 2179 g->bw, NULL, false, false); 2180 ro_gui_menu_handle_action( 2181 new_bw->window->window, 2182 BROWSER_NAVIGATE_FORWARD, true); 2183 } else { 2184 ro_gui_menu_handle_action(g->window, 2185 BROWSER_NAVIGATE_FORWARD, true); 2186 } 2187 break; 2188 2189 case ICON_TOOLBAR_STOP: 2190 ro_gui_menu_handle_action(g->window, 2191 BROWSER_NAVIGATE_STOP, true); 2192 break; 2193 2194 case ICON_TOOLBAR_RELOAD: 2195 if (pointer->buttons == wimp_CLICK_SELECT) 2196 ro_gui_menu_handle_action(g->window, 2197 BROWSER_NAVIGATE_RELOAD, true); 2198 else if (pointer->buttons == wimp_CLICK_ADJUST) 2199 ro_gui_menu_handle_action(g->window, 2200 BROWSER_NAVIGATE_RELOAD_ALL, 2201 true); 2202 break; 2203 2204 case ICON_TOOLBAR_HISTORY: 2205 if (pointer->buttons == wimp_CLICK_SELECT) 2206 ro_gui_menu_handle_action(g->window, 2207 HISTORY_SHOW_LOCAL, true); 2208 else 2209 ro_gui_menu_handle_action(g->window, 2210 HISTORY_SHOW_GLOBAL, true); 2211 break; 2212 case ICON_TOOLBAR_HOME: 2213 ro_gui_menu_handle_action(g->window, 2214 BROWSER_NAVIGATE_HOME, true); 2215 break; 2216 case ICON_TOOLBAR_SEARCH: 2217 ro_gui_menu_handle_action(g->window, 2218 BROWSER_FIND_TEXT, true); 2219 break; 2220 case ICON_TOOLBAR_SCALE: 2221 ro_gui_menu_handle_action(g->window, 2222 BROWSER_SCALE_VIEW, true); 2223 break; 2224 2225 case ICON_TOOLBAR_BOOKMARK: 2226 if (pointer->buttons == wimp_CLICK_ADJUST) 2227 ro_gui_menu_handle_action(g->window, 2228 HOTLIST_ADD_URL, true); 2229 else 2230 ro_gui_menu_handle_action(g->window, 2231 HOTLIST_SHOW, true); 2232 break; 2233 2234 case ICON_TOOLBAR_SAVE: 2235 if (pointer->buttons == wimp_CLICK_ADJUST) 2236 ro_gui_menu_handle_action(g->window, 2237 BROWSER_SAVE_COMPLETE, true); 2238 else 2239 ro_gui_menu_handle_action(g->window, 2240 BROWSER_SAVE, true); 2241 break; 2242 case ICON_TOOLBAR_PRINT: 2243 ro_gui_menu_handle_action(g->window, 2244 BROWSER_PRINT, true); 2245 break; 2246 case ICON_TOOLBAR_UP: 2247 if (pointer->buttons == wimp_CLICK_ADJUST) { 2248 if (g->bw && g->bw->current_content) { 2249 hlcache_handle *h = 2250 g->bw->current_content; 2251 new_bw = browser_window_create(NULL, 2252 g->bw, NULL, false, 2253 false); 2254 /* do it without loading the content 2255 * into the new window */ 2256 ro_gui_window_navigate_up( 2257 new_bw->window, 2258 content_get_url(h)); 2259 } 2260 } else { 2261 ro_gui_menu_handle_action(g->window, 2262 BROWSER_NAVIGATE_UP, true); 2263 } 2264 break; 2265 case ICON_TOOLBAR_URL: 2266 if (pointer->buttons & 2267 (wimp_DRAG_SELECT | wimp_DRAG_ADJUST)) { 2268 if (g->bw->current_content) { 2269 hlcache_handle *h = 2270 g->bw->current_content; 2271 gui_save_type save_type; 2272 2273 if (ro_gui_shift_pressed()) 2274 save_type = GUI_SAVE_LINK_URL; 2275 else 2276 save_type = GUI_SAVE_LINK_TEXT; 2277 2278 ro_gui_drag_save_link(save_type, 2279 content_get_url(h), 2280 content_get_title(h), 2281 g); 2282 } 2283 } 2284 else 2285 ro_gui_url_complete_start(g); 2286 break; 2287 case ICON_TOOLBAR_SUGGEST: 2288 ro_gui_popup_menu(url_suggest_menu, 2289 g->toolbar->toolbar_handle, 2290 ICON_TOOLBAR_SUGGEST); 2291 break; 2292 } 2293 return true; 2294} 2295 2296 2297/** 2298 * Handle Mouse_Click events in a browser window. 2299 * 2300 * \param pointer details of mouse click 2301 * \return true if click handled, false otherwise 2302 */ 2303 2304bool ro_gui_window_click(wimp_pointer *pointer) 2305{ 2306 struct gui_window *g; 2307 os_coord pos; 2308 2309 g = (struct gui_window *)ro_gui_wimp_event_get_user_data(pointer->w); 2310 2311 /* try to close url-completion */ 2312 ro_gui_url_complete_close(g, pointer->i); 2313 2314 /* set input focus */ 2315 if (pointer->buttons == wimp_CLICK_SELECT || 2316 pointer->buttons == wimp_CLICK_ADJUST) 2317 gui_window_place_caret(g, -100, -100, 0); 2318 2319 if (pointer->buttons == wimp_CLICK_MENU) { 2320 ro_gui_menu_create(browser_menu, pointer->pos.x, pointer->pos.y, pointer->w); 2321 } else { 2322 if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) 2323 browser_window_mouse_click(g->bw, 2324 ro_gui_mouse_click_state(pointer->buttons), 2325 pos.x, pos.y); 2326 } 2327 return true; 2328} 2329 2330 2331/** 2332 * Process Key_Pressed events in a browser window. 2333 */ 2334 2335bool ro_gui_window_keypress(wimp_key *key) 2336{ 2337 struct gui_window *g; 2338 bool toolbar; 2339 hlcache_handle *h; 2340 wimp_window_state state; 2341 int y; 2342 const char *toolbar_url; 2343 os_error *error; 2344 wimp_pointer pointer; 2345 float scale; 2346 uint32_t c = (uint32_t) key->c; 2347 2348 /* Find gui window */ 2349 if ((g = ro_gui_window_lookup(key->w)) != NULL) { 2350 toolbar = false; 2351 } else if ((g = ro_gui_toolbar_lookup(key->w)) != NULL) { 2352 toolbar = true; 2353 } else { 2354 /* nothing to do with us */ 2355 return false; 2356 } 2357 2358 h = g->bw->current_content; 2359 2360 error = xwimp_get_pointer_info(&pointer); 2361 if (error) { 2362 LOG(("xwimp_get_pointer_info: 0x%x: %s\n", 2363 error->errnum, error->errmess)); 2364 warn_user("WimpError", error->errmess); 2365 return false; 2366 } 2367 2368 /* First send the key to the browser window, eg. form fields. */ 2369 if (!toolbar) { 2370 if ((unsigned)c < 0x20 || (0x7f <= c && c <= 0x9f) || 2371 (c & IS_WIMP_KEY)) { 2372 /* Munge control keys into unused control chars */ 2373 /* We can't map onto 1->26 (reserved for ctrl+<qwerty> 2374 That leaves 27->31 and 128->159 */ 2375 switch (c & ~IS_WIMP_KEY) { 2376 case wimp_KEY_TAB: c = 9; break; 2377 case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break; 2378 2379 /* cursor movement keys */ 2380 case wimp_KEY_HOME: 2381 case wimp_KEY_CONTROL | wimp_KEY_LEFT: 2382 c = KEY_LINE_START; 2383 break; 2384 case wimp_KEY_END: 2385 if (os_version >= RISCOS5) 2386 c = KEY_LINE_END; 2387 else 2388 c = KEY_DELETE_RIGHT; 2389 break; 2390 case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = KEY_LINE_END; break; 2391 case wimp_KEY_CONTROL | wimp_KEY_UP: c = KEY_TEXT_START; break; 2392 case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = KEY_TEXT_END; break; 2393 case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = KEY_WORD_LEFT ; break; 2394 case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = KEY_WORD_RIGHT; break; 2395 case wimp_KEY_SHIFT | wimp_KEY_UP: c = KEY_PAGE_UP; break; 2396 case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = KEY_PAGE_DOWN; break; 2397 case wimp_KEY_LEFT: c = KEY_LEFT; break; 2398 case wimp_KEY_RIGHT: c = KEY_RIGHT; break; 2399 case wimp_KEY_UP: c = KEY_UP; break; 2400 case wimp_KEY_DOWN: c = KEY_DOWN; break; 2401 2402 /* editing */ 2403 case wimp_KEY_CONTROL | wimp_KEY_END: 2404 c = KEY_DELETE_LINE_END; 2405 break; 2406 case wimp_KEY_DELETE: 2407 if (ro_gui_ctrl_pressed()) 2408 c = KEY_DELETE_LINE_START; 2409 else if (os_version < RISCOS5) 2410 c = KEY_DELETE_LEFT; 2411 break; 2412 2413 default: 2414 break; 2415 } 2416 } 2417 2418 if (!(c & IS_WIMP_KEY)) { 2419 if (browser_window_key_press(g->bw, c)) 2420 return true; 2421 } 2422 2423 /* Reset c to incoming character / key code 2424 * as we may have corrupted it above */ 2425 c = (uint32_t) key->c; 2426 } 2427 2428 switch (c) { 2429 case IS_WIMP_KEY + wimp_KEY_F1: /* Help. */ 2430 return ro_gui_menu_handle_action(g->window, 2431 HELP_OPEN_CONTENTS, false); 2432 2433 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F1: 2434 return ro_gui_menu_handle_action(g->window, 2435 BROWSER_PAGE_INFO, false); 2436 2437 case IS_WIMP_KEY + wimp_KEY_F2: 2438 if (!g->toolbar) 2439 return false; 2440 ro_gui_url_complete_close(NULL, 0); 2441 ro_gui_set_icon_string(g->toolbar->toolbar_handle, 2442 ICON_TOOLBAR_URL, "www.", true); 2443 xwimp_set_caret_position(g->toolbar->toolbar_handle, 2444 ICON_TOOLBAR_URL, 0, 0, -1, 4); 2445 ro_gui_url_complete_start(g); 2446 ro_gui_url_complete_keypress(g, wimp_KEY_DOWN); 2447 return true; 2448 2449 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F2: 2450 /* Close window. */ 2451 ro_gui_url_complete_close(NULL, 0); 2452 browser_window_destroy(g->bw); 2453 return true; 2454 2455 case 19: /* Ctrl + S */ 2456 case IS_WIMP_KEY + wimp_KEY_F3: 2457 return ro_gui_menu_handle_action(g->window, 2458 BROWSER_SAVE, false); 2459 2460 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F3: 2461 return ro_gui_menu_handle_action(g->window, 2462 BROWSER_EXPORT_TEXT, false); 2463 2464 case IS_WIMP_KEY + wimp_KEY_SHIFT + wimp_KEY_F3: 2465 return ro_gui_menu_handle_action(g->window, 2466 BROWSER_SAVE_COMPLETE, false); 2467 2468 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_SHIFT + 2469 wimp_KEY_F3: 2470 return ro_gui_menu_handle_action(g->window, 2471 BROWSER_EXPORT_DRAW, false); 2472 2473 case 6: /* Ctrl + F */ 2474 case IS_WIMP_KEY + wimp_KEY_F4: /* Search */ 2475 return ro_gui_menu_handle_action(g->window, 2476 BROWSER_FIND_TEXT, false); 2477 2478 case IS_WIMP_KEY + wimp_KEY_F5: /* Reload */ 2479 return ro_gui_menu_handle_action(g->window, 2480 BROWSER_NAVIGATE_RELOAD, false); 2481 2482 case 18: /* Ctrl+R (Full reload) */ 2483 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F5: 2484 /* Full reload */ 2485 return ro_gui_menu_handle_action(g->window, 2486 BROWSER_NAVIGATE_RELOAD_ALL, false); 2487 2488 case IS_WIMP_KEY + wimp_KEY_F6: /* Hotlist */ 2489 return ro_gui_menu_handle_action(g->window, 2490 HOTLIST_SHOW, false); 2491 2492 case IS_WIMP_KEY + wimp_KEY_F7: /* Show local history */ 2493 return ro_gui_menu_handle_action(g->window, 2494 HISTORY_SHOW_LOCAL, false); 2495 2496 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F7: 2497 /* Show global history */ 2498 return ro_gui_menu_handle_action(g->window, 2499 HISTORY_SHOW_GLOBAL, false); 2500 2501 case IS_WIMP_KEY + wimp_KEY_F8: /* View source */ 2502 ro_gui_view_source(h); 2503 return true; 2504 2505 case IS_WIMP_KEY + wimp_KEY_F9: 2506 /* Dump content for debugging. */ 2507 ro_gui_dump_content(h); 2508 return true; 2509 2510 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F9: 2511 urldb_dump(); 2512 return true; 2513 2514 case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_SHIFT + 2515 wimp_KEY_F9: 2516 talloc_report_full(0, stderr); 2517 return true; 2518 2519 case IS_WIMP_KEY + wimp_KEY_F11: /* Zoom */ 2520 return ro_gui_menu_handle_action(g->window, 2521 BROWSER_SCALE_VIEW, false); 2522 2523 case IS_WIMP_KEY + wimp_KEY_SHIFT + wimp_KEY_F11: 2524 /* Toggle display of box outlines. */ 2525 html_redraw_debug = !html_redraw_debug; 2526 gui_window_redraw_window(g); 2527 return true; 2528 2529 case wimp_KEY_RETURN: 2530 if (!toolbar) 2531 break; 2532 toolbar_url = ro_gui_get_icon_string( 2533 g->toolbar->toolbar_handle, 2534 ICON_TOOLBAR_URL); 2535 ro_gui_window_launch_url(g, toolbar_url); 2536 return true; 2537 2538 case wimp_KEY_ESCAPE: 2539 if (ro_gui_url_complete_close(NULL, 0)) { 2540 ro_gui_url_complete_start(g); 2541 return true; 2542 } 2543 return ro_gui_menu_handle_action(g->window, 2544 BROWSER_NAVIGATE_STOP, false); 2545 2546 case 8: /* CTRL+H / Backspace */ 2547 if (toolbar) 2548 return ro_gui_url_complete_keypress(g, c); 2549 break; 2550 2551 case 14: /* CTRL+N */ 2552 return ro_gui_menu_handle_action(g->window, 2553 BROWSER_NEW_WINDOW, false); 2554 2555 case 17: /* CTRL+Q (Zoom out) */ 2556 case 23: /* CTRL+W (Zoom in) */ 2557 if (!h) 2558 break; 2559 scale = g->bw->scale; 2560 if (ro_gui_shift_pressed() && c == 17) 2561 scale = g->bw->scale - 0.1; 2562 else if (ro_gui_shift_pressed() && c == 23) 2563 scale = g->bw->scale + 0.1; 2564 else if (c == 17) { 2565 for (int i = SCALE_SNAP_TO_SIZE - 1; 2566 i >= 0; i--) 2567 if (scale_snap_to[i] < 2568 g->bw->scale) { 2569 scale = scale_snap_to[i]; 2570 break; 2571 } 2572 } else { 2573 for (unsigned int i = 0; 2574 i < SCALE_SNAP_TO_SIZE; i++) 2575 if (scale_snap_to[i] > 2576 g->bw->scale) { 2577 scale = scale_snap_to[i]; 2578 break; 2579 } 2580 } 2581 if (scale < scale_snap_to[0]) 2582 scale = scale_snap_to[0]; 2583 if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1]) 2584 scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1]; 2585 if (g->bw->scale != scale) { 2586 browser_window_set_scale(g->bw, scale, true); 2587// g->reformat_pending = true; 2588// if ((h) && (content_get_type(h) != CONTENT_HTML)) 2589// browser_window_update(g->bw, false); 2590// browser_reformat_pending = true; 2591 } 2592 return true; 2593 2594 case IS_WIMP_KEY + wimp_KEY_PRINT: 2595 return ro_gui_menu_handle_action(g->window, 2596 BROWSER_PRINT, false); 2597 2598 case IS_WIMP_KEY | wimp_KEY_LEFT: 2599 case IS_WIMP_KEY | wimp_KEY_RIGHT: 2600 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_LEFT: 2601 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_RIGHT: 2602 if (toolbar) 2603 return false; 2604 break; 2605 case IS_WIMP_KEY + wimp_KEY_UP: 2606 case IS_WIMP_KEY + wimp_KEY_DOWN: 2607 case IS_WIMP_KEY + wimp_KEY_PAGE_UP: 2608 case IS_WIMP_KEY + wimp_KEY_PAGE_DOWN: 2609 case wimp_KEY_HOME: 2610 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_UP: 2611 case IS_WIMP_KEY + wimp_KEY_END: 2612 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_DOWN: 2613 if (toolbar) 2614 return ro_gui_url_complete_keypress(g, c); 2615 break; 2616 default: 2617 if (toolbar) 2618 return ro_gui_url_complete_keypress(g, c); 2619 return false; 2620 } 2621 2622 state.w = g->window; 2623 error = xwimp_get_window_state(&state); 2624 if (error) { 2625 LOG(("xwimp_get_window_state: 0x%x: %s", 2626 error->errnum, error->errmess)); 2627 return true; 2628 } 2629 2630 y = state.visible.y1 - state.visible.y0 - 32; 2631 if (g->toolbar) 2632 y -= ro_gui_theme_toolbar_full_height(g->toolbar); 2633 2634 switch (c) { 2635 case IS_WIMP_KEY | wimp_KEY_LEFT: 2636 state.xscroll -= 32; 2637 break; 2638 case IS_WIMP_KEY | wimp_KEY_RIGHT: 2639 state.xscroll += 32; 2640 break; 2641 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_LEFT: 2642 state.xscroll = -0x10000000; 2643 break; 2644 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_RIGHT: 2645 state.xscroll = 0x10000000; 2646 break; 2647 case IS_WIMP_KEY | wimp_KEY_UP: 2648 state.yscroll += 32; 2649 break; 2650 case IS_WIMP_KEY | wimp_KEY_DOWN: 2651 state.yscroll -= 32; 2652 break; 2653 case IS_WIMP_KEY | wimp_KEY_PAGE_UP: 2654 state.yscroll += y; 2655 break; 2656 case IS_WIMP_KEY | wimp_KEY_PAGE_DOWN: 2657 state.yscroll -= y; 2658 break; 2659 case wimp_KEY_HOME: 2660 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_UP: 2661 state.yscroll = 0x10000000; 2662 break; 2663 case IS_WIMP_KEY | wimp_KEY_END: 2664 case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_DOWN: 2665 state.yscroll = -0x10000000; 2666 break; 2667 } 2668 2669 error = xwimp_open_window(PTR_WIMP_OPEN(&state)); 2670 if (error) { 2671 LOG(("xwimp_open_window: 0x%x: %s", 2672 error->errnum, error->errmess)); 2673 } 2674 2675 return true; 2676} 2677 2678 2679/** 2680 * Process Scroll_Request events. 2681 */ 2682void ro_gui_scroll_request(wimp_scroll *scroll) 2683{ 2684 struct gui_window *g = ro_gui_window_lookup(scroll->w); 2685 2686 if (g && g->bw->current_content && ro_gui_shift_pressed()) { 2687 /* extended scroll request with shift held down; change zoom */ 2688 float scale, inc; 2689 2690 if (scroll->ymin & 3) 2691 inc = 0.02; /* RO5 sends the msg 5 times; 2692 * don't ask me why */ 2693 else 2694 inc = (1 << (ABS(scroll->ymin)>>2)) / 20.0F; 2695 2696 if (scroll->ymin > 0) { 2697 scale = g->bw->scale + inc; 2698 if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1]) 2699 scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1]; 2700 } else { 2701 scale = g->bw->scale - inc; 2702 if (scale < scale_snap_to[0]) 2703 scale = scale_snap_to[0]; 2704 } 2705 if (g->bw->scale != scale) 2706 browser_window_set_scale(g->bw, scale, true); 2707 } else { 2708 int x = scroll->visible.x1 - scroll->visible.x0 - 32; 2709 int y = scroll->visible.y1 - scroll->visible.y0 - 32; 2710 os_error *error; 2711 2712 if (g && g->toolbar) 2713 y -= ro_gui_theme_toolbar_full_height(g->toolbar); 2714 2715 switch (scroll->xmin) { 2716 case wimp_SCROLL_PAGE_LEFT: 2717 scroll->xscroll -= x; 2718 break; 2719 case wimp_SCROLL_COLUMN_LEFT: 2720 scroll->xscroll -= 32; 2721 break; 2722 case wimp_SCROLL_COLUMN_RIGHT: 2723 scroll->xscroll += 32; 2724 break; 2725 case wimp_SCROLL_PAGE_RIGHT: 2726 scroll->xscroll += x; 2727 break; 2728 default: 2729 scroll->xscroll += (x * (scroll->xmin>>2)) >> 2; 2730 break; 2731 } 2732 2733 switch (scroll->ymin) { 2734 case wimp_SCROLL_PAGE_UP: 2735 scroll->yscroll += y; 2736 break; 2737 case wimp_SCROLL_LINE_UP: 2738 scroll->yscroll += 32; 2739 break; 2740 case wimp_SCROLL_LINE_DOWN: 2741 scroll->yscroll -= 32; 2742 break; 2743 case wimp_SCROLL_PAGE_DOWN: 2744 scroll->yscroll -= y; 2745 break; 2746 default: 2747 scroll->yscroll += (y * (scroll->ymin>>2)) >> 2; 2748 break; 2749 } 2750 2751 error = xwimp_open_window((wimp_open *) scroll); 2752 if (error) { 2753 LOG(("xwimp_open_window: 0x%x: %s", 2754 error->errnum, error->errmess)); 2755 } 2756 } 2757} 2758 2759 2760/** 2761 * Convert x,y screen co-ordinates into window co-ordinates. 2762 * 2763 * \param g gui window 2764 * \param x x ordinate 2765 * \param y y ordinate 2766 * \param pos receives position in window co-ordinatates 2767 * \return true iff conversion successful 2768 */ 2769 2770bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, 2771 os_coord *pos) 2772{ 2773 wimp_window_state state; 2774 os_error *error; 2775 2776 assert(g); 2777 2778 state.w = g->window; 2779 error = xwimp_get_window_state(&state); 2780 if (error) { 2781 LOG(("xwimp_get_window_state: 0x%x:%s", 2782 error->errnum, error->errmess)); 2783 warn_user("WimpError", error->errmess); 2784 return false; 2785 } 2786 pos->x = (x - (state.visible.x0 - state.xscroll)) / 2 / g->bw->scale; 2787 pos->y = ((state.visible.y1 - state.yscroll) - y) / 2 / g->bw->scale; 2788 return true; 2789} 2790 2791 2792/** 2793 * Convert x,y window co-ordinates into screen co-ordinates. 2794 * 2795 * \param g gui window 2796 * \param x x ordinate 2797 * \param y y ordinate 2798 * \param pos receives position in screen co-ordinatates 2799 * \return true iff conversion successful 2800 */ 2801 2802bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, 2803 os_coord *pos) 2804{ 2805 wimp_window_state state; 2806 os_error *error; 2807 2808 assert(g); 2809 2810 state.w = g->window; 2811 error = xwimp_get_window_state(&state); 2812 if (error) { 2813 LOG(("xwimp_get_window_state: 0x%x:%s", 2814 error->errnum, error->errmess)); 2815 warn_user("WimpError", error->errmess); 2816 return false; 2817 } 2818 pos->x = (x * 2 * g->bw->scale) + (state.visible.x0 - state.xscroll); 2819 pos->y = (state.visible.y1 - state.yscroll) - (y * 2 * g->bw->scale); 2820 return true; 2821} 2822 2823 2824/** 2825 * Handle Message_DataLoad (file dragged in) for a window. 2826 * 2827 * \param g window 2828 * \param message Message_DataLoad block 2829 * \return true if the load was processed 2830 * 2831 * If the file was dragged into a form file input, it is used as the value. 2832 */ 2833 2834bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message) 2835{ 2836 struct box *box; 2837 struct box *file_box = 0; 2838 struct box *text_box = 0; 2839 struct browser_window *bw = g->bw; 2840 hlcache_handle *h; 2841 int box_x, box_y; 2842 os_error *error; 2843 os_coord pos; 2844 2845 h = bw->current_content; 2846 2847 /* HTML content only. */ 2848 if (!bw->current_content || content_get_type(h) != CONTENT_HTML) 2849 return false; 2850 2851 /* Ignore directories etc. */ 2852 if (0x1000 <= message->data.data_xfer.file_type) 2853 return false; 2854 2855 if (!ro_gui_window_to_window_pos(g, message->data.data_xfer.pos.x, 2856 message->data.data_xfer.pos.y, &pos)) 2857 return false; 2858 2859 box = html_get_box_tree(h); 2860 2861 /* Consider the margins of the html page now */ 2862 box_x = box->margin[LEFT]; 2863 box_y = box->margin[TOP]; 2864 2865 while ((box = box_at_point(box, pos.x, pos.y, &box_x, &box_y, &h))) { 2866 if (box->style && css_computed_visibility(box->style) == 2867 CSS_VISIBILITY_HIDDEN) 2868 continue; 2869 2870 if (box->gadget) { 2871 switch (box->gadget->type) { 2872 case GADGET_FILE: 2873 file_box = box; 2874 break; 2875 2876 case GADGET_TEXTBOX: 2877 case GADGET_TEXTAREA: 2878 case GADGET_PASSWORD: 2879 text_box = box; 2880 break; 2881 2882 default: /* appease compiler */ 2883 break; 2884 } 2885 } 2886 } 2887 2888 if (!file_box && !text_box) 2889 return false; 2890 2891 if (file_box) { 2892 utf8_convert_ret ret; 2893 char *utf8_fn; 2894 2895 ret = utf8_from_local_encoding( 2896 message->data.data_xfer.file_name, 0, 2897 &utf8_fn); 2898 if (ret != UTF8_CONVERT_OK) { 2899 /* A bad encoding should never happen */ 2900 assert(ret != UTF8_CONVERT_BADENC); 2901 LOG(("utf8_from_local_encoding failed")); 2902 /* Load was for us - just no memory */ 2903 return true; 2904 } 2905 2906 /* Found: update form input. */ 2907 free(file_box->gadget->value); 2908 file_box->gadget->value = utf8_fn; 2909 2910 /* Redraw box. */ 2911 box_coords(file_box, &pos.x, &pos.y); 2912 gui_window_redraw(bw->window, pos.x, pos.y, 2913 pos.x + file_box->width, 2914 pos.y + file_box->height); 2915 } else { 2916 2917 const char *filename = message->data.data_xfer.file_name; 2918 2919 browser_window_mouse_click(g->bw, BROWSER_MOUSE_PRESS_1, pos.x, pos.y); 2920 2921 if (!ro_gui_window_import_text(g, filename, false)) 2922 return true; /* it was for us, it just didn't work! */ 2923 } 2924 2925 /* send DataLoadAck */ 2926 message->action = message_DATA_LOAD_ACK; 2927 message->your_ref = message->my_ref; 2928 error = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender); 2929 if (error) { 2930 LOG(("xwimp_send_message: 0x%x: %s\n", 2931 error->errnum, error->errmess)); 2932 warn_user("WimpError", error->errmess); 2933 } 2934 2935 return true; 2936} 2937 2938 2939/** 2940 * Handle Message_DataLoad (file dragged in) for a toolbar 2941 * 2942 * \param g window 2943 * \param message Message_DataLoad block 2944 * \return true if the load was processed 2945 */ 2946 2947bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message) 2948{ 2949 if (message->data.data_xfer.file_type == osfile_TYPE_TEXT && 2950 ro_gui_window_import_text(g, message->data.data_xfer.file_name, true)) { 2951 2952 os_error *error; 2953 2954 /* send DataLoadAck */ 2955 message->action = message_DATA_LOAD_ACK; 2956 message->your_ref = message->my_ref; 2957 error = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender); 2958 if (error) { 2959 LOG(("xwimp_send_message: 0x%x: %s\n", 2960 error->errnum, error->errmess)); 2961 warn_user("WimpError", error->errmess); 2962 } 2963 return true; 2964 } 2965 return false; 2966} 2967 2968 2969/** 2970 * Process pending reformats 2971 */ 2972 2973void ro_gui_window_process_reformats(void) 2974{ 2975 struct gui_window *g; 2976 2977 browser_reformat_pending = false; 2978 for (g = window_list; g; g = g->next) { 2979 if (!g->bw->reformat_pending) 2980 continue; 2981 g->bw->reformat_pending = false; 2982 browser_window_reformat(g->bw, 2983 g->old_width / 2, 2984 g->old_height / 2); 2985 } 2986} 2987 2988 2989/** 2990 * Clones a browser window's options. 2991 * 2992 * \param new_bw the new browser window 2993 * \param old_bw the browser window to clone from, or NULL for default 2994 */ 2995 2996void ro_gui_window_clone_options(struct browser_window *new_bw, 2997 struct browser_window *old_bw) { 2998 struct gui_window *old_gui = NULL; 2999 struct gui_window *new_gui; 3000 3001 assert(new_bw); 3002 3003 /* Get our GUIs 3004 */ 3005 new_gui = new_bw->window; 3006 3007 if (old_bw) 3008 old_gui = old_bw->window; 3009 3010 /* Clone the basic options 3011 */ 3012 if (!old_gui) { 3013 new_bw->scale = ((float)option_scale) / 100; 3014 new_gui->option.background_images = option_background_images; 3015 new_gui->option.buffer_animations = option_buffer_animations; 3016 new_gui->option.buffer_everything = option_buffer_everything; 3017 } else { 3018 new_gui->option = old_gui->option; 3019 } 3020 3021 /* Set up the toolbar 3022 */ 3023 if (new_gui->toolbar) { 3024 new_gui->toolbar->display_buttons = option_toolbar_show_buttons; 3025 new_gui->toolbar->display_url = option_toolbar_show_address; 3026 new_gui->toolbar->display_throbber = option_toolbar_show_throbber; 3027 if ((old_gui) && (old_gui->toolbar)) { 3028 new_gui->toolbar->display_buttons = old_gui->toolbar->display_buttons; 3029 new_gui->toolbar->display_url = old_gui->toolbar->display_url; 3030 new_gui->toolbar->display_throbber = old_gui->toolbar->display_throbber; 3031 new_gui->toolbar->reformat_buttons = true; 3032 ro_gui_theme_process_toolbar(new_gui->toolbar, -1); 3033 } 3034 } 3035} 3036 3037 3038/** 3039 * Makes a browser window's options the default. 3040 * 3041 * \param bw the browser window to read options from 3042 */ 3043 3044void ro_gui_window_default_options(struct browser_window *bw) { 3045 struct gui_window *gui; 3046 3047 assert(bw); 3048 3049 /* Get our GUI 3050 */ 3051 gui = bw->window; 3052 if (!gui) return; 3053 3054 /* Save the basic options 3055 */ 3056 option_scale = bw->scale * 100; 3057 option_buffer_animations = gui->option.buffer_animations; 3058 option_buffer_everything = gui->option.buffer_everything; 3059 3060 /* Set up the toolbar 3061 */ 3062 if (gui->toolbar) { 3063 option_toolbar_show_buttons = gui->toolbar->display_buttons; 3064 option_toolbar_show_address = gui->toolbar->display_url; 3065 option_toolbar_show_throbber = gui->toolbar->display_throbber; 3066 } 3067 if (gui->status_bar) 3068 option_toolbar_status_width = ro_gui_status_bar_get_width(gui->status_bar); 3069} 3070 3071 3072 3073 3074/** 3075 * Updates the navigation controls for all toolbars; 3076 * 3077 * \param g the gui_window to launch the URL into 3078 * \param url the URL to launch, or NULL to simply update the suggestion icon 3079 */ 3080void ro_gui_window_prepare_navigate_all(void) { 3081 struct gui_window *g; 3082 3083 for (g = window_list; g; g = g->next) 3084 ro_gui_prepare_navigate(g); 3085} 3086 3087 3088/** 3089 * Returns the state of the mouse buttons and modifiers keys for a 3090 * click/release action, suitable for passing to the OS-independent 3091 * browser window code 3092 */ 3093 3094browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons) 3095{ 3096 browser_mouse_state state = 0; 3097 3098 if (buttons & (wimp_CLICK_SELECT)) 3099 state |= BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1; 3100 if (buttons & (wimp_CLICK_ADJUST)) 3101 state |= BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2; 3102 3103 if (buttons & (wimp_DRAG_SELECT)) { 3104 state |= BROWSER_MOUSE_DRAG_1; 3105 mouse_drag = true; 3106 } 3107 if (buttons & (wimp_DRAG_ADJUST)) { 3108 state |= BROWSER_MOUSE_DRAG_2; 3109 mouse_drag = true; 3110 } 3111 3112 if (ro_gui_shift_pressed()) state |= BROWSER_MOUSE_MOD_1; 3113 if (ro_gui_ctrl_pressed()) state |= BROWSER_MOUSE_MOD_2; 3114 3115 return state; 3116} 3117 3118 3119/** 3120 * Returns the state of the mouse buttons and modifiers keys whilst 3121 * dragging, for passing to the OS-independent browser window code 3122 */ 3123 3124browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons) 3125{ 3126 browser_mouse_state state = 0; 3127 3128 3129 if (buttons & (wimp_CLICK_SELECT)) state |= BROWSER_MOUSE_HOLDING_1; 3130 if (buttons & (wimp_CLICK_ADJUST)) state |= BROWSER_MOUSE_HOLDING_2; 3131 3132 if (!(buttons & (wimp_CLICK_SELECT) || buttons & (wimp_CLICK_ADJUST))) 3133 mouse_drag = false; 3134 if (mouse_drag) state |= BROWSER_MOUSE_DRAG_ON; 3135 3136 if (ro_gui_shift_pressed()) state |= BROWSER_MOUSE_MOD_1; 3137 if (ro_gui_ctrl_pressed()) state |= BROWSER_MOUSE_MOD_2; 3138 3139 return state; 3140} 3141 3142 3143/** 3144 * Returns true iff one or more Shift keys is held down 3145 */ 3146 3147bool ro_gui_shift_pressed(void) 3148{ 3149 int shift = 0; 3150 xosbyte1(osbyte_SCAN_KEYBOARD, 0 ^ 0x80, 0, &shift); 3151 return (shift == 0xff); 3152} 3153 3154 3155/** 3156 * Returns true iff one or more Ctrl keys is held down 3157 */ 3158 3159bool ro_gui_ctrl_pressed(void) 3160{ 3161 int ctrl = 0; 3162 xosbyte1(osbyte_SCAN_KEYBOARD, 1 ^ 0x80, 0, &ctrl); 3163 return (ctrl == 0xff); 3164} 3165 3166 3167/** 3168 * Returns true iff one or more Alt keys is held down 3169 */ 3170 3171bool ro_gui_alt_pressed(void) 3172{ 3173 int alt = 0; 3174 xosbyte1(osbyte_SCAN_KEYBOARD, 2 ^ 0x80, 0, &alt); 3175 return (alt == 0xff); 3176} 3177 3178 3179/** 3180 * Completes scrolling of a browser window 3181 * 3182 * \param g gui window 3183 */ 3184 3185void ro_gui_window_scroll_end(struct gui_window *g, wimp_dragged *drag) 3186{ 3187 wimp_pointer pointer; 3188 os_error *error; 3189 os_coord pos; 3190 3191 gui_current_drag_type = GUI_DRAG_NONE; 3192 if (!g) 3193 return; 3194 3195 error = xwimp_drag_box((wimp_drag*)-1); 3196 if (error) { 3197 LOG(("xwimp_drag_box: 0x%x : %s", 3198 error->errnum, error->errmess)); 3199 warn_user("WimpError", error->errmess); 3200 } 3201 3202 error = xwimp_get_pointer_info(&pointer); 3203 if (error) { 3204 LOG(("xwimp_get_pointer_info 0x%x : %s", 3205 error->errnum, error->errmess)); 3206 warn_user("WimpError", error->errmess); 3207 return; 3208 } 3209 3210 error = xwimpspriteop_set_pointer_shape("ptr_default", 0x31, 0, 0, 0, 0); 3211 if (error) { 3212 LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s", 3213 error->errnum, error->errmess)); 3214 warn_user("WimpError", error->errmess); 3215 } 3216 3217 if (ro_gui_window_to_window_pos(g, drag->final.x0, drag->final.y0, &pos)) 3218 browser_window_mouse_drag_end(g->bw, 3219 ro_gui_mouse_click_state(pointer.buttons), 3220 pos.x, pos.y); 3221} 3222 3223 3224/** 3225 * Completes resizing of a browser frame 3226 * 3227 * \param g gui window 3228 */ 3229 3230void ro_gui_window_frame_resize_end(struct gui_window *g, wimp_dragged *drag) 3231{ 3232 /* our clean-up is the same as for page scrolling */ 3233 ro_gui_window_scroll_end(g, drag); 3234} 3235 3236/** 3237 * Import text file into window or its toolbar 3238 * 3239 * \param g gui window containing textarea 3240 * \param filename pathname of file to be imported 3241 * \param toolbar true iff imported to toolbar rather than main window 3242 * \return true iff successful 3243 */ 3244 3245bool ro_gui_window_import_text(struct gui_window *g, const char *filename, 3246 bool toolbar) 3247{ 3248 fileswitch_object_type obj_type; 3249 os_error *error; 3250 char *buf, *utf8_buf; 3251 int size; 3252 utf8_convert_ret ret; 3253 3254 error = xosfile_read_stamped(filename, &obj_type, NULL, NULL, 3255 &size, NULL, NULL); 3256 if (error) { 3257 LOG(("xosfile_read_stamped: 0x%x:%s", 3258 error->errnum, error->errmess)); 3259 warn_user("FileError", error->errmess); 3260 return true; /* was for us, but it didn't work! */ 3261 } 3262 3263 buf = malloc(size); 3264 if (!buf) { 3265 warn_user("NoMemory", NULL); 3266 return true; 3267 } 3268 3269 error = xosfile_load_stamped(filename, (byte*)buf, 3270 NULL, NULL, NULL, NULL, NULL); 3271 if (error) { 3272 LOG(("xosfile_load_stamped: 0x%x:%s", 3273 error->errnum, error->errmess)); 3274 warn_user("LoadError", error->errmess); 3275 free(buf); 3276 return true; 3277 } 3278 3279 ret = utf8_from_local_encoding(buf, size, &utf8_buf); 3280 if (ret != UTF8_CONVERT_OK) { 3281 /* bad encoding shouldn't happen */ 3282 assert(ret != UTF8_CONVERT_BADENC); 3283 LOG(("utf8_from_local_encoding failed")); 3284 free(buf); 3285 warn_user("NoMemory", NULL); 3286 return true; 3287 } 3288 size = strlen(utf8_buf); 3289 3290 if (toolbar) { 3291 const char *ep = utf8_buf + size; 3292 const char *sp; 3293 char *p = utf8_buf; 3294 3295 /* skip leading whitespace */ 3296 while (isspace(*p)) p++; 3297 3298 sp = p; 3299 while (*p && *p != '\r' && *p != '\n') 3300 p += utf8_next(p, ep - p, 0); 3301 *p = '\0'; 3302 3303 if (p > sp) 3304 ro_gui_window_launch_url(g, sp); 3305 } 3306 else 3307 browser_window_paste_text(g->bw, utf8_buf, size, true); 3308 3309 free(buf); 3310 free(utf8_buf); 3311 return true; 3312} 3313 3314 3315/** 3316 * Window is being iconised. Create a suitable thumbnail sprite 3317 * (which, sadly, must be in the Wimp sprite pool), and return 3318 * the sprite name and truncated title to the iconiser 3319 * 3320 * \param g the gui window being iconised 3321 * \param wi the WindowInfo message from the iconiser 3322 */ 3323 3324void ro_gui_window_iconise(struct gui_window *g, 3325 wimp_full_message_window_info *wi) 3326{ 3327 /* sadly there is no 'legal' way to get the sprite into 3328 * the Wimp sprite pool other than via a filing system */ 3329 const char *temp_fname = "Pipe:$._tmpfile"; 3330 struct browser_window *bw = g->bw; 3331 osspriteop_header *overlay = NULL; 3332 osspriteop_header *sprite_header; 3333 struct bitmap *bitmap; 3334 osspriteop_area *area; 3335 int width = 34, height = 34; 3336 hlcache_handle *h; 3337 os_error *error; 3338 int len, id; 3339 3340 assert(bw); 3341 3342 h = bw->current_content; 3343 if (!h) return; 3344 3345 /* if an overlay sprite is defined, locate it and gets its dimensions 3346 * so that we can produce a thumbnail with the same dimensions */ 3347 if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) { 3348 error = xosspriteop_read_sprite_info(osspriteop_PTR, 3349 (osspriteop_area *)0x100, 3350 (osspriteop_id)overlay, &width, &height, NULL, 3351 NULL); 3352 if (error) { 3353 LOG(("xosspriteop_read_sprite_info: 0x%x: %s", 3354 error->errnum, error->errmess)); 3355 warn_user("MiscError", error->errmess); 3356 overlay = NULL; 3357 } 3358 else if (sprite_bpp(overlay) != 8) { 3359 LOG(("overlay sprite is not 8bpp")); 3360 overlay = NULL; 3361 } 3362 } 3363 3364 /* create the thumbnail sprite */ 3365 bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE | 3366 BITMAP_CLEAR_MEMORY); 3367 if (!bitmap) { 3368 LOG(("Thumbnail initialisation failed.")); 3369 return; 3370 } 3371 thumbnail_create(h, bitmap, NULL); 3372 if (overlay) 3373 bitmap_overlay_sprite(bitmap, overlay); 3374 area = thumbnail_convert_8bpp(bitmap); 3375 bitmap_destroy(bitmap); 3376 if (!area) { 3377 LOG(("Thumbnail conversion failed.")); 3378 return; 3379 } 3380 3381 /* choose a suitable sprite name */ 3382 id = 0; 3383 while (iconise_used[id]) 3384 if ((unsigned)++id >= NOF_ELEMENTS(iconise_used)) { 3385 id = iconise_next; 3386 if ((unsigned)++iconise_next >= 3387 NOF_ELEMENTS(iconise_used)) 3388 iconise_next = 0; 3389 break; 3390 } 3391 3392 sprite_header = (osspriteop_header *)(area + 1); 3393 len = sprintf(sprite_header->name, "ic_netsf%.2d", id); 3394 3395 error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, 3396 area, temp_fname); 3397 if (error) { 3398 LOG(("xosspriteop_save_sprite_file: 0x%x:%s", 3399 error->errnum, error->errmess)); 3400 warn_user("MiscError", error->errmess); 3401 free(area); 3402 return; 3403 } 3404 3405 error = xwimpspriteop_merge_sprite_file(temp_fname); 3406 if (error) { 3407 LOG(("xwimpspriteop_merge_sprite_file: 0x%x:%s", 3408 error->errnum, error->errmess)); 3409 warn_user("WimpError", error->errmess); 3410 remove(temp_fname); 3411 free(area); 3412 return; 3413 } 3414 3415 memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */ 3416 strncpy(wi->title, g->title, sizeof(wi->title)); 3417 wi->title[sizeof(wi->title) - 1] = '\0'; 3418 3419 if (wimptextop_string_width(wi->title, 0) > 182) { 3420 /* work around bug in Pinboard where it will fail to display 3421 * the icon if the text is very wide */ 3422 if (strlen(wi->title) > 10) 3423 wi->title[10] = '\0'; /* pinboard does this anyway */ 3424 while (wimptextop_string_width(wi->title, 0) > 182) 3425 wi->title[strlen(wi->title) - 1] = '\0'; 3426 } 3427 3428 wi->size = sizeof(wimp_full_message_window_info); 3429 wi->your_ref = wi->my_ref; 3430 error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi, 3431 wi->sender); 3432 if (error) { 3433 LOG(("xwimp_send_message: 0x%x:%s", 3434 error->errnum, error->errmess)); 3435 warn_user("WimpError", error->errmess); 3436 } 3437 else { 3438 g->iconise_icon = id; 3439 iconise_used[id] = true; 3440 } 3441 3442 free(area); 3443} 3444 3445 3446/** 3447 * Navigate up one level 3448 * 3449 * \param g the gui_window to open the parent link in 3450 * \param url the URL to open the parent of 3451 */ 3452bool ro_gui_window_navigate_up(struct gui_window *g, const char *url) { 3453 char *parent; 3454 url_func_result res; 3455 bool compare; 3456 3457 if (!g || (!g->bw)) 3458 return false; 3459 3460 res = url_parent(url, &parent); 3461 if (res == URL_FUNC_OK) { 3462 res = url_compare(url, parent, false, &compare); 3463 if ((res == URL_FUNC_OK) && !compare) 3464 browser_window_go(g->bw, parent, 0, true); 3465 free(parent); 3466 } 3467 return true; 3468}