/peek-build/src/netsurf/riscos/window.c
C | 3468 lines | 2449 code | 479 blank | 540 comment | 481 complexity | fc8bb1d57c292c3e32af2212245e1337 MD5 | raw file
Large files files are truncated, but you can click here to view the full 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.…
Large files files are truncated, but you can click here to view the full file