PageRenderTime 74ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/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
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0

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. /** \file
  24. * Browser window handling (implementation).
  25. */
  26. #include <assert.h>
  27. #include <ctype.h>
  28. #include <inttypes.h>
  29. #include <math.h>
  30. #include <stdio.h>
  31. #include <stdbool.h>
  32. #include <time.h>
  33. #include <string.h>
  34. #include "oslib/colourtrans.h"
  35. #include "oslib/osbyte.h"
  36. #include "oslib/osfile.h"
  37. #include "oslib/osspriteop.h"
  38. #include "oslib/wimp.h"
  39. #include "oslib/wimpspriteop.h"
  40. #include "utils/config.h"
  41. #include "content/content.h"
  42. #include "content/hlcache.h"
  43. #include "content/urldb.h"
  44. #include "css/css.h"
  45. #include "desktop/browser.h"
  46. #include "desktop/frames.h"
  47. #include "desktop/mouse.h"
  48. #include "desktop/plotters.h"
  49. #include "desktop/textinput.h"
  50. #include "desktop/tree.h"
  51. #include "desktop/gui.h"
  52. #include "render/box.h"
  53. #include "render/form.h"
  54. #include "riscos/bitmap.h"
  55. #include "riscos/buffer.h"
  56. #include "riscos/dialog.h"
  57. #include "riscos/global_history.h"
  58. #include "riscos/gui.h"
  59. #include "riscos/gui/status_bar.h"
  60. #include "riscos/menus.h"
  61. #include "riscos/options.h"
  62. #include "riscos/oslib_pre7.h"
  63. #include "riscos/save.h"
  64. #include "riscos/sprite.h"
  65. #include "riscos/theme.h"
  66. #include "riscos/thumbnail.h"
  67. #include "riscos/url_complete.h"
  68. #include "riscos/wimp.h"
  69. #include "riscos/wimp_event.h"
  70. #include "riscos/wimputils.h"
  71. #include "utils/log.h"
  72. #include "utils/talloc.h"
  73. #include "utils/url.h"
  74. #include "utils/utf8.h"
  75. #include "utils/utils.h"
  76. #include "utils/messages.h"
  77. #ifndef wimp_KEY_END
  78. #define wimp_KEY_END wimp_KEY_COPY
  79. #endif
  80. #ifndef wimp_WINDOW_GIVE_SHADED_ICON_INFO
  81. /* RISC OS 5+. Requires OSLib trunk. */
  82. #define wimp_WINDOW_GIVE_SHADED_ICON_INFO ((wimp_extra_window_flags) 0x10u)
  83. #endif
  84. #define SCROLL_VISIBLE_PADDING 32
  85. /** Remembers which iconised sprite numbers are in use */
  86. static bool iconise_used[64];
  87. static int iconise_next = 0;
  88. /** Whether a pressed mouse button has become a drag */
  89. static bool mouse_drag;
  90. /** List of all browser windows. */
  91. static struct gui_window *window_list = 0;
  92. /** GUI window which is being redrawn. Valid only during redraw. */
  93. struct gui_window *ro_gui_current_redraw_gui;
  94. static float scale_snap_to[] = {0.10, 0.125, 0.25, 0.333, 0.5, 0.75,
  95. 1.0,
  96. 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 12.0, 16.0};
  97. #define SCALE_SNAP_TO_SIZE (sizeof scale_snap_to) / (sizeof(float))
  98. /** An entry in ro_gui_pointer_table. */
  99. struct ro_gui_pointer_entry {
  100. bool wimp_area; /** The pointer is in the Wimp's sprite area. */
  101. char sprite_name[16];
  102. int xactive;
  103. int yactive;
  104. };
  105. /** Map from gui_pointer_shape to pointer sprite data. Must be ordered as
  106. * enum gui_pointer_shape. */
  107. struct ro_gui_pointer_entry ro_gui_pointer_table[] = {
  108. { true, "ptr_default", 0, 0 },
  109. { false, "ptr_point", 6, 0 },
  110. { false, "ptr_caret", 4, 9 },
  111. { false, "ptr_menu", 6, 4 },
  112. { false, "ptr_ud", 6, 7 },
  113. { false, "ptr_ud", 6, 7 },
  114. { false, "ptr_lr", 7, 6 },
  115. { false, "ptr_lr", 7, 6 },
  116. { false, "ptr_ld", 7, 7 },
  117. { false, "ptr_ld", 7, 7 },
  118. { false, "ptr_rd", 7, 7 },
  119. { false, "ptr_rd", 6, 7 },
  120. { false, "ptr_cross", 7, 7 },
  121. { false, "ptr_move", 8, 0 },
  122. { false, "ptr_wait", 7, 10 },
  123. { false, "ptr_help", 0, 0 },
  124. { false, "ptr_nodrop", 0, 0 },
  125. { false, "ptr_nt_allwd", 10, 10 },
  126. { false, "ptr_progress", 0, 0 },
  127. };
  128. static void ro_gui_window_remove_update_boxes(struct gui_window *g);
  129. static void gui_window_set_extent(struct gui_window *g, int width, int height);
  130. static void ro_gui_window_open(wimp_open *open);
  131. static void ro_gui_window_close(wimp_w w);
  132. static void ro_gui_window_redraw(wimp_draw *redraw);
  133. static bool ro_gui_window_click(wimp_pointer *mouse);
  134. static bool ro_gui_window_keypress(wimp_key *key);
  135. static void ro_gui_window_launch_url(struct gui_window *g, const char *url);
  136. static void ro_gui_window_clone_options(struct browser_window *new_bw,
  137. struct browser_window *old_bw);
  138. static browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons);
  139. static bool ro_gui_window_import_text(struct gui_window *g,
  140. const char *filename, bool toolbar);
  141. struct update_box {
  142. int x0;
  143. int y0;
  144. int x1;
  145. int y1;
  146. bool use_buffer;
  147. struct gui_window *g;
  148. union content_msg_data data;
  149. struct update_box *next;
  150. };
  151. struct update_box *pending_updates;
  152. #define MARGIN 4
  153. /**
  154. * Create and open a new browser window.
  155. *
  156. * \param bw browser_window structure to update
  157. * \param clone the browser window to clone options from, or NULL for default
  158. * \return gui_window, or 0 on error and error reported
  159. */
  160. struct gui_window *gui_create_browser_window(struct browser_window *bw,
  161. struct browser_window *clone, bool new_tab)
  162. {
  163. int screen_width, screen_height, win_width, win_height, scroll_width;
  164. static int window_count = 2;
  165. wimp_window window;
  166. wimp_window_state state;
  167. os_error *error;
  168. bool open_centred = true;
  169. struct gui_window *g;
  170. struct browser_window *top;
  171. g = malloc(sizeof *g);
  172. if (!g) {
  173. warn_user("NoMemory", 0);
  174. return 0;
  175. }
  176. g->bw = bw;
  177. g->toolbar = 0;
  178. g->status_bar = 0;
  179. g->old_width = 0;
  180. g->old_height = 0;
  181. g->update_extent = true;
  182. strcpy(g->title, "NetSurf");
  183. g->throbber = 0;
  184. g->throbtime = 0;
  185. g->iconise_icon = -1;
  186. /* Set the window position */
  187. if (bw->parent) {
  188. window.visible.x0 = 0;
  189. window.visible.x1 = 64;
  190. window.visible.y0 = 0;
  191. window.visible.y1 = 64;
  192. open_centred = false;
  193. } else if (clone && clone->window && option_window_size_clone) {
  194. for (top = clone; top->parent; top = top->parent);
  195. state.w = top->window->window;
  196. error = xwimp_get_window_state(&state);
  197. if (error) {
  198. LOG(("xwimp_get_window_state: 0x%x: %s",
  199. error->errnum, error->errmess));
  200. warn_user("WimpError", error->errmess);
  201. }
  202. window.visible.x0 = state.visible.x0;
  203. window.visible.x1 = state.visible.x1;
  204. window.visible.y0 = state.visible.y0 - 48;
  205. window.visible.y1 = state.visible.y1 - 48;
  206. open_centred = false;
  207. } else {
  208. ro_gui_screen_size(&screen_width, &screen_height);
  209. /* Check if we have a preferred position */
  210. if ((option_window_screen_width != 0) &&
  211. (option_window_screen_height != 0)) {
  212. win_width = (option_window_width * screen_width) /
  213. option_window_screen_width;
  214. win_height = (option_window_height * screen_height) /
  215. option_window_screen_height;
  216. window.visible.x0 = (option_window_x * screen_width) /
  217. option_window_screen_width;
  218. window.visible.y0 = (option_window_y * screen_height) /
  219. option_window_screen_height;
  220. if (option_window_stagger) {
  221. window.visible.y0 += 96 -
  222. (48 * (window_count % 5));
  223. }
  224. open_centred = false;
  225. if (win_width < 100)
  226. win_width = 100;
  227. if (win_height < 100)
  228. win_height = 100;
  229. } else {
  230. /* Base how we define the window height/width
  231. on the compile time options set */
  232. win_width = screen_width * 3 / 4;
  233. if (1600 < win_width)
  234. win_width = 1600;
  235. win_height = win_width * 3 / 4;
  236. window.visible.x0 = (screen_width - win_width) / 2;
  237. window.visible.y0 = ((screen_height - win_height) / 2) +
  238. 96 - (48 * (window_count % 5));
  239. }
  240. window.visible.x1 = window.visible.x0 + win_width;
  241. window.visible.y1 = window.visible.y0 + win_height;
  242. }
  243. /* General flags for a non-movable, non-resizable, no-title bar window */
  244. window.xscroll = 0;
  245. window.yscroll = 0;
  246. window.next = wimp_TOP;
  247. window.flags = wimp_WINDOW_MOVEABLE |
  248. wimp_WINDOW_NEW_FORMAT |
  249. wimp_WINDOW_VSCROLL |
  250. wimp_WINDOW_HSCROLL |
  251. wimp_WINDOW_IGNORE_XEXTENT |
  252. wimp_WINDOW_IGNORE_YEXTENT |
  253. wimp_WINDOW_SCROLL_REPEAT;
  254. window.title_fg = wimp_COLOUR_BLACK;
  255. window.title_bg = wimp_COLOUR_LIGHT_GREY;
  256. window.work_fg = wimp_COLOUR_LIGHT_GREY;
  257. window.work_bg = wimp_COLOUR_TRANSPARENT;
  258. window.scroll_outer = wimp_COLOUR_DARK_GREY;
  259. window.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY;
  260. window.highlight_bg = wimp_COLOUR_CREAM;
  261. window.extra_flags = wimp_WINDOW_USE_EXTENDED_SCROLL_REQUEST |
  262. wimp_WINDOW_GIVE_SHADED_ICON_INFO;
  263. window.extent.x0 = 0;
  264. window.extent.y0 = -(window.visible.y1 - window.visible.y0);
  265. window.extent.x1 = window.visible.x1 - window.visible.x0;
  266. window.extent.y1 = 0;
  267. window.title_flags = wimp_ICON_TEXT |
  268. wimp_ICON_INDIRECTED |
  269. wimp_ICON_HCENTRED;
  270. window.work_flags = wimp_BUTTON_CLICK_DRAG <<
  271. wimp_ICON_BUTTON_TYPE_SHIFT;
  272. window.sprite_area = wimpspriteop_AREA;
  273. window.xmin = 1;
  274. window.ymin = 1;
  275. window.title_data.indirected_text.text = g->title;
  276. window.title_data.indirected_text.validation = (char *) -1;
  277. window.title_data.indirected_text.size = 255;
  278. window.icon_count = 0;
  279. /* Add in flags for our window type */
  280. switch (bw->browser_window_type) {
  281. case BROWSER_WINDOW_FRAMESET:
  282. window.flags &= ~(wimp_WINDOW_VSCROLL |
  283. wimp_WINDOW_HSCROLL);
  284. window.title_fg = 0xff;
  285. break;
  286. case BROWSER_WINDOW_IFRAME:
  287. window.flags |= wimp_WINDOW_NO_BOUNDS;
  288. case BROWSER_WINDOW_FRAME:
  289. if (bw->scrolling == SCROLLING_NO)
  290. window.flags &= ~(wimp_WINDOW_VSCROLL |
  291. wimp_WINDOW_HSCROLL);
  292. if (bw->scrolling == SCROLLING_AUTO)
  293. window.flags &= ~wimp_WINDOW_HSCROLL;
  294. if (!bw->border)
  295. window.title_fg = 0xff;
  296. else {
  297. /* set the correct border colour */
  298. unsigned int col;
  299. col = bw->border_colour & 0xffffff;
  300. sprintf(g->validation, "C%.6x", col);
  301. window.extra_flags |= wimp_WINDOW_USE_TITLE_VALIDATION_STRING;
  302. window.title_data.indirected_text.validation = g->validation;
  303. }
  304. break;
  305. case BROWSER_WINDOW_NORMAL:
  306. window.flags |= wimp_WINDOW_SIZE_ICON |
  307. wimp_WINDOW_BACK_ICON |
  308. wimp_WINDOW_CLOSE_ICON |
  309. wimp_WINDOW_TITLE_ICON |
  310. wimp_WINDOW_TOGGLE_ICON;
  311. break;
  312. }
  313. if (open_centred) {
  314. scroll_width = ro_get_vscroll_width(NULL);
  315. window.visible.x0 -= scroll_width;
  316. }
  317. error = xwimp_create_window(&window, &g->window);
  318. if (error) {
  319. LOG(("xwimp_create_window: 0x%x: %s",
  320. error->errnum, error->errmess));
  321. warn_user("WimpError", error->errmess);
  322. free(g);
  323. return 0;
  324. }
  325. /* Link into window list */
  326. g->prev = 0;
  327. g->next = window_list;
  328. if (window_list)
  329. window_list->prev = g;
  330. window_list = g;
  331. window_count++;
  332. /* Add in a toolbar and status bar */
  333. if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) {
  334. g->status_bar = ro_gui_status_bar_create(g->window, option_toolbar_status_width);
  335. g->toolbar = ro_gui_theme_create_toolbar(NULL, THEME_BROWSER_TOOLBAR);
  336. ro_gui_theme_attach_toolbar(g->toolbar, g->window);
  337. } else {
  338. g->toolbar = NULL;
  339. }
  340. /* Set the window options */
  341. bw->window = g;
  342. ro_gui_window_clone_options(bw, clone);
  343. ro_gui_prepare_navigate(g);
  344. /* Register event handlers */
  345. ro_gui_wimp_event_set_user_data(g->window, g);
  346. ro_gui_wimp_event_register_open_window(g->window, ro_gui_window_open);
  347. ro_gui_wimp_event_register_close_window(g->window, ro_gui_window_close);
  348. ro_gui_wimp_event_register_redraw_window(g->window, ro_gui_window_redraw);
  349. ro_gui_wimp_event_register_keypress(g->window, ro_gui_window_keypress);
  350. if (g->toolbar)
  351. ro_gui_wimp_event_register_keypress(g->toolbar->toolbar_handle,
  352. ro_gui_window_keypress);
  353. ro_gui_wimp_event_register_mouse_click(g->window, ro_gui_window_click);
  354. /* Open the window at the top of the stack */
  355. state.w = g->window;
  356. error = xwimp_get_window_state(&state);
  357. if (error) {
  358. LOG(("xwimp_get_window_state: 0x%x: %s",
  359. error->errnum, error->errmess));
  360. warn_user("WimpError", error->errmess);
  361. return g;
  362. }
  363. state.next = wimp_TOP;
  364. if (bw->parent) {
  365. top = browser_window_owner(bw);
  366. error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
  367. top->window->window,
  368. wimp_CHILD_LINKS_PARENT_WORK_AREA
  369. << wimp_CHILD_XORIGIN_SHIFT |
  370. wimp_CHILD_LINKS_PARENT_WORK_AREA
  371. << wimp_CHILD_YORIGIN_SHIFT);
  372. if (error) {
  373. LOG(("xwimp_open_window_nested: 0x%x: %s",
  374. error->errnum, error->errmess));
  375. warn_user("WimpError", error->errmess);
  376. }
  377. }
  378. ro_gui_window_open(PTR_WIMP_OPEN(&state));
  379. /* Claim the caret for top-level windows */
  380. if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) {
  381. if (g->toolbar && g->toolbar->display_url) {
  382. error = xwimp_set_caret_position(
  383. g->toolbar->toolbar_handle,
  384. ICON_TOOLBAR_URL, -1, -1, -1, 0);
  385. ro_gui_url_complete_start(g);
  386. if (error) {
  387. LOG(("xwimp_set_caret_position: 0x%x: %s",
  388. error->errnum, error->errmess));
  389. warn_user("WimpError", error->errmess);
  390. }
  391. } else
  392. gui_window_place_caret(g, -100, -100, 0);
  393. }
  394. return g;
  395. }
  396. /**
  397. * Close a browser window and free any related resources.
  398. *
  399. * \param g gui_window to destroy
  400. */
  401. void gui_window_destroy(struct gui_window *g)
  402. {
  403. os_error *error;
  404. wimp_w w;
  405. assert(g);
  406. /* stop any tracking */
  407. if (gui_track_gui_window == g) {
  408. gui_track_gui_window = NULL;
  409. gui_current_drag_type = GUI_DRAG_NONE;
  410. }
  411. /* remove from list */
  412. if (g->prev)
  413. g->prev->next = g->next;
  414. else
  415. window_list = g->next;
  416. if (g->next)
  417. g->next->prev = g->prev;
  418. /* destroy toolbar */
  419. if (g->toolbar)
  420. ro_gui_theme_destroy_toolbar(g->toolbar);
  421. if (g->status_bar)
  422. ro_gui_status_bar_destroy(g->status_bar);
  423. w = g->window;
  424. ro_gui_url_complete_close(NULL, 0);
  425. ro_gui_dialog_close_persistent(w);
  426. if (current_menu_window == w)
  427. ro_gui_menu_closed(true);
  428. ro_gui_window_remove_update_boxes(g);
  429. /* delete window */
  430. error = xwimp_delete_window(w);
  431. if (error) {
  432. LOG(("xwimp_delete_window: 0x%x: %s",
  433. error->errnum, error->errmess));
  434. warn_user("WimpError", error->errmess);
  435. }
  436. ro_gui_wimp_event_finalise(w);
  437. free(g);
  438. }
  439. /**
  440. * Set the title of a browser window.
  441. *
  442. * \param g gui_window to update
  443. * \param title new window title, copied
  444. */
  445. void gui_window_set_title(struct gui_window *g, const char *title)
  446. {
  447. int scale_disp;
  448. assert(g);
  449. assert(title);
  450. if (g->bw->scale != 1.0) {
  451. scale_disp = g->bw->scale * 100;
  452. if (ABS((float)scale_disp - g->bw->scale * 100) >= 0.05)
  453. snprintf(g->title, sizeof g->title, "%s (%.1f%%)",
  454. title, g->bw->scale * 100);
  455. else
  456. snprintf(g->title, sizeof g->title, "%s (%i%%)",
  457. title, scale_disp);
  458. } else {
  459. strncpy(g->title, title, sizeof g->title);
  460. }
  461. /* only top-level parents have titlebars */
  462. if (!g->bw->parent)
  463. ro_gui_set_window_title(g->window, g->title);
  464. }
  465. /**
  466. * Force a redraw of part of the contents of a browser window.
  467. *
  468. * \param g gui_window to redraw
  469. * \param x0 rectangle to redraw
  470. * \param y0 rectangle to redraw
  471. * \param x1 rectangle to redraw
  472. * \param y1 rectangle to redraw
  473. */
  474. void gui_window_redraw(struct gui_window *g, int x0, int y0, int x1, int y1)
  475. {
  476. os_error *error;
  477. assert(g);
  478. error = xwimp_force_redraw(g->window, x0 * 2, -y1 * 2, x1 * 2, -y0 * 2);
  479. if (error) {
  480. LOG(("xwimp_force_redraw: 0x%x: %s",
  481. error->errnum, error->errmess));
  482. warn_user("WimpError", error->errmess);
  483. }
  484. }
  485. /**
  486. * Force a redraw of the entire contents of a browser window.
  487. *
  488. * \param g gui_window to redraw
  489. */
  490. void gui_window_redraw_window(struct gui_window *g)
  491. {
  492. wimp_window_info info;
  493. os_error *error;
  494. assert(g);
  495. info.w = g->window;
  496. error = xwimp_get_window_info_header_only(&info);
  497. if (error) {
  498. LOG(("xwimp_get_window_info_header_only: 0x%x: %s",
  499. error->errnum, error->errmess));
  500. warn_user("WimpError", error->errmess);
  501. return;
  502. }
  503. error = xwimp_force_redraw(g->window, info.extent.x0, info.extent.y0,
  504. info.extent.x1, info.extent.y1);
  505. if (error) {
  506. LOG(("xwimp_force_redraw: 0x%x: %s",
  507. error->errnum, error->errmess));
  508. warn_user("WimpError", error->errmess);
  509. }
  510. }
  511. /**
  512. * Redraw an area of a window.
  513. *
  514. * \param g gui_window
  515. * \param data content_msg_data union with filled in redraw data
  516. */
  517. void gui_window_update_box(struct gui_window *g,
  518. const union content_msg_data *data)
  519. {
  520. hlcache_handle *h = g->bw->current_content;
  521. bool use_buffer;
  522. int x0, y0, x1, y1;
  523. struct update_box *cur;
  524. if (!h)
  525. return;
  526. x0 = floorf(data->redraw.x * 2 * g->bw->scale);
  527. y0 = -ceilf((data->redraw.y + data->redraw.height) * 2 * g->bw->scale);
  528. x1 = ceilf((data->redraw.x + data->redraw.width) * 2 * g->bw->scale) + 1;
  529. y1 = -floorf(data->redraw.y * 2 * g->bw->scale) + 1;
  530. use_buffer =
  531. (g->option.buffer_everything || g->option.buffer_animations);
  532. /* try to optimise buffered redraws */
  533. if (use_buffer) {
  534. for (cur = pending_updates; cur != NULL; cur = cur->next) {
  535. if ((cur->g != g) || (!cur->use_buffer))
  536. continue;
  537. if ((((cur->x0 - x1) < MARGIN) || ((cur->x1 - x0) < MARGIN)) &&
  538. (((cur->y0 - y1) < MARGIN) || ((cur->y1 - y0) < MARGIN))) {
  539. cur->x0 = min(cur->x0, x0);
  540. cur->y0 = min(cur->y0, y0);
  541. cur->x1 = max(cur->x1, x1);
  542. cur->y1 = max(cur->y1, y1);
  543. return;
  544. }
  545. }
  546. }
  547. cur = malloc(sizeof(struct update_box));
  548. if (!cur) {
  549. LOG(("No memory for malloc."));
  550. warn_user("NoMemory", 0);
  551. return;
  552. }
  553. cur->x0 = x0;
  554. cur->y0 = y0;
  555. cur->x1 = x1;
  556. cur->y1 = y1;
  557. cur->next = pending_updates;
  558. pending_updates = cur;
  559. cur->g = g;
  560. cur->use_buffer = use_buffer;
  561. cur->data = *data;
  562. }
  563. /**
  564. * Get the scroll position of a browser window.
  565. *
  566. * \param g gui_window
  567. * \param sx receives x ordinate of point at top-left of window
  568. * \param sy receives y ordinate of point at top-left of window
  569. * \return true iff successful
  570. */
  571. bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
  572. {
  573. wimp_window_state state;
  574. os_error *error;
  575. int toolbar_height = 0;
  576. assert(g);
  577. state.w = g->window;
  578. error = xwimp_get_window_state(&state);
  579. if (error) {
  580. LOG(("xwimp_get_window_state: 0x%x: %s",
  581. error->errnum, error->errmess));
  582. warn_user("WimpError", error->errmess);
  583. return false;
  584. }
  585. if (g->toolbar)
  586. toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar);
  587. *sx = state.xscroll / (2 * g->bw->scale);
  588. *sy = -(state.yscroll - toolbar_height) / (2 * g->bw->scale);
  589. return true;
  590. }
  591. /**
  592. * Set the scroll position of a browser window.
  593. *
  594. * \param g gui_window to scroll
  595. * \param sx point to place at top-left of window
  596. * \param sy point to place at top-left of window
  597. */
  598. void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
  599. {
  600. wimp_window_state state;
  601. os_error *error;
  602. assert(g);
  603. state.w = g->window;
  604. error = xwimp_get_window_state(&state);
  605. if (error) {
  606. LOG(("xwimp_get_window_state: 0x%x: %s",
  607. error->errnum, error->errmess));
  608. warn_user("WimpError", error->errmess);
  609. return;
  610. }
  611. state.xscroll = sx * 2 * g->bw->scale;
  612. state.yscroll = -sy * 2 * g->bw->scale;
  613. if (g->toolbar)
  614. state.yscroll += ro_gui_theme_toolbar_full_height(g->toolbar);
  615. ro_gui_window_open(PTR_WIMP_OPEN(&state));
  616. }
  617. /**
  618. * Scrolls the specified area of a browser window into view.
  619. *
  620. * \param g gui_window to scroll
  621. * \param x0 left point to ensure visible
  622. * \param y0 bottom point to ensure visible
  623. * \param x1 right point to ensure visible
  624. * \param y1 top point to ensure visible
  625. */
  626. void gui_window_scroll_visible(struct gui_window *g, int x0, int y0, int x1, int y1)
  627. {
  628. wimp_window_state state;
  629. os_error *error;
  630. int cx0, cy0, width, height;
  631. int padding_available;
  632. int toolbar_height = 0;
  633. int correction;
  634. assert(g);
  635. state.w = g->window;
  636. error = xwimp_get_window_state(&state);
  637. if (error) {
  638. LOG(("xwimp_get_window_state: 0x%x: %s",
  639. error->errnum, error->errmess));
  640. warn_user("WimpError", error->errmess);
  641. return;
  642. }
  643. if (g->toolbar)
  644. toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar);
  645. x0 = x0 * 2 * g->bw->scale;
  646. y0 = y0 * 2 * g->bw->scale;
  647. x1 = x1 * 2 * g->bw->scale;
  648. y1 = y1 * 2 * g->bw->scale;
  649. cx0 = state.xscroll;
  650. cy0 = -state.yscroll + toolbar_height;
  651. width = state.visible.x1 - state.visible.x0;
  652. height = state.visible.y1 - state.visible.y0 - toolbar_height;
  653. /* make sure we're visible */
  654. correction = (x1 - cx0 - width);
  655. if (correction > 0)
  656. cx0 += correction;
  657. correction = (y1 - cy0 - height);
  658. if (correction > 0)
  659. cy0 += correction;
  660. if (x0 < cx0)
  661. cx0 = x0;
  662. if (y0 < cy0)
  663. cy0 = y0;
  664. /* try to give a SCROLL_VISIBLE_PADDING border of space around us */
  665. padding_available = (width - x1 + x0) / 2;
  666. if (padding_available > 0) {
  667. if (padding_available > SCROLL_VISIBLE_PADDING)
  668. padding_available = SCROLL_VISIBLE_PADDING;
  669. correction = (cx0 + width - x1);
  670. if (correction < padding_available)
  671. cx0 += padding_available;
  672. correction = (x0 - cx0);
  673. if (correction < padding_available)
  674. cx0 -= padding_available;
  675. }
  676. padding_available = (height - y1 + y0) / 2;
  677. if (padding_available > 0) {
  678. if (padding_available > SCROLL_VISIBLE_PADDING)
  679. padding_available = SCROLL_VISIBLE_PADDING;
  680. correction = (cy0 + height - y1);
  681. if (correction < padding_available)
  682. cy0 += padding_available;
  683. correction = (y0 - cy0);
  684. if (correction < padding_available)
  685. cy0 -= padding_available;
  686. }
  687. state.xscroll = cx0;
  688. state.yscroll = -cy0 + toolbar_height;
  689. ro_gui_window_open(PTR_WIMP_OPEN(&state));
  690. }
  691. /**
  692. * Opens a frame at a specified position.
  693. *
  694. * \param g child gui_window to open
  695. * \param x0 left point to open at
  696. * \param y0 bottom point to open at
  697. * \param x1 right point to open at
  698. * \param y1 top point to open at
  699. */
  700. void gui_window_position_frame(struct gui_window *g, int x0, int y0, int x1, int y1)
  701. {
  702. wimp_window_state state;
  703. os_error *error;
  704. int px0, py1;
  705. struct browser_window *bw;
  706. struct browser_window *parent;
  707. struct browser_window *top;
  708. float scale = 1.0;
  709. assert(g);
  710. bw = g->bw;
  711. assert(bw);
  712. parent = bw->parent;
  713. assert(parent);
  714. top = browser_window_owner(bw);
  715. /* store position for children */
  716. if (parent->browser_window_type == BROWSER_WINDOW_IFRAME) {
  717. bw->x0 = x0;
  718. bw->y0 = y0;
  719. bw->x1 = x1;
  720. bw->y1 = y1;
  721. } else {
  722. bw->x0 = x0 = parent->x0 + x0;
  723. bw->y0 = y0 = parent->y0 + y0;
  724. bw->x1 = x1 = parent->x0 + x1;
  725. bw->y1 = y1 = parent->y0 + y1;
  726. }
  727. /* only scale iframe locations */
  728. if (bw->browser_window_type == BROWSER_WINDOW_IFRAME)
  729. scale = g->bw->scale;
  730. /* get the position of the top level window */
  731. state.w = top->window->window;
  732. error = xwimp_get_window_state(&state);
  733. if (error) {
  734. LOG(("xwimp_get_window_state: 0x%x: %s",
  735. error->errnum, error->errmess));
  736. warn_user("WimpError", error->errmess);
  737. return;
  738. }
  739. px0 = state.visible.x0 - state.xscroll;
  740. py1 = state.visible.y1 - state.yscroll;
  741. /* get our current window state */
  742. state.w = g->window;
  743. error = xwimp_get_window_state(&state);
  744. if (error) {
  745. LOG(("xwimp_get_window_state: 0x%x: %s",
  746. error->errnum, error->errmess));
  747. warn_user("WimpError", error->errmess);
  748. return;
  749. }
  750. if (!g->bw->border) {
  751. x0 -= 1;
  752. y0 -= 1;
  753. x1 += 1;
  754. y1 += 1;
  755. }
  756. x1 = x1 * 2 * scale;
  757. y1 = y1 * 2 * scale;
  758. /* scrollbars must go inside */
  759. if (state.flags & wimp_WINDOW_HSCROLL) {
  760. y1 -= ro_get_hscroll_height(NULL);
  761. if (g->bw->border)
  762. y1 += 2;
  763. }
  764. if (state.flags & wimp_WINDOW_VSCROLL) {
  765. x1 -= ro_get_vscroll_width(NULL);
  766. if (g->bw->border)
  767. x1 += 2;
  768. }
  769. state.visible.x0 = px0 + x0 * 2 * scale;
  770. state.visible.y0 = py1 - y1;
  771. state.visible.x1 = px0 + x1;
  772. state.visible.y1 = py1 - y0 * 2 * scale;
  773. g->update_extent = true;
  774. ro_gui_window_open(PTR_WIMP_OPEN(&state));
  775. }
  776. /**
  777. * Find the current dimensions of a browser window's content area.
  778. *
  779. * \param g gui_window to measure
  780. * \param width receives width of window
  781. * \param height receives height of window
  782. * \param scaled whether to return scaled values
  783. */
  784. void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, bool scaled)
  785. {
  786. /* use the cached window sizes */
  787. *width = g->old_width / 2;
  788. *height = g->old_height / 2;
  789. if (scaled) {
  790. *width /= g->bw->scale;
  791. *height /= g->bw->scale;
  792. }
  793. }
  794. /**
  795. * Update the extent of the inside of a browser window to that of the current content.
  796. *
  797. * \param g gui_window to update the extent of
  798. */
  799. void gui_window_update_extent(struct gui_window *g)
  800. {
  801. os_error *error;
  802. wimp_window_state state;
  803. bool update;
  804. unsigned int flags;
  805. int scroll = 0;
  806. assert(g);
  807. state.w = g->window;
  808. error = xwimp_get_window_state(&state);
  809. if (error) {
  810. LOG(("xwimp_get_window_state: 0x%x: %s",
  811. error->errnum, error->errmess));
  812. warn_user("WimpError", error->errmess);
  813. return;
  814. }
  815. /* scroll on toolbar height change */
  816. if (g->toolbar) {
  817. scroll = ro_gui_theme_height_change(g->toolbar);
  818. state.yscroll -= scroll;
  819. }
  820. /* only allow a further reformat if we've gained/lost scrollbars */
  821. flags = state.flags & (wimp_WINDOW_HSCROLL | wimp_WINDOW_VSCROLL);
  822. update = g->bw->reformat_pending;
  823. g->update_extent = true;
  824. ro_gui_window_open(PTR_WIMP_OPEN(&state));
  825. state.w = g->window;
  826. error = xwimp_get_window_state(&state);
  827. if (error) {
  828. LOG(("xwimp_get_window_state: 0x%x: %s",
  829. error->errnum, error->errmess));
  830. warn_user("WimpError", error->errmess);
  831. return;
  832. }
  833. if (flags == (state.flags & (wimp_WINDOW_HSCROLL | wimp_WINDOW_VSCROLL)))
  834. g->bw->reformat_pending = update;
  835. if ((scroll != 0) && (g->bw->children))
  836. browser_window_recalculate_frameset(g->bw);
  837. }
  838. /**
  839. * Set the status bar of a browser window.
  840. *
  841. * \param g gui_window to update
  842. * \param text new status text
  843. */
  844. void gui_window_set_status(struct gui_window *g, const char *text)
  845. {
  846. if (g->status_bar)
  847. ro_gui_status_bar_set_text(g->status_bar, text);
  848. }
  849. /**
  850. * Change mouse pointer shape
  851. */
  852. void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
  853. {
  854. static gui_pointer_shape curr_pointer = GUI_POINTER_DEFAULT;
  855. struct ro_gui_pointer_entry *entry;
  856. os_error *error;
  857. if (shape == curr_pointer)
  858. return;
  859. assert(shape < sizeof ro_gui_pointer_table /
  860. sizeof ro_gui_pointer_table[0]);
  861. entry = &ro_gui_pointer_table[shape];
  862. if (entry->wimp_area) {
  863. /* pointer in the Wimp's sprite area */
  864. error = xwimpspriteop_set_pointer_shape(entry->sprite_name,
  865. 1, entry->xactive, entry->yactive, 0, 0);
  866. if (error) {
  867. LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s",
  868. error->errnum, error->errmess));
  869. warn_user("WimpError", error->errmess);
  870. }
  871. } else {
  872. /* pointer in our own sprite area */
  873. error = xosspriteop_set_pointer_shape(osspriteop_USER_AREA,
  874. gui_sprites,
  875. (osspriteop_id) entry->sprite_name,
  876. 1, entry->xactive, entry->yactive, 0, 0);
  877. if (error) {
  878. LOG(("xosspriteop_set_pointer_shape: 0x%x: %s",
  879. error->errnum, error->errmess));
  880. warn_user("WimpError", error->errmess);
  881. }
  882. }
  883. curr_pointer = shape;
  884. }
  885. /**
  886. * Remove the mouse pointer from the screen
  887. */
  888. void gui_window_hide_pointer(struct gui_window *g)
  889. {
  890. os_error *error;
  891. error = xwimpspriteop_set_pointer_shape(NULL, 0x30, 0, 0, 0, 0);
  892. if (error) {
  893. LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s",
  894. error->errnum, error->errmess));
  895. warn_user("WimpError", error->errmess);
  896. }
  897. }
  898. /**
  899. * Set the contents of a window's address bar.
  900. *
  901. * \param g gui_window to update
  902. * \param url new url for address bar
  903. */
  904. void gui_window_set_url(struct gui_window *g, const char *url)
  905. {
  906. wimp_caret caret;
  907. os_error *error;
  908. const char *toolbar_url;
  909. if (!g->toolbar)
  910. return;
  911. ro_gui_set_icon_string(g->toolbar->toolbar_handle,
  912. ICON_TOOLBAR_URL, url, true);
  913. ro_gui_force_redraw_icon(g->toolbar->toolbar_handle,
  914. ICON_TOOLBAR_FAVICON);
  915. /* if the caret is in the address bar, move it to the end */
  916. error = xwimp_get_caret_position(&caret);
  917. if (error) {
  918. LOG(("xwimp_get_caret_position: 0x%x: %s",
  919. error->errnum, error->errmess));
  920. warn_user("WimpError", error->errmess);
  921. return;
  922. }
  923. if (!(caret.w == g->toolbar->toolbar_handle &&
  924. caret.i == ICON_TOOLBAR_URL))
  925. return;
  926. toolbar_url = ro_gui_get_icon_string(g->toolbar->toolbar_handle,
  927. ICON_TOOLBAR_URL);
  928. error = xwimp_set_caret_position(g->toolbar->toolbar_handle,
  929. ICON_TOOLBAR_URL, 0, 0, -1, (int)strlen(toolbar_url));
  930. if (error) {
  931. LOG(("xwimp_set_caret_position: 0x%x: %s",
  932. error->errnum, error->errmess));
  933. warn_user("WimpError", error->errmess);
  934. }
  935. ro_gui_url_complete_start(g);
  936. }
  937. /**
  938. * Update the interface to reflect start of page loading.
  939. *
  940. * \param g window with start of load
  941. */
  942. void gui_window_start_throbber(struct gui_window *g)
  943. {
  944. ro_gui_menu_objects_moved();
  945. ro_gui_prepare_navigate(g);
  946. xos_read_monotonic_time(&g->throbtime);
  947. g->throbber = 0;
  948. }
  949. /**
  950. * Update the interface to reflect page loading stopped.
  951. *
  952. * \param g window with start of load
  953. */
  954. void gui_window_stop_throbber(struct gui_window *g)
  955. {
  956. char throb_buf[12];
  957. ro_gui_prepare_navigate(g);
  958. g->throbber = 0;
  959. if (g->toolbar) {
  960. strcpy(throb_buf, "throbber0");
  961. ro_gui_set_icon_string(g->toolbar->toolbar_handle,
  962. ICON_TOOLBAR_THROBBER, throb_buf, true);
  963. if ((g->toolbar->descriptor) && (g->toolbar->descriptor->throbber_redraw))
  964. ro_gui_force_redraw_icon(g->toolbar->toolbar_handle,
  965. ICON_TOOLBAR_THROBBER);
  966. }
  967. }
  968. /**
  969. * set favicon
  970. */
  971. void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
  972. {
  973. }
  974. /**
  975. * set gui display of a retrieved favicon representing the search provider
  976. * \param ico may be NULL for local calls; then access current cache from
  977. * search_web_ico()
  978. */
  979. void gui_window_set_search_ico(hlcache_handle *ico)
  980. {
  981. }
  982. /**
  983. * Place the caret in a browser window.
  984. *
  985. * \param g window with caret
  986. * \param x coordinates of caret
  987. * \param y coordinates of caret
  988. * \param height height of caret
  989. */
  990. void gui_window_place_caret(struct gui_window *g, int x, int y, int height)
  991. {
  992. os_error *error;
  993. error = xwimp_set_caret_position(g->window, -1,
  994. x * 2 * g->bw->scale,
  995. -(y + height) * 2 * g->bw->scale,
  996. height * 2 * g->bw->scale, -1);
  997. if (error) {
  998. LOG(("xwimp_set_caret_position: 0x%x: %s",
  999. error->errnum, error->errmess));
  1000. warn_user("WimpError", error->errmess);
  1001. }
  1002. }
  1003. /**
  1004. * Remove the caret, if present.
  1005. *
  1006. * \param g window with caret
  1007. */
  1008. void gui_window_remove_caret(struct gui_window *g)
  1009. {
  1010. wimp_caret caret;
  1011. os_error *error;
  1012. error = xwimp_get_caret_position(&caret);
  1013. if (error) {
  1014. LOG(("xwimp_get_caret_position: 0x%x: %s",
  1015. error->errnum, error->errmess));
  1016. warn_user("WimpError", error->errmess);
  1017. return;
  1018. }
  1019. if (caret.w != g->window)
  1020. /* we don't have the caret: do nothing */
  1021. return;
  1022. /* hide caret, but keep input focus */
  1023. gui_window_place_caret(g, -100, -100, 0);
  1024. }
  1025. /**
  1026. * Called when the gui_window has new content.
  1027. *
  1028. * \param g the gui_window that has new content
  1029. */
  1030. void gui_window_new_content(struct gui_window *g)
  1031. {
  1032. ro_gui_menu_objects_moved();
  1033. ro_gui_prepare_navigate(g);
  1034. ro_gui_dialog_close_persistent(g->window);
  1035. }
  1036. /**
  1037. * Starts drag scrolling of a browser window
  1038. *
  1039. * \param gw gui window
  1040. */
  1041. bool gui_window_scroll_start(struct gui_window *g)
  1042. {
  1043. wimp_window_info_base info;
  1044. wimp_pointer pointer;
  1045. os_error *error;
  1046. wimp_drag drag;
  1047. int height;
  1048. int width;
  1049. error = xwimp_get_pointer_info(&pointer);
  1050. if (error) {
  1051. LOG(("xwimp_get_pointer_info 0x%x : %s",
  1052. error->errnum, error->errmess));
  1053. warn_user("WimpError", error->errmess);
  1054. return false;
  1055. }
  1056. info.w = g->window;
  1057. error = xwimp_get_window_info_header_only((wimp_window_info*)&info);
  1058. if (error) {
  1059. LOG(("xwimp_get_window_state: 0x%x : %s",
  1060. error->errnum, error->errmess));
  1061. warn_user("WimpError", error->errmess);
  1062. return false;
  1063. }
  1064. width = info.extent.x1 - info.extent.x0;
  1065. height = info.extent.y1 - info.extent.y0;
  1066. drag.type = wimp_DRAG_USER_POINT;
  1067. drag.bbox.x1 = pointer.pos.x + info.xscroll;
  1068. drag.bbox.y0 = pointer.pos.y + info.yscroll;
  1069. drag.bbox.x0 = drag.bbox.x1 - (width - (info.visible.x1 - info.visible.x0));
  1070. drag.bbox.y1 = drag.bbox.y0 + (height - (info.visible.y1 - info.visible.y0));
  1071. if (g->toolbar) {
  1072. int tbar_height = ro_gui_theme_toolbar_full_height(g->toolbar);
  1073. drag.bbox.y0 -= tbar_height;
  1074. drag.bbox.y1 -= tbar_height;
  1075. }
  1076. error = xwimp_drag_box(&drag);
  1077. if (error) {
  1078. LOG(("xwimp_drag_box: 0x%x : %s",
  1079. error->errnum, error->errmess));
  1080. warn_user("WimpError", error->errmess);
  1081. return false;
  1082. }
  1083. gui_track_gui_window = g;
  1084. gui_current_drag_type = GUI_DRAG_SCROLL;
  1085. return true;
  1086. }
  1087. /**
  1088. * Platform-dependent part of starting a box scrolling operation,
  1089. * for frames and textareas.
  1090. *
  1091. * \param x0 minimum x ordinate of box relative to mouse pointer
  1092. * \param y0 minimum y ordinate
  1093. * \param x1 maximum x ordinate
  1094. * \param y1 maximum y ordinate
  1095. * \return true iff succesful
  1096. */
  1097. bool gui_window_box_scroll_start(struct gui_window *g, int x0, int y0, int x1, int y1)
  1098. {
  1099. wimp_pointer pointer;
  1100. os_error *error;
  1101. wimp_drag drag;
  1102. error = xwimp_get_pointer_info(&pointer);
  1103. if (error) {
  1104. LOG(("xwimp_get_pointer_info 0x%x : %s",
  1105. error->errnum, error->errmess));
  1106. warn_user("WimpError", error->errmess);
  1107. return false;
  1108. }
  1109. drag.type = wimp_DRAG_USER_POINT;
  1110. drag.bbox.x0 = pointer.pos.x + (int)(x0 * 2 * g->bw->scale);
  1111. drag.bbox.y0 = pointer.pos.y + (int)(y0 * 2 * g->bw->scale);
  1112. drag.bbox.x1 = pointer.pos.x + (int)(x1 * 2 * g->bw->scale);
  1113. drag.bbox.y1 = pointer.pos.y + (int)(y1 * 2 * g->bw->scale);
  1114. error = xwimp_drag_box(&drag);
  1115. if (error) {
  1116. LOG(("xwimp_drag_box: 0x%x : %s",
  1117. error->errnum, error->errmess));
  1118. warn_user("WimpError", error->errmess);
  1119. return false;
  1120. }
  1121. gui_current_drag_type = GUI_DRAG_SCROLL;
  1122. return true;
  1123. }
  1124. /**
  1125. * Starts drag resizing of a browser frame
  1126. *
  1127. * \param gw gui window
  1128. */
  1129. bool gui_window_frame_resize_start(struct gui_window *g)
  1130. {
  1131. wimp_pointer pointer;
  1132. os_error *error;
  1133. wimp_drag drag;
  1134. int x0, y0, x1, y1;
  1135. int row = -1, col = -1, i, toolbar_height = 0;
  1136. struct browser_window *top, *bw, *parent;
  1137. wimp_window_state state;
  1138. /* get the maximum drag box (collapse all surrounding frames */
  1139. bw = g->bw;
  1140. parent = bw->parent;
  1141. x0 = bw->x0;
  1142. y0 = bw->y0;
  1143. x1 = bw->x1;
  1144. y1 = bw->y1;
  1145. for (i = 0; i < (parent->cols * parent->rows); i++) {
  1146. if (&parent->children[i] == bw) {
  1147. col = i % parent->cols;
  1148. row = i / parent->cols;
  1149. }
  1150. }
  1151. assert((row >= 0) && (col >= 0));
  1152. if (bw->drag_resize_left)
  1153. x0 = parent->children[row * parent->cols + (col - 1)].x0;
  1154. if (bw->drag_resize_right)
  1155. x1 = parent->children[row * parent->cols + (col + 1)].x1;
  1156. if (bw->drag_resize_up)
  1157. y0 = parent->children[(row - 1) * parent->cols + col].y0;
  1158. if (bw->drag_resize_down)
  1159. y1 = parent->children[(row + 1) * parent->cols + col].y1;
  1160. /* convert to screen co-ordinates */
  1161. top = browser_window_owner(bw);
  1162. if (top->window->toolbar)
  1163. toolbar_height = ro_gui_theme_toolbar_full_height(top->window->toolbar);
  1164. state.w = top->window->window;
  1165. error = xwimp_get_window_state(&state);
  1166. if (error) {
  1167. LOG(("xwimp_get_window_state: 0x%x: %s",
  1168. error->errnum, error->errmess));
  1169. warn_user("WimpError", error->errmess);
  1170. return false;
  1171. }
  1172. x0 = state.visible.x0 + x0 * 2;
  1173. y0 = state.visible.y1 - y0 * 2 - toolbar_height;
  1174. x1 = state.visible.x0 + x1 * 2 - 1;
  1175. y1 = state.visible.y1 - y1 * 2 - toolbar_height - 1;
  1176. /* get the pointer position */
  1177. error = xwimp_get_pointer_info(&pointer);
  1178. if (error) {
  1179. LOG(("xwimp_get_pointer_info 0x%x : %s",
  1180. error->errnum, error->errmess));
  1181. warn_user("WimpError", error->errmess);
  1182. return false;
  1183. }
  1184. /* stop dragging in directions we can't extend */
  1185. if (!(bw->drag_resize_left || bw->drag_resize_right)) {
  1186. x0 = pointer.pos.x;
  1187. x1 = pointer.pos.x;
  1188. }
  1189. if (!(bw->drag_resize_up || bw->drag_resize_down)) {
  1190. y0 = pointer.pos.y;
  1191. y1 = pointer.pos.y;
  1192. }
  1193. /* start the drag */
  1194. drag.type = wimp_DRAG_USER_POINT;
  1195. drag.bbox.x0 = x0;
  1196. drag.bbox.y0 = y1;
  1197. drag.bbox.x1 = x1;
  1198. drag.bbox.y1 = y0;
  1199. error = xwimp_drag_box(&drag);
  1200. if (error) {
  1201. LOG(("xwimp_drag_box: 0x%x : %s",
  1202. error->errnum, error->errmess));
  1203. warn_user("WimpError", error->errmess);
  1204. return false;
  1205. }
  1206. /* we may not be the window the pointer is currently over */
  1207. gui_track_gui_window = bw->window;
  1208. gui_current_drag_type = GUI_DRAG_FRAME;
  1209. return true;
  1210. }
  1211. /**
  1212. * Save the specified content as a link.
  1213. *
  1214. * \param g gui_window containing the content
  1215. * \param c the content to save
  1216. */
  1217. void gui_window_save_link(struct gui_window *g, const char *url,
  1218. const char *title)
  1219. {
  1220. ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, url, title);
  1221. ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
  1222. }
  1223. /**
  1224. * Set the scale setting of a window
  1225. *
  1226. * \param g gui window
  1227. * \param scale scale value (1.0 == normal scale)
  1228. */
  1229. void gui_window_set_scale(struct gui_window *g, float scale)
  1230. {
  1231. ro_gui_dialog_update_zoom(g);
  1232. }
  1233. /**
  1234. * Redraws the content for all windows.
  1235. */
  1236. void ro_gui_window_redraw_all(void)
  1237. {
  1238. struct gui_window *g;
  1239. for (g = window_list; g; g = g->next)
  1240. gui_window_redraw_window(g);
  1241. }
  1242. /**
  1243. * Handle a Redraw_Window_Request for a browser window.
  1244. */
  1245. void ro_gui_window_redraw(wimp_draw *redraw)
  1246. {
  1247. osbool more;
  1248. struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w);
  1249. float scale = g->bw->scale;
  1250. hlcache_handle *h = g->bw->current_content;
  1251. os_error *error;
  1252. /* Handle no content quickly
  1253. */
  1254. if (!h) {
  1255. ro_gui_user_redraw(redraw, true, os_COLOUR_WHITE);
  1256. return;
  1257. }
  1258. /* We can't render locked content as it is being in the process of
  1259. being transformed. We won't update anything (i.e. leaving
  1260. window area as is) instead of showing random data in case of
  1261. buffered redraw. */
  1262. if (content_is_locked(h))
  1263. return;
  1264. plot = ro_plotters;
  1265. ro_plot_set_scale(scale);
  1266. ro_gui_current_redraw_gui = g;
  1267. current_redraw_browser = g->bw;
  1268. /* HTML rendering handles scale itself */
  1269. if (content_get_type(h) == CONTENT_HTML)
  1270. scale = 1;
  1271. error = xwimp_redraw_window(redraw, &more);
  1272. if (error) {
  1273. LOG(("xwimp_redraw_window: 0x%x: %s",
  1274. error->errnum, error->errmess));
  1275. warn_user("WimpError", error->errmess);
  1276. return;
  1277. }
  1278. while (more) {
  1279. int clip_x0, clip_y0, clip_x1, clip_y1;
  1280. /* OS's redraw request coordinates are in screen coordinates,
  1281. * with an origin at the bottom left of the screen.
  1282. * Find the coordinate of the top left of the document in terms
  1283. * of OS screen coordinates.
  1284. * NOTE: OS units are 2 per px. */
  1285. ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
  1286. ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
  1287. /* Convert OS redraw rectangle request coordinates into NetSurf
  1288. * coordinates. NetSurf coordinates have origin at top left of
  1289. * document and units are in px. */
  1290. clip_x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */
  1291. clip_y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */
  1292. clip_x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */
  1293. clip_y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */
  1294. if (ro_gui_current_redraw_gui->option.buffer_everything)
  1295. ro_gui_buffer_open(redraw);
  1296. /* Set up NetSurf's plotters with current clip rectangle */
  1297. plot.clip(clip_x0, clip_y0, clip_x1, clip_y1);
  1298. if (content_get_type(h) != CONTENT_HTML)
  1299. plot.rectangle(clip_x0, clip_y0, clip_x1, clip_y1,
  1300. plot_style_fill_white);
  1301. /* Redraw the clip rectangle area of the content */
  1302. content_redraw(h, 0, 0,
  1303. content_get_width(h) * scale,
  1304. content_get_height(h) * scale,
  1305. clip_x0, clip_y0, clip_x1, clip_y1,
  1306. g->bw->scale,
  1307. 0xFFFFFF);
  1308. if (ro_gui_current_redraw_gui->option.buffer_everything)
  1309. ro_gui_buffer_close();
  1310. /* Check to see if there are more rectangles to draw and
  1311. * get next one */
  1312. error = xwimp_get_rectangle(redraw, &more);
  1313. /* RISC OS 3.7 returns an error here if enough buffer was
  1314. claimed to cause a new dynamic area to be created. It
  1315. doesn't actually stop anything working, so we mask it out
  1316. for now until a better fix is found. This appears to be a
  1317. bug in RISC OS. */
  1318. if (error && !(ro_gui_current_redraw_gui->
  1319. option.buffer_everything &&
  1320. error->errnum == error_WIMP_GET_RECT)) {
  1321. LOG(("xwimp_get_rectangle: 0x%x: %s",
  1322. error->errnum, error->errmess));
  1323. warn_user("WimpError", error->errmess);
  1324. ro_gui_current_redraw_gui = NULL;
  1325. current_redraw_browser = NULL;
  1326. return;
  1327. }
  1328. }
  1329. ro_gui_current_redraw_gui = NULL;
  1330. current_redraw_browser = NULL;
  1331. }
  1332. /**
  1333. * Remove all pending update boxes for a window
  1334. *
  1335. * \param g gui_window
  1336. */
  1337. void ro_gui_window_remove_update_boxes(struct gui_window *g) {
  1338. struct update_box *cur;
  1339. for (cur = pending_updates; cur != NULL; cur = cur->next) {
  1340. if (cur->g == g)
  1341. cur->g = NULL;
  1342. }
  1343. }
  1344. /**
  1345. * Redraw any pending update boxes.
  1346. */
  1347. void ro_gui_window_update_boxes(void) {
  1348. hlcache_handle *h;
  1349. osbool more;
  1350. bool clear_background = false;
  1351. bool use_buffer;
  1352. wimp_draw update;
  1353. int clip_x0, clip_y0, clip_x1, clip_y1;
  1354. os_error *error;
  1355. struct update_box *cur;
  1356. struct gui_window *g;
  1357. const union content_msg_data *data;
  1358. for (cur = pending_updates; cur != NULL; cur = cur->next) {
  1359. g = cur->g;
  1360. if (!g)
  1361. continue;
  1362. h = g->bw->current_content;
  1363. data = &cur->data;
  1364. use_buffer = cur->use_buffer;
  1365. if (!h)
  1366. continue;
  1367. update.w = g->window;
  1368. update.box.x0 = cur->x0;
  1369. update.box.y0 = cur->y0;
  1370. update.box.x1 = cur->x1;
  1371. update.box.y1 = cur->y1;
  1372. error = xwimp_update_window(&update, &more);
  1373. if (error) {
  1374. LOG(("xwimp_update_window: 0x%x: %s",
  1375. error->errnum, error->errmess));
  1376. warn_user("WimpError", error->errmess);
  1377. continue;
  1378. }
  1379. /* Set the current redraw gui_window to get options from */
  1380. ro_gui_current_redraw_gui = g;
  1381. current_redraw_browser = g->bw;
  1382. plot = ro_plotters;
  1383. ro_plot_origin_x = update.box.x0 - update.xscroll;
  1384. ro_plot_origin_y = update.box.y1 - update.yscroll;
  1385. ro_plot_set_scale(g->bw->scale);
  1386. /* We should clear the background, except for HTML. */
  1387. if (content_get_type(h) != CONTENT_HTML)
  1388. clear_background = true;
  1389. while (more) {
  1390. clip_x0 = (update.clip.x0 - ro_plot_origin_x) / 2;
  1391. clip_y0 = (ro_plot_origin_y - update.clip.y1) / 2;
  1392. clip_x1 = (update.clip.x1 - ro_plot_origin_x) / 2;
  1393. clip_y1 = (ro_plot_origin_y - update.clip.y0) / 2;
  1394. if (use_buffer)
  1395. ro_gui_buffer_open(&update);
  1396. if (clear_background) {
  1397. error = xcolourtrans_set_gcol(
  1398. os_COLOUR_WHITE,
  1399. colourtrans_SET_BG_GCOL,
  1400. os_ACTION_OVERWRITE, 0,
  1401. 0);
  1402. if (error) {
  1403. LOG(("xcolourtrans_set_gcol: "
  1404. "0x%x: %s",
  1405. error->errnum,
  1406. error->errmess));
  1407. warn_user("MiscError",
  1408. error->errmess);
  1409. }
  1410. os_clg();
  1411. }
  1412. content_redraw(h, 0, 0,
  1413. content_get_width(h),
  1414. content_get_height(h),
  1415. clip_x0, clip_y0,
  1416. clip_x1, clip_y1,
  1417. g->bw->scale,
  1418. 0xFFFFFF);
  1419. if (use_buffer)
  1420. ro_gui_buffer_close();
  1421. error = xwimp_get_rectangle(&update, &more);
  1422. /* RISC OS 3.7 returns an error here if enough buffer
  1423. * was claimed to cause a new dynamic area to be
  1424. * created. It doesn't actually stop anything working,
  1425. * so we mask it out for now until a better fix is
  1426. * found. This appears to be a bug in RISC OS. */
  1427. if (error && !(use_buffer &&
  1428. error->errnum == error_WIMP_GET_RECT)) {
  1429. LOG(("xwimp_get_rectangle: 0x%x: %s",
  1430. error->errnum, error->errmess));
  1431. warn_user("WimpError", error->errmess);
  1432. ro_gui_current_redraw_gui = NULL;
  1433. current_redraw_browser = NULL;
  1434. continue;
  1435. }
  1436. }
  1437. /* Reset the current redraw gui_window to prevent
  1438. * thumbnails from retaining options */
  1439. ro_gui_current_redraw_gui = NULL;
  1440. current_redraw_browser = NULL;
  1441. }
  1442. while (pending_updates) {
  1443. cur = pending_updates;
  1444. pending_updates = pending_updates->next;
  1445. free(cur);
  1446. }
  1447. }
  1448. /**
  1449. * Launch a new url in the given window.
  1450. *
  1451. * \param g gui_window to update
  1452. * \param url url to be launched
  1453. */
  1454. void ro_gui_window_launch_url(struct gui_window *g, const char *url)
  1455. {
  1456. url_func_result res;
  1457. char *url_norm;
  1458. ro_gui_url_complete_close(NULL, 0);
  1459. res = url_normalize(url, &url_norm);
  1460. if (res == URL_FUNC_OK) {
  1461. gui_window_set_url(g, url_norm);
  1462. browser_window_go(g->bw, url_norm, 0, true);
  1463. global_history_add_recent(url_norm);
  1464. free(url_norm);
  1465. }
  1466. }
  1467. /**
  1468. * Forces all windows to be set to the current theme
  1469. */
  1470. void ro_gui_window_update_theme(void) {
  1471. struct gui_window *g;
  1472. for (g = window_list; g; g = g->next) {
  1473. if (g->toolbar) {
  1474. if (g->toolbar->editor)
  1475. if (!ro_gui_theme_update_toolbar(NULL, g->toolbar->editor))
  1476. g->toolbar->editor = NULL;
  1477. if (!ro_gui_theme_update_toolbar(NULL, g->toolbar)) {
  1478. ro_gui_theme_destroy_toolbar(g->toolbar);
  1479. g->toolbar = NULL;
  1480. }
  1481. ro_gui_theme_toolbar_editor_sync(g->toolbar);
  1482. gui_window_update_extent(g);
  1483. }
  1484. }
  1485. }
  1486. /**
  1487. * Updates a windows extent.
  1488. *
  1489. * \param g the gui_window to update
  1490. * \param width the minimum width, or -1 to use window width
  1491. * \param height the minimum height, or -1 to use window height
  1492. */
  1493. void gui_window_set_extent(struct gui_window *g, int width, int height)
  1494. {
  1495. int screen_width;
  1496. int toolbar_height = 0;
  1497. hlcache_handle *h;
  1498. wimp_window_state state;
  1499. os_error *error;
  1500. h = g->bw->current_content;
  1501. if (g->toolbar)
  1502. toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar);
  1503. /* get the current state */
  1504. if ((height == -1) || (width == -1)) {
  1505. state.w = g->window;
  1506. error = xwimp_get_window_state(&state);
  1507. if (error) {
  1508. LOG(("xwimp_get_window_state: 0x%x: %s",
  1509. error->errnum, error->errmess));
  1510. warn_user("WimpError", error->errmess);
  1511. return;
  1512. }
  1513. if (width == -1)
  1514. width = state.visible.x1 - state.visible.x0;
  1515. if (height == -1) {
  1516. height = state.visible.y1 - state.visible.y0;
  1517. height -= toolbar_height;
  1518. }
  1519. }
  1520. /* the top-level framed window is a total pain. to get it to maximise
  1521. * to the top of the screen we need to fake it having a suitably large
  1522. * extent */
  1523. if (g->bw->children &&
  1524. (g->bw->browser_window_type == BROWSER_WINDOW_NORMAL)) {
  1525. ro_gui_screen_size(&screen_width, &height);
  1526. if (g->toolbar)
  1527. height -= ro_gui_theme_toolbar_full_height(g->toolbar);
  1528. height -= ro_get_hscroll_height(g->window);
  1529. height -= ro_get_title_height(g->window);
  1530. }
  1531. if (h) {
  1532. width = max(width, content_get_width(h) * 2 * g->bw->scale);
  1533. height = max(height, content_get_height(h) * 2 * g->bw->scale);
  1534. }
  1535. os_box extent = { 0, -height, width, toolbar_height };
  1536. error = xwimp_set_extent(g->window, &extent);
  1537. if (error) {
  1538. LOG(("xwimp_set_extent: 0x%x: %s",
  1539. error->errnum, error->errmess));
  1540. warn_user("WimpError", error->errmess);
  1541. return;
  1542. }
  1543. }
  1544. /**
  1545. * Open a window using the given wimp_open, handling toolbars and resizing.
  1546. */
  1547. void ro_gui_window_open(wimp_open *open)
  1548. {
  1549. struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(open->w);
  1550. int width = open->visible.x1 - open->visible.x0;
  1551. int height = open->visible.y1 - open->visible.y0;
  1552. int size, fheight, fwidth, toolbar_height = 0;
  1553. bool no_vscroll, no_hscroll;
  1554. float new_scale = 0;
  1555. hlcache_handle *h;
  1556. wimp_window_state state;
  1557. os_error *error;
  1558. wimp_w parent;
  1559. bits linkage;
  1560. if (open->next == wimp_TOP && g->iconise_icon >= 0) {
  1561. /* window is no longer iconised, release its sprite number */
  1562. iconise_used[g->iconise_icon] = false;
  1563. g->iconise_icon = -1;
  1564. }
  1565. h = g->bw->current_content;
  1566. /* get the current flags/nesting state */
  1567. state.w = g->window;
  1568. error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage);
  1569. if (error) {
  1570. LOG(("xwimp_get_window_state: 0x%x: %s",
  1571. error->errnum, error->errmess));
  1572. warn_user("WimpError", error->errmess);
  1573. return;
  1574. }
  1575. /* account for toolbar height, if present */
  1576. if (g->toolbar)
  1577. toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar);
  1578. height -= toolbar_height;
  1579. /* work with the state from now on so we can modify flags */
  1580. state.visible = open->visible;
  1581. state.xscroll = open->xscroll;
  1582. state.yscroll = open->yscroll;
  1583. state.next = open->next;
  1584. /* handle 'auto' scroll bars' and non-fitting scrollbar removal */
  1585. if ((g->bw->scrolling == SCROLLING_AUTO) ||
  1586. (g->bw->scrolling == SCROLLING_YES)) {
  1587. /* windows lose scrollbars when containing a frameset */
  1588. no_hscroll = (g->bw->children &&
  1589. (g->bw->browser_window_type !=
  1590. BROWSER_WINDOW_NORMAL));
  1591. no_vscroll = g->bw->children;
  1592. /* hscroll */
  1593. size = ro_get_hscroll_height(NULL);
  1594. if (g->bw->border)
  1595. size -= 2;
  1596. fheight = height;
  1597. if (state.flags & wimp_WINDOW_HSCROLL)
  1598. fheight += size;
  1599. if ((!no_hscroll) &&
  1600. ((fheight > size) ||
  1601. (g->bw->browser_window_type ==
  1602. BROWSER_WINDOW_NORMAL)) &&
  1603. ((h && width < content_get_width(h) *
  1604. 2 * g->bw->scale) ||
  1605. (g->bw->browser_window_type ==
  1606. BROWSER_WINDOW_NORMAL))) {
  1607. if (!(state.flags & wimp_WINDOW_HSCROLL)) {
  1608. height -= size;
  1609. state.visible.y0 += size;
  1610. if (h) {
  1611. g->bw->reformat_pending = true;
  1612. browser_reformat_pending = true;
  1613. }
  1614. }
  1615. state.flags |= wimp_WINDOW_HSCROLL;
  1616. } else {
  1617. if (state.flags & wimp_WINDOW_HSCROLL) {
  1618. height += size;
  1619. state.visible.y0 -= size;
  1620. if (h) {
  1621. g->bw->reformat_pending = true;
  1622. browser_reformat_pending = true;
  1623. }
  1624. }
  1625. state.flags &= ~wimp_WINDOW_HSCROLL;
  1626. }
  1627. /* vscroll */
  1628. size = ro_get_vscroll_width(NULL);
  1629. if (g->bw->border)
  1630. size -= 2;
  1631. fwidth = width;
  1632. if (state.flags & wimp_WINDOW_VSCROLL)
  1633. fwidth += size;
  1634. if ((!no_vscroll) &&
  1635. ((fwidth > size) ||
  1636. (g->bw->browser_window_type ==
  1637. BROWSER_WINDOW_NORMAL)) &&
  1638. ((h && height < content_get_height(h) *
  1639. 2 * g->bw->scale) ||
  1640. (g->bw->scrolling == SCROLLING_YES))) {
  1641. if (!(state.flags & wimp_WINDOW_VSCROLL)) {
  1642. width -= size;
  1643. state.visible.x1 -= size;
  1644. if (h) {
  1645. g->bw->reformat_pending = true;
  1646. browser_reformat_pending = true;
  1647. }
  1648. }
  1649. state.flags |= wimp_WINDOW_VSCROLL;
  1650. } else {
  1651. if (state.flags & wimp_WINDOW_VSCROLL) {
  1652. width += size;
  1653. state.

Large files files are truncated, but you can click here to view the full file