PageRenderTime 11ms CodeModel.GetById 10ms app.highlight 131ms RepoModel.GetById 1ms app.codeStats 1ms

/peek-build/src/netsurf/riscos/window.c

https://bitbucket.org/C0deMaver1ck/peeklinux
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