PageRenderTime 68ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/C0deMaver1ck/peeklinux
C | 2248 lines | 1719 code | 191 blank | 338 comment | 377 complexity | 5258496f5b9d407a85d243c1f2bfdf76 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 2004, 2005 Richard Wilson <info@tinct.net>
  3. *
  4. * This file is part of NetSurf, http://www.netsurf-browser.org/
  5. *
  6. * NetSurf is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; version 2 of the License.
  9. *
  10. * NetSurf is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /** \file
  19. * Window themes and toolbars (implementation).
  20. */
  21. #include <alloca.h>
  22. #include <assert.h>
  23. #include <stdio.h>
  24. #include <stdbool.h>
  25. #include <string.h>
  26. #include "oslib/dragasprite.h"
  27. #include "oslib/os.h"
  28. #include "oslib/osgbpb.h"
  29. #include "oslib/osfile.h"
  30. #include "oslib/osfind.h"
  31. #include "oslib/osspriteop.h"
  32. #include "oslib/wimpspriteop.h"
  33. #include "oslib/squash.h"
  34. #include "oslib/wimp.h"
  35. #include "oslib/wimpextend.h"
  36. #include "oslib/wimpspriteop.h"
  37. #include "content/content.h"
  38. #include "desktop/gui.h"
  39. #include "riscos/dialog.h"
  40. #include "riscos/gui.h"
  41. #include "riscos/menus.h"
  42. #include "riscos/options.h"
  43. #include "riscos/theme.h"
  44. #include "riscos/treeview.h"
  45. #include "riscos/wimp.h"
  46. #include "riscos/wimp_event.h"
  47. #include "riscos/wimputils.h"
  48. #include "utils/log.h"
  49. #include "utils/utils.h"
  50. #define THEME_URL_MEMORY 256
  51. #define THEME_THROBBER_MEMORY 12
  52. static struct theme_descriptor *theme_current = NULL;
  53. static struct theme_descriptor *theme_descriptors = NULL;
  54. static struct toolbar *theme_toolbar_drag = NULL;
  55. static struct toolbar_icon *theme_toolbar_icon_drag = NULL;
  56. static bool theme_toolbar_editor_drag = false;
  57. /* these order of the icons must match the numbers defined in riscos/gui.h */
  58. static const char * theme_browser_icons[] = {"back", "forward", "stop",
  59. "reload", "home", "history", "save", "print", "hotlist",
  60. "scale", "search", "up", NULL};
  61. static const char * theme_hotlist_icons[] = {"delete", "expand", "open",
  62. "launch", "create", NULL};
  63. static const char * theme_history_icons[] = {"delete", "expand", "open",
  64. "launch", NULL};
  65. static const char * theme_cookies_icons[] = {"delete", "expand", "open",
  66. NULL};
  67. static bool ro_gui_theme_add_descriptor(const char *folder, const char *leafname);
  68. static void ro_gui_theme_redraw(wimp_draw *redraw);
  69. static void ro_gui_theme_get_available_in_dir(const char *directory);
  70. static void ro_gui_theme_free(struct theme_descriptor *descriptor);
  71. static struct toolbar_icon *ro_gui_theme_add_toolbar_icon(
  72. struct toolbar *toolbar, const char *name, int icon_number);
  73. static void ro_gui_theme_update_toolbar_icon(struct toolbar *toolbar,
  74. struct toolbar_icon *icon);
  75. static void ro_gui_theme_destroy_toolbar_icon(struct toolbar_icon *icon);
  76. static void ro_gui_theme_link_toolbar_icon(struct toolbar *toolbar,
  77. struct toolbar_icon *icon, struct toolbar_icon *link,
  78. bool before);
  79. static void ro_gui_theme_delink_toolbar_icon(struct toolbar *toolbar,
  80. struct toolbar_icon *icon);
  81. static struct toolbar_icon *ro_gui_theme_toolbar_get_insert_icon(
  82. struct toolbar *toolbar, int x, int y, bool *before);
  83. static void ro_gui_theme_add_toolbar_icons(struct toolbar *toolbar,
  84. const char* icons[], const char* ident);
  85. static void ro_gui_theme_set_help_prefix(struct toolbar *toolbar);
  86. /* A basic window for the toolbar and status
  87. */
  88. static wimp_window theme_toolbar_window = {
  89. {0, 0, 1, 1},
  90. 0,
  91. 0,
  92. wimp_TOP,
  93. wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | wimp_WINDOW_NO_BOUNDS |
  94. wimp_WINDOW_FURNITURE_WINDOW |
  95. wimp_WINDOW_IGNORE_XEXTENT | wimp_WINDOW_IGNORE_YEXTENT,
  96. wimp_COLOUR_BLACK,
  97. wimp_COLOUR_LIGHT_GREY,
  98. wimp_COLOUR_LIGHT_GREY,
  99. wimp_COLOUR_VERY_LIGHT_GREY,
  100. wimp_COLOUR_DARK_GREY,
  101. wimp_COLOUR_MID_LIGHT_GREY,
  102. wimp_COLOUR_CREAM,
  103. wimp_WINDOW_NEVER3D | 0x16u /* RISC OS 5.03+ */,
  104. {0, 0, 16384, 16384},
  105. 0,
  106. 0,
  107. wimpspriteop_AREA,
  108. 1,
  109. 1,
  110. {""},
  111. 0,
  112. { }
  113. };
  114. /* Shared icon validation
  115. */
  116. static char theme_url_validation[] = "Pptr_write;KN";
  117. static char theme_null_text_string[] = "";
  118. static char theme_separator_name[] = "separator";
  119. static char theme_favicon_sprite[12];
  120. /**
  121. * Initialise the theme handler
  122. */
  123. void ro_gui_theme_initialise(void)
  124. {
  125. struct theme_descriptor *descriptor;
  126. theme_descriptors = ro_gui_theme_get_available();
  127. descriptor = ro_gui_theme_find(option_theme);
  128. if (!descriptor)
  129. descriptor = ro_gui_theme_find("Aletheia");
  130. ro_gui_theme_apply(descriptor);
  131. }
  132. /**
  133. * Finalise the theme handler
  134. */
  135. void ro_gui_theme_finalise(void)
  136. {
  137. ro_gui_theme_close(theme_current, false);
  138. ro_gui_theme_free(theme_descriptors);
  139. }
  140. /**
  141. * Finds a theme from the cached values.
  142. *
  143. * The returned theme is only guaranteed to be valid until the next call
  144. * to ro_gui_theme_get_available() unless it has been opened using
  145. * ro_gui_theme_open().
  146. *
  147. * \param leafname the filename of the theme_descriptor to return
  148. * \return the requested theme_descriptor, or NULL if not found
  149. */
  150. struct theme_descriptor *ro_gui_theme_find(const char *leafname)
  151. {
  152. struct theme_descriptor *descriptor;
  153. if (!leafname)
  154. return NULL;
  155. for (descriptor = theme_descriptors; descriptor;
  156. descriptor = descriptor->next)
  157. if (!strcmp(leafname, descriptor->leafname))
  158. return descriptor;
  159. /* fallback for 10 chars on old filesystems */
  160. for (descriptor = theme_descriptors; descriptor;
  161. descriptor = descriptor->next)
  162. if (!strncmp(leafname, descriptor->leafname, 10))
  163. return descriptor;
  164. return NULL;
  165. }
  166. /**
  167. * Reads and caches the currently available themes.
  168. *
  169. * \return the requested theme_descriptor, or NULL if not found
  170. */
  171. struct theme_descriptor *ro_gui_theme_get_available(void)
  172. {
  173. struct theme_descriptor *current;
  174. struct theme_descriptor *test;
  175. /* close any unused descriptors */
  176. ro_gui_theme_free(theme_descriptors);
  177. /* add our default 'Aletheia' theme */
  178. ro_gui_theme_add_descriptor("NetSurf:Resources", "Aletheia");
  179. /* scan our choices directory */
  180. ro_gui_theme_get_available_in_dir(option_theme_path);
  181. /* sort alphabetically in a very rubbish way */
  182. if ((theme_descriptors) && (theme_descriptors->next)) {
  183. current = theme_descriptors;
  184. while ((test = current->next)) {
  185. if (strcmp(current->name, test->name) > 0) {
  186. current->next->previous = current->previous;
  187. if (current->previous)
  188. current->previous->next = current->next;
  189. current->next = test->next;
  190. test->next = current;
  191. current->previous = test;
  192. if (current->next)
  193. current->next->previous = current;
  194. current = test->previous;
  195. if (!current) current = test;
  196. } else {
  197. current = current->next;
  198. }
  199. }
  200. while (theme_descriptors->previous)
  201. theme_descriptors = theme_descriptors->previous;
  202. }
  203. return theme_descriptors;
  204. }
  205. /**
  206. * Adds the themes in a directory to the global cache.
  207. *
  208. * \param directory the directory to scan
  209. */
  210. static void ro_gui_theme_get_available_in_dir(const char *directory)
  211. {
  212. int context = 0;
  213. int read_count;
  214. osgbpb_INFO(100) info;
  215. os_error *error;
  216. while (context != -1) {
  217. /* read some directory info */
  218. error = xosgbpb_dir_entries_info(directory,
  219. (osgbpb_info_list *) &info, 1, context,
  220. sizeof(info), 0, &read_count, &context);
  221. if (error) {
  222. LOG(("xosgbpb_dir_entries_info: 0x%x: %s",
  223. error->errnum, error->errmess));
  224. if (error->errnum == 0xd6) /* no such dir */
  225. return;
  226. warn_user("MiscError", error->errmess);
  227. break;
  228. }
  229. /* only process files */
  230. if ((read_count != 0) && (info.obj_type == fileswitch_IS_FILE))
  231. ro_gui_theme_add_descriptor(directory, info.name);
  232. }
  233. }
  234. /**
  235. * Checks a theme is valid and adds it to the current list
  236. *
  237. * \param folder the theme folder
  238. * \param leafname the theme leafname
  239. * \return whether the theme was added
  240. */
  241. bool ro_gui_theme_add_descriptor(const char *folder, const char *leafname)
  242. {
  243. struct theme_file_header file_header;
  244. struct theme_descriptor *current;
  245. struct theme_descriptor *test;
  246. int output_left;
  247. os_fw file_handle;
  248. os_error *error;
  249. char *filename;
  250. /* create a full filename */
  251. filename = malloc(strlen(folder) + strlen(leafname) + 2);
  252. if (!filename) {
  253. LOG(("No memory for malloc"));
  254. warn_user("NoMemory", 0);
  255. return false;
  256. }
  257. sprintf(filename, "%s.%s", folder, leafname);
  258. /* get the header */
  259. error = xosfind_openinw(osfind_NO_PATH, filename, 0,
  260. &file_handle);
  261. if (error) {
  262. LOG(("xosfind_openinw: 0x%x: %s",
  263. error->errnum, error->errmess));
  264. warn_user("FileError", error->errmess);
  265. free(filename);
  266. return false;
  267. }
  268. if (file_handle == 0) {
  269. free(filename);
  270. return false;
  271. }
  272. error = xosgbpb_read_atw(file_handle,
  273. (byte *) &file_header,
  274. sizeof (struct theme_file_header),
  275. 0, &output_left);
  276. xosfind_closew(file_handle);
  277. if (error) {
  278. LOG(("xosbgpb_read_atw: 0x%x: %s",
  279. error->errnum, error->errmess));
  280. warn_user("FileError", error->errmess);
  281. free(filename);
  282. return false;
  283. }
  284. if (output_left > 0) { /* should try to read more? */
  285. free(filename);
  286. return false;
  287. }
  288. /* create a new theme descriptor */
  289. current = (struct theme_descriptor *)calloc(1,
  290. sizeof(struct theme_descriptor));
  291. if (!current) {
  292. LOG(("calloc failed"));
  293. warn_user("NoMemory", 0);
  294. free(filename);
  295. return false;
  296. }
  297. if (!ro_gui_theme_read_file_header(current, &file_header)) {
  298. free(filename);
  299. free(current);
  300. return false;
  301. }
  302. current->filename = filename;
  303. current->leafname = current->filename + strlen(folder) + 1;
  304. /* don't add duplicates */
  305. for (test = theme_descriptors; test; test = test->next) {
  306. if (!strcmp(current->name, test->name)) {
  307. free(current->filename);
  308. free(current);
  309. return false;
  310. }
  311. }
  312. /* link in our new descriptor at the head*/
  313. if (theme_descriptors) {
  314. current->next = theme_descriptors;
  315. theme_descriptors->previous = current;
  316. }
  317. theme_descriptors = current;
  318. return true;
  319. }
  320. /**
  321. * Fills in the basic details for a descriptor from a file header.
  322. * The filename string is not set.
  323. *
  324. * \param descriptor the descriptor to set up
  325. * \param file_header the header to read from
  326. * \return false for a badly formed theme, true otherwise
  327. */
  328. bool ro_gui_theme_read_file_header(struct theme_descriptor *descriptor,
  329. struct theme_file_header *file_header)
  330. {
  331. if ((file_header->magic_value != 0x4d54534e) ||
  332. (file_header->parser_version > 2))
  333. return false;
  334. strcpy(descriptor->name, file_header->name);
  335. strcpy(descriptor->author, file_header->author);
  336. descriptor->browser_background = file_header->browser_bg;
  337. descriptor->hotlist_background = file_header->hotlist_bg;
  338. descriptor->status_background = file_header->status_bg;
  339. descriptor->status_foreground = file_header->status_fg;
  340. descriptor->decompressed_size = file_header->decompressed_sprite_size;
  341. descriptor->compressed_size = file_header->compressed_sprite_size;
  342. if (file_header->parser_version >= 2) {
  343. descriptor->throbber_right =
  344. !(file_header->theme_flags & (1 << 0));
  345. descriptor->throbber_redraw =
  346. file_header->theme_flags & (1 << 1);
  347. } else {
  348. descriptor->throbber_right =
  349. (file_header->theme_flags == 0x00);
  350. descriptor->throbber_redraw = true;
  351. }
  352. return true;
  353. }
  354. /**
  355. * Opens a theme ready for use.
  356. *
  357. * \param descriptor the theme_descriptor to open
  358. * \param list whether to open all themes in the list
  359. * \return whether the operation was successful
  360. */
  361. bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
  362. {
  363. fileswitch_object_type obj_type;
  364. squash_output_status status;
  365. os_coord dimensions;
  366. os_mode mode;
  367. os_error *error;
  368. struct theme_descriptor *next_descriptor;
  369. char sprite_name[16];
  370. const char *name = sprite_name;
  371. bool result = true;
  372. int i, n;
  373. int workspace_size, file_size;
  374. char *raw_data, *workspace;
  375. osspriteop_area *decompressed;
  376. /* If we are freeing the whole of the list then we need to
  377. start at the first descriptor.
  378. */
  379. if (list && descriptor)
  380. while (descriptor->previous) descriptor = descriptor->previous;
  381. /* Open the themes
  382. */
  383. for (; descriptor; descriptor = next_descriptor) {
  384. /* see if we should iterate through the entire list */
  385. if (list)
  386. next_descriptor = descriptor->next;
  387. else
  388. next_descriptor = NULL;
  389. /* if we are already loaded, increase the usage count */
  390. if (descriptor->theme) {
  391. descriptor->theme->users = descriptor->theme->users + 1;
  392. continue;
  393. }
  394. /* create a new theme */
  395. descriptor->theme = (struct theme *)calloc(1,
  396. sizeof(struct theme));
  397. if (!descriptor->theme) {
  398. LOG(("calloc() failed"));
  399. warn_user("NoMemory", 0);
  400. continue;
  401. }
  402. descriptor->theme->users = 1;
  403. /* try to load the associated file */
  404. error = xosfile_read_stamped_no_path(descriptor->filename,
  405. &obj_type, 0, 0, &file_size, 0, 0);
  406. if (error) {
  407. LOG(("xosfile_read_stamped_no_path: 0x%x: %s",
  408. error->errnum, error->errmess));
  409. warn_user("FileError", error->errmess);
  410. continue;
  411. }
  412. if (obj_type != fileswitch_IS_FILE)
  413. continue;
  414. raw_data = malloc(file_size);
  415. if (!raw_data) {
  416. LOG(("malloc() failed"));
  417. warn_user("NoMemory", 0);
  418. continue;
  419. }
  420. error = xosfile_load_stamped_no_path(descriptor->filename,
  421. (byte *)raw_data, 0, 0, 0, 0, 0);
  422. if (error) {
  423. free(raw_data);
  424. LOG(("xosfile_load_stamped_no_path: 0x%x: %s",
  425. error->errnum, error->errmess));
  426. warn_user("FileError", error->errmess);
  427. continue;
  428. }
  429. /* decompress the new data */
  430. error = xsquash_decompress_return_sizes(-1, &workspace_size, 0);
  431. if (error) {
  432. free(raw_data);
  433. LOG(("xsquash_decompress_return_sizes: 0x%x: %s",
  434. error->errnum, error->errmess));
  435. warn_user("MiscError", error->errmess);
  436. continue;
  437. }
  438. decompressed = (osspriteop_area *)malloc(
  439. descriptor->decompressed_size);
  440. workspace = malloc(workspace_size);
  441. if ((!decompressed) || (!workspace)) {
  442. free(decompressed);
  443. free(raw_data);
  444. LOG(("malloc() failed"));
  445. warn_user("NoMemory", 0);
  446. continue;
  447. }
  448. error = xsquash_decompress(squash_INPUT_ALL_PRESENT, workspace,
  449. (byte *)(raw_data + sizeof(
  450. struct theme_file_header)),
  451. descriptor->compressed_size,
  452. (byte *)decompressed,
  453. descriptor->decompressed_size,
  454. &status, 0, 0, 0, 0);
  455. free(workspace);
  456. free(raw_data);
  457. if (error) {
  458. free(decompressed);
  459. LOG(("xsquash_decompress: 0x%x: %s",
  460. error->errnum, error->errmess));
  461. warn_user("MiscError", error->errmess);
  462. continue;
  463. }
  464. if (status != 0) {
  465. free(decompressed);
  466. continue;
  467. }
  468. descriptor->theme->sprite_area = decompressed;
  469. /* find the highest sprite called 'throbber%i', and get the
  470. * maximum dimensions for all 'thobber%i' icons. */
  471. for (i = 1; i <= descriptor->theme->sprite_area->sprite_count;
  472. i++) {
  473. error = xosspriteop_return_name(osspriteop_USER_AREA,
  474. descriptor->theme->sprite_area,
  475. sprite_name, 16, i, 0);
  476. if (error) {
  477. LOG(("xosspriteop_return_name: 0x%x: %s",
  478. error->errnum, error->errmess));
  479. warn_user("MiscError", error->errmess);
  480. continue;
  481. }
  482. if (strncmp(sprite_name, "throbber", 8))
  483. continue;
  484. /* get the max sprite width/height */
  485. error = xosspriteop_read_sprite_info(
  486. osspriteop_USER_AREA,
  487. descriptor->theme->sprite_area,
  488. (osspriteop_id) name,
  489. &dimensions.x, &dimensions.y,
  490. (osbool *) 0, &mode);
  491. if (error) {
  492. LOG(("xosspriteop_read_sprite_info: 0x%x: %s",
  493. error->errnum, error->errmess));
  494. warn_user("MiscError", error->errmess);
  495. continue;
  496. }
  497. ro_convert_pixels_to_os_units(&dimensions, mode);
  498. if (descriptor->theme->throbber_width < dimensions.x)
  499. descriptor->theme->throbber_width =
  500. dimensions.x;
  501. if (descriptor->theme->throbber_height < dimensions.y)
  502. descriptor->theme->throbber_height =
  503. dimensions.y;
  504. /* get the throbber number */
  505. n = atoi(sprite_name + 8);
  506. if (descriptor->theme->throbber_frames < n)
  507. descriptor->theme->throbber_frames = n;
  508. }
  509. }
  510. return result;
  511. }
  512. /**
  513. * Applies the theme to all current windows and subsequent ones.
  514. *
  515. * \param descriptor the theme_descriptor to open
  516. * \return whether the operation was successful
  517. */
  518. bool ro_gui_theme_apply(struct theme_descriptor *descriptor)
  519. {
  520. struct theme_descriptor *theme_previous;
  521. /* check if the theme is already applied */
  522. if (descriptor == theme_current)
  523. return true;
  524. /* re-open the new-theme and release the current theme */
  525. if (!ro_gui_theme_open(descriptor, false))
  526. return false;
  527. theme_previous = theme_current;
  528. theme_current = descriptor;
  529. /* apply the theme to all the current windows */
  530. ro_gui_window_update_theme();
  531. ro_gui_tree_update_theme(hotlist_tree);
  532. ro_gui_tree_update_theme(global_history_tree);
  533. ro_gui_tree_update_theme(cookies_tree);
  534. ro_gui_theme_close(theme_previous, false);
  535. return true;
  536. }
  537. /**
  538. * Closes a theme after use.
  539. *
  540. * \param descriptor the theme_descriptor to close
  541. * \param list whether to open all themes in the list
  542. * \return whether the operation was successful
  543. */
  544. void ro_gui_theme_close(struct theme_descriptor *descriptor, bool list)
  545. {
  546. if (!descriptor)
  547. return;
  548. /* move to the start of the list */
  549. while (list && descriptor->previous)
  550. descriptor = descriptor->previous;
  551. /* close the themes */
  552. while (descriptor) {
  553. if (descriptor->theme) {
  554. descriptor->theme->users = descriptor->theme->users - 1;
  555. if (descriptor->theme->users <= 0) {
  556. free(descriptor->theme->sprite_area);
  557. free(descriptor->theme);
  558. descriptor->theme = NULL;
  559. }
  560. }
  561. if (!list)
  562. return;
  563. descriptor = descriptor->next;
  564. }
  565. }
  566. /**
  567. * Performs the redraw for a toolbar
  568. *
  569. * \param redraw the redraw area
  570. * \param toolbar the toolbar to redraw
  571. */
  572. void ro_gui_theme_redraw(wimp_draw *redraw)
  573. {
  574. struct toolbar *toolbar;
  575. struct gui_window *g;
  576. struct toolbar_icon *icon;
  577. osbool more;
  578. wimp_icon separator_icon;
  579. os_error *error;
  580. bool perform_redraw = false;
  581. toolbar = (struct toolbar *)ro_gui_wimp_event_get_user_data(redraw->w);
  582. assert(toolbar);
  583. /* set the content-type icon */
  584. g = ro_gui_toolbar_lookup(toolbar->toolbar_handle);
  585. /* only set type for browser windows */
  586. sprintf(theme_favicon_sprite, "Ssmall_xxx");
  587. if (g) {
  588. assert(toolbar->type == THEME_BROWSER_TOOLBAR);
  589. assert(g->bw);
  590. if (g->bw->current_content) {
  591. sprintf(theme_favicon_sprite, "Ssmall_%.3x",
  592. ro_content_filetype_from_type(
  593. content_get_type(g->bw->current_content)));
  594. if (!ro_gui_wimp_sprite_exists(theme_favicon_sprite + 1))
  595. sprintf(theme_favicon_sprite, "Ssmall_xxx");
  596. }
  597. }
  598. /* set up the icon */
  599. if ((toolbar->descriptor) && (toolbar->descriptor->theme) &&
  600. (toolbar->descriptor->theme->sprite_area)) {
  601. const char *name = theme_separator_name;
  602. separator_icon.flags = wimp_ICON_SPRITE | wimp_ICON_INDIRECTED |
  603. wimp_ICON_HCENTRED | wimp_ICON_VCENTRED;
  604. separator_icon.data.indirected_sprite.id = (osspriteop_id) name;
  605. separator_icon.data.indirected_sprite.area =
  606. toolbar->descriptor->theme->sprite_area;
  607. separator_icon.data.indirected_sprite.size = 12;
  608. separator_icon.extent.y0 = 0;
  609. separator_icon.extent.y1 = toolbar->height;
  610. perform_redraw = true;
  611. }
  612. perform_redraw &= toolbar->display_buttons || toolbar->editor;
  613. if ((toolbar->editor) && (toolbar->editor->toolbar_handle == redraw->w))
  614. toolbar = toolbar->editor;
  615. error = xwimp_redraw_window(redraw, &more);
  616. if (error) {
  617. LOG(("xwimp_redraw_window: 0x%x: %s",
  618. error->errnum, error->errmess));
  619. warn_user("WimpError", error->errmess);
  620. return;
  621. }
  622. while (more) {
  623. if (perform_redraw)
  624. for (icon = toolbar->icon; icon; icon = icon->next)
  625. if ((icon->icon_number == -1) &&
  626. (icon->display)) {
  627. separator_icon.extent.x0 = icon->x;
  628. separator_icon.extent.x1 = icon->x +
  629. icon->width;
  630. xwimp_plot_icon(&separator_icon);
  631. }
  632. error = xwimp_get_rectangle(redraw, &more);
  633. if (error) {
  634. LOG(("xwimp_get_rectangle: 0x%x: %s",
  635. error->errnum, error->errmess));
  636. warn_user("WimpError", error->errmess);
  637. return;
  638. }
  639. }
  640. }
  641. /**
  642. * Frees any unused theme descriptors.
  643. *
  644. * \param descriptor the theme_descriptor to free
  645. * \param list whether to open all themes in the list
  646. * \return whether the operation was successful
  647. */
  648. void ro_gui_theme_free(struct theme_descriptor *descriptor)
  649. {
  650. struct theme_descriptor *next_descriptor;
  651. if (!descriptor)
  652. return;
  653. /* move to the start of the list */
  654. while (descriptor->previous)
  655. descriptor = descriptor->previous;
  656. /* free closed themes */
  657. for (; descriptor; descriptor = next_descriptor) {
  658. next_descriptor = descriptor->next;
  659. /* no theme? no descriptor */
  660. if (!descriptor->theme) {
  661. if (descriptor->previous)
  662. descriptor->previous->next = descriptor->next;
  663. if (descriptor->next)
  664. descriptor->next->previous =
  665. descriptor->previous;
  666. /* keep the cached list in sync */
  667. if (theme_descriptors == descriptor)
  668. theme_descriptors = next_descriptor;
  669. /* release any memory */
  670. free(descriptor->filename);
  671. free(descriptor);
  672. }
  673. }
  674. }
  675. /**
  676. * Creates a toolbar.
  677. *
  678. * \param descriptor the theme to use, or NULL for current
  679. * \param type the toolbar type
  680. * \return a new toolbar, or NULL for failure
  681. */
  682. struct toolbar *ro_gui_theme_create_toolbar(struct theme_descriptor *descriptor,
  683. toolbar_type type)
  684. {
  685. struct toolbar *toolbar;
  686. /* Create a new toolbar
  687. */
  688. toolbar = calloc(sizeof(struct toolbar), 1);
  689. if (!toolbar) {
  690. LOG(("No memory for malloc()"));
  691. warn_user("NoMemory", 0);
  692. return NULL;
  693. }
  694. toolbar->type = type;
  695. /* Store the theme
  696. */
  697. if (!descriptor) descriptor = theme_current;
  698. toolbar->descriptor = descriptor;
  699. /* Apply the default settings
  700. */
  701. toolbar->display_buttons = true;
  702. toolbar->toolbar_current = 16384;
  703. switch (type) {
  704. case THEME_BROWSER_TOOLBAR:
  705. toolbar->display_url = true;
  706. toolbar->display_throbber = true;
  707. ro_gui_theme_add_toolbar_icons(toolbar,
  708. theme_browser_icons,
  709. option_toolbar_browser);
  710. toolbar->suggest = ro_gui_theme_add_toolbar_icon(NULL,
  711. "gright",
  712. ICON_TOOLBAR_SUGGEST);
  713. break;
  714. case THEME_HOTLIST_TOOLBAR:
  715. ro_gui_theme_add_toolbar_icons(toolbar,
  716. theme_hotlist_icons,
  717. option_toolbar_hotlist);
  718. break;
  719. case THEME_HISTORY_TOOLBAR:
  720. ro_gui_theme_add_toolbar_icons(toolbar,
  721. theme_history_icons,
  722. option_toolbar_history);
  723. break;
  724. case THEME_COOKIES_TOOLBAR:
  725. ro_gui_theme_add_toolbar_icons(toolbar,
  726. theme_cookies_icons,
  727. option_toolbar_cookies);
  728. break;
  729. case THEME_BROWSER_EDIT_TOOLBAR:
  730. ro_gui_theme_add_toolbar_icons(toolbar,
  731. theme_browser_icons,
  732. "0123456789ab|");
  733. break;
  734. case THEME_HOTLIST_EDIT_TOOLBAR:
  735. ro_gui_theme_add_toolbar_icons(toolbar,
  736. theme_hotlist_icons,
  737. "40123|");
  738. break;
  739. case THEME_HISTORY_EDIT_TOOLBAR:
  740. ro_gui_theme_add_toolbar_icons(toolbar,
  741. theme_history_icons,
  742. "0123|");
  743. break;
  744. case THEME_COOKIES_EDIT_TOOLBAR:
  745. ro_gui_theme_add_toolbar_icons(toolbar,
  746. theme_cookies_icons,
  747. "012|");
  748. break;
  749. }
  750. /* Claim the memory for our Wimp indirection
  751. */
  752. if (type == THEME_BROWSER_TOOLBAR) {
  753. toolbar->url_buffer = calloc(1, THEME_URL_MEMORY +
  754. THEME_THROBBER_MEMORY);
  755. if (!toolbar->url_buffer) {
  756. LOG(("No memory for calloc()"));
  757. ro_gui_theme_destroy_toolbar(toolbar);
  758. return NULL;
  759. }
  760. toolbar->throbber_buffer = toolbar->url_buffer +
  761. THEME_URL_MEMORY;
  762. sprintf(toolbar->throbber_buffer, "throbber0");
  763. }
  764. /* Apply the desired theme to the toolbar
  765. */
  766. if (!ro_gui_theme_update_toolbar(descriptor, toolbar)) {
  767. ro_gui_theme_destroy_toolbar(toolbar);
  768. return NULL;
  769. }
  770. toolbar->old_height = ro_gui_theme_toolbar_full_height(toolbar);
  771. return toolbar;
  772. }
  773. /**
  774. * Updates a toolbar to use a particular theme.
  775. * The toolbar may be unstable on failure and should be destroyed.
  776. *
  777. * \param descriptor the theme to use, or NULL for current
  778. * \param toolbar the toolbar to update
  779. * \return whether the operation was successful
  780. */
  781. bool ro_gui_theme_update_toolbar(struct theme_descriptor *descriptor,
  782. struct toolbar *toolbar)
  783. {
  784. wimp_icon_create new_icon;
  785. os_error *error;
  786. osspriteop_area *sprite_area;
  787. struct toolbar_icon *toolbar_icon;
  788. int width, max_icon;
  789. wimp_icon_flags icon_flags;
  790. struct gui_window *g;
  791. if (!toolbar) return false;
  792. /* Set the theme and window sprite area
  793. */
  794. if (!descriptor) descriptor = theme_current;
  795. toolbar->descriptor = descriptor;
  796. if ((toolbar->descriptor) && (toolbar->descriptor->theme))
  797. sprite_area = toolbar->descriptor->theme->sprite_area;
  798. else
  799. sprite_area = (osspriteop_area *)1;
  800. theme_toolbar_window.sprite_area = sprite_area;
  801. /* Update the icon sizes
  802. */
  803. for (toolbar_icon = toolbar->icon; toolbar_icon;
  804. toolbar_icon = toolbar_icon->next)
  805. ro_gui_theme_update_toolbar_icon(toolbar, toolbar_icon);
  806. if (toolbar->suggest)
  807. ro_gui_theme_update_toolbar_icon(toolbar, toolbar->suggest);
  808. /* Recreate the toolbar window
  809. */
  810. if (toolbar->descriptor) {
  811. if (toolbar->type == THEME_BROWSER_TOOLBAR)
  812. theme_toolbar_window.work_bg =
  813. toolbar->descriptor->browser_background;
  814. else
  815. theme_toolbar_window.work_bg =
  816. toolbar->descriptor->hotlist_background;
  817. } else {
  818. theme_toolbar_window.work_bg = wimp_COLOUR_VERY_LIGHT_GREY;
  819. }
  820. theme_toolbar_window.work_flags &= ~wimp_ICON_BUTTON_TYPE;
  821. if ((toolbar->editor) ||
  822. (toolbar->type == THEME_HOTLIST_EDIT_TOOLBAR) ||
  823. (toolbar->type == THEME_HISTORY_EDIT_TOOLBAR) ||
  824. (toolbar->type == THEME_BROWSER_EDIT_TOOLBAR) ||
  825. (toolbar->type == THEME_COOKIES_EDIT_TOOLBAR))
  826. theme_toolbar_window.work_flags |= (wimp_BUTTON_CLICK_DRAG <<
  827. wimp_ICON_BUTTON_TYPE_SHIFT);
  828. theme_toolbar_window.sprite_area = sprite_area;
  829. if (toolbar->toolbar_handle) {
  830. error = xwimp_delete_window(toolbar->toolbar_handle);
  831. if (error)
  832. LOG(("xwimp_delete_window: 0x%x: %s",
  833. error->errnum, error->errmess));
  834. ro_gui_wimp_event_finalise(toolbar->toolbar_handle);
  835. toolbar->toolbar_handle = NULL;
  836. }
  837. error = xwimp_create_window(&theme_toolbar_window,
  838. &toolbar->toolbar_handle);
  839. if (error) {
  840. LOG(("xwimp_create_window: 0x%x: %s",
  841. error->errnum, error->errmess));
  842. warn_user("WimpError", error->errmess);
  843. return false;
  844. }
  845. ro_gui_wimp_event_register_redraw_window(toolbar->toolbar_handle,
  846. ro_gui_theme_redraw);
  847. ro_gui_wimp_event_set_user_data(toolbar->toolbar_handle, toolbar);
  848. switch (toolbar->type) {
  849. case THEME_BROWSER_TOOLBAR:
  850. case THEME_BROWSER_EDIT_TOOLBAR:
  851. ro_gui_wimp_event_register_mouse_click(toolbar->toolbar_handle,
  852. ro_gui_toolbar_click);
  853. break;
  854. case THEME_HOTLIST_TOOLBAR:
  855. case THEME_HOTLIST_EDIT_TOOLBAR:
  856. case THEME_HISTORY_TOOLBAR:
  857. case THEME_HISTORY_EDIT_TOOLBAR:
  858. case THEME_COOKIES_TOOLBAR:
  859. case THEME_COOKIES_EDIT_TOOLBAR:
  860. ro_gui_wimp_event_register_mouse_click(toolbar->toolbar_handle,
  861. ro_gui_tree_toolbar_click);
  862. break;
  863. }
  864. /* Create the basic icons
  865. */
  866. if ((toolbar->type == THEME_HOTLIST_TOOLBAR) ||
  867. (toolbar->type == THEME_HOTLIST_EDIT_TOOLBAR))
  868. max_icon = ICON_TOOLBAR_HOTLIST_LAST;
  869. else if ((toolbar->type == THEME_HISTORY_TOOLBAR) ||
  870. (toolbar->type == THEME_HISTORY_EDIT_TOOLBAR))
  871. max_icon = ICON_TOOLBAR_HISTORY_LAST;
  872. else if ((toolbar->type == THEME_COOKIES_TOOLBAR) ||
  873. (toolbar->type == THEME_COOKIES_EDIT_TOOLBAR))
  874. max_icon = ICON_TOOLBAR_COOKIES_LAST;
  875. else
  876. max_icon = ICON_TOOLBAR_LAST;
  877. new_icon.w = toolbar->toolbar_handle;
  878. new_icon.icon.data.indirected_text.size = 1;
  879. new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE |
  880. wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED |
  881. wimp_ICON_VCENTRED;
  882. if ((toolbar->editor) ||
  883. (toolbar->type == THEME_HOTLIST_EDIT_TOOLBAR) ||
  884. (toolbar->type == THEME_HISTORY_EDIT_TOOLBAR) ||
  885. (toolbar->type == THEME_COOKIES_EDIT_TOOLBAR) ||
  886. (toolbar->type == THEME_BROWSER_EDIT_TOOLBAR))
  887. new_icon.icon.flags |= (wimp_BUTTON_CLICK_DRAG <<
  888. wimp_ICON_BUTTON_TYPE_SHIFT);
  889. else
  890. new_icon.icon.flags |= (wimp_BUTTON_CLICK <<
  891. wimp_ICON_BUTTON_TYPE_SHIFT);
  892. if (toolbar->descriptor)
  893. new_icon.icon.flags |= (toolbar->descriptor->browser_background
  894. << wimp_ICON_BG_COLOUR_SHIFT);
  895. else
  896. new_icon.icon.flags |= (wimp_COLOUR_VERY_LIGHT_GREY
  897. << wimp_ICON_BG_COLOUR_SHIFT);
  898. icon_flags = new_icon.icon.flags;
  899. for (int i = 0; i < max_icon; i++) {
  900. new_icon.icon.data.indirected_text.text =
  901. theme_null_text_string;
  902. new_icon.icon.data.indirected_text.validation =
  903. theme_null_text_string;
  904. toolbar_icon = toolbar->icon;
  905. while (toolbar_icon) {
  906. if (toolbar_icon->icon_number == i) {
  907. new_icon.icon.data.indirected_text.validation =
  908. toolbar_icon->validation;
  909. break;
  910. } else {
  911. toolbar_icon = toolbar_icon->next;
  912. }
  913. }
  914. error = xwimp_create_icon(&new_icon, 0);
  915. if (error) {
  916. LOG(("xwimp_create_icon: 0x%x: %s",
  917. error->errnum, error->errmess));
  918. warn_user("WimpError", error->errmess);
  919. return false;
  920. }
  921. }
  922. /* Create the URL/throbber icons
  923. */
  924. if (toolbar->type == THEME_BROWSER_TOOLBAR) {
  925. /* container for all URL bits (ie border) */
  926. new_icon.icon.flags = wimp_ICON_BORDER | (wimp_COLOUR_BLACK <<
  927. wimp_ICON_FG_COLOUR_SHIFT);
  928. error = xwimp_create_icon(&new_icon, 0);
  929. if (error) {
  930. LOG(("xwimp_create_icon: 0x%x: %s",
  931. error->errnum, error->errmess));
  932. warn_user("WimpError", error->errmess);
  933. return false;
  934. }
  935. /* favicon image */
  936. new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE |
  937. wimp_ICON_INDIRECTED | wimp_ICON_FILLED |
  938. wimp_ICON_HCENTRED | wimp_ICON_VCENTRED |
  939. (wimp_BUTTON_CLICK_DRAG <<
  940. wimp_ICON_BUTTON_TYPE_SHIFT);
  941. new_icon.icon.data.indirected_text.text = theme_null_text_string;
  942. new_icon.icon.data.indirected_text.validation =
  943. theme_favicon_sprite;
  944. new_icon.icon.data.indirected_text.size = 1;
  945. error = xwimp_create_icon(&new_icon, 0);
  946. if (error) {
  947. LOG(("xwimp_create_icon: 0x%x: %s",
  948. error->errnum, error->errmess));
  949. warn_user("WimpError", error->errmess);
  950. return false;
  951. }
  952. /* Writable text portion */
  953. new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
  954. wimp_ICON_VCENTRED |
  955. wimp_ICON_FILLED | (wimp_COLOUR_BLACK <<
  956. wimp_ICON_FG_COLOUR_SHIFT) |
  957. (wimp_BUTTON_WRITE_CLICK_DRAG <<
  958. wimp_ICON_BUTTON_TYPE_SHIFT);
  959. new_icon.icon.data.indirected_text.text = toolbar->url_buffer;
  960. new_icon.icon.data.indirected_text.validation =
  961. theme_url_validation;
  962. new_icon.icon.data.indirected_text.size = THEME_URL_MEMORY;
  963. error = xwimp_create_icon(&new_icon, 0);
  964. if (error) {
  965. LOG(("xwimp_create_icon: 0x%x: %s",
  966. error->errnum, error->errmess));
  967. warn_user("WimpError", error->errmess);
  968. return false;
  969. }
  970. /* Now the URL suggestion icon
  971. */
  972. new_icon.icon.data.indirected_text.text =
  973. theme_null_text_string;
  974. new_icon.icon.data.indirected_text.size = 1;
  975. new_icon.icon.flags = icon_flags | (wimp_BUTTON_CLICK <<
  976. wimp_ICON_BUTTON_TYPE_SHIFT);
  977. if (toolbar->suggest)
  978. new_icon.icon.data.indirected_text.validation =
  979. toolbar->suggest->validation;
  980. else
  981. new_icon.icon.data.indirected_text.validation =
  982. theme_null_text_string;
  983. error = xwimp_create_icon(&new_icon, 0);
  984. if (error) {
  985. LOG(("xwimp_create_icon: 0x%x: %s",
  986. error->errnum, error->errmess));
  987. warn_user("WimpError", error->errmess);
  988. return false;
  989. }
  990. /* Now the throbber
  991. */
  992. new_icon.icon.flags = wimp_ICON_SPRITE | wimp_ICON_INDIRECTED |
  993. wimp_ICON_HCENTRED | wimp_ICON_VCENTRED;
  994. new_icon.icon.data.indirected_sprite.id =
  995. (osspriteop_id)toolbar->throbber_buffer;
  996. new_icon.icon.data.indirected_sprite.area = sprite_area;
  997. new_icon.icon.data.indirected_sprite.size =
  998. THEME_THROBBER_MEMORY;
  999. error = xwimp_create_icon(&new_icon, 0);
  1000. if (error) {
  1001. LOG(("xwimp_create_icon: 0x%x: %s",
  1002. error->errnum, error->errmess));
  1003. warn_user("WimpError", error->errmess);
  1004. return false;
  1005. }
  1006. }
  1007. if (toolbar->parent_handle)
  1008. ro_gui_theme_attach_toolbar(toolbar, toolbar->parent_handle);
  1009. /* Force a re-processing of the toolbar
  1010. */
  1011. width = toolbar->toolbar_current;
  1012. toolbar->reformat_buttons = true;
  1013. toolbar->toolbar_current = -1;
  1014. ro_gui_theme_process_toolbar(toolbar, width);
  1015. /* Keep menus up to date etc
  1016. */
  1017. ro_gui_theme_set_help_prefix(toolbar);
  1018. switch (toolbar->type) {
  1019. case THEME_BROWSER_TOOLBAR:
  1020. g = ro_gui_window_lookup(toolbar->parent_handle);
  1021. if (g)
  1022. ro_gui_prepare_navigate(g);
  1023. break;
  1024. case THEME_HOTLIST_TOOLBAR:
  1025. case THEME_HISTORY_TOOLBAR:
  1026. case THEME_COOKIES_TOOLBAR:
  1027. ro_gui_menu_prepare_action(toolbar->parent_handle,
  1028. TREE_SELECTION, false);
  1029. ro_gui_menu_prepare_action(toolbar->parent_handle,
  1030. TREE_EXPAND_ALL, false);
  1031. break;
  1032. default:
  1033. break;
  1034. }
  1035. return true;
  1036. }
  1037. /**
  1038. * Attaches a toolbar to a window.
  1039. *
  1040. * \param toolbar the toolbar to update
  1041. * \param parent the window to contain the toolbar
  1042. * \return whether the operation was successful
  1043. */
  1044. bool ro_gui_theme_attach_toolbar(struct toolbar *toolbar, wimp_w parent)
  1045. {
  1046. wimp_outline outline;
  1047. wimp_window_state state;
  1048. int height;
  1049. os_error *error;
  1050. if (!toolbar)
  1051. return false;
  1052. /* Attach/close the windows
  1053. */
  1054. toolbar->parent_handle = parent;
  1055. height = ro_gui_theme_toolbar_height(toolbar);
  1056. if (height > 0) {
  1057. outline.w = parent;
  1058. xwimp_get_window_outline(&outline);
  1059. state.w = parent;
  1060. xwimp_get_window_state(&state);
  1061. state.w = toolbar->toolbar_handle;
  1062. state.visible.x1 = outline.outline.x1 - 2;
  1063. state.visible.y0 = state.visible.y1 - height + 2;
  1064. state.xscroll = 0;
  1065. state.yscroll = toolbar->height - 2; /* clipped by the WIMP */
  1066. error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), parent,
  1067. wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
  1068. << wimp_CHILD_XORIGIN_SHIFT |
  1069. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1070. << wimp_CHILD_YORIGIN_SHIFT |
  1071. wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
  1072. << wimp_CHILD_LS_EDGE_SHIFT |
  1073. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1074. << wimp_CHILD_BS_EDGE_SHIFT |
  1075. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1076. << wimp_CHILD_RS_EDGE_SHIFT |
  1077. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1078. << wimp_CHILD_TS_EDGE_SHIFT);
  1079. if (error) {
  1080. LOG(("xwimp_open_window_nested: 0x%x: %s",
  1081. error->errnum, error->errmess));
  1082. warn_user("WimpError", error->errmess);
  1083. return false;
  1084. }
  1085. if (!toolbar->editor)
  1086. return true;
  1087. state.w = toolbar->editor->toolbar_handle;
  1088. state.visible.y1 -= toolbar->height;
  1089. state.yscroll = toolbar->editor->height - 2;
  1090. error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
  1091. toolbar->toolbar_handle,
  1092. wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
  1093. << wimp_CHILD_XORIGIN_SHIFT |
  1094. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1095. << wimp_CHILD_YORIGIN_SHIFT |
  1096. wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
  1097. << wimp_CHILD_LS_EDGE_SHIFT |
  1098. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1099. << wimp_CHILD_BS_EDGE_SHIFT |
  1100. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1101. << wimp_CHILD_RS_EDGE_SHIFT |
  1102. wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
  1103. << wimp_CHILD_TS_EDGE_SHIFT);
  1104. if (error) {
  1105. LOG(("xwimp_open_window_nested: 0x%x: %s",
  1106. error->errnum, error->errmess));
  1107. warn_user("WimpError", error->errmess);
  1108. return false;
  1109. }
  1110. return true;
  1111. }
  1112. error = xwimp_close_window(toolbar->toolbar_handle);
  1113. if (error) {
  1114. LOG(("xwimp_close_window: 0x%x: %s",
  1115. error->errnum, error->errmess));
  1116. warn_user("WimpError", error->errmess);
  1117. return false;
  1118. }
  1119. return true;
  1120. }
  1121. /**
  1122. * Updates the toolbar to reflect changes to the icon flags and any reformatting
  1123. * required due to the change in parent window size.
  1124. *
  1125. * \param toolbar the toolbar to update
  1126. * \param width a specific width to resize to, or -1 to use parent width
  1127. * \return whether the operation was successful
  1128. */
  1129. bool ro_gui_theme_process_toolbar(struct toolbar *toolbar, int width)
  1130. {
  1131. wimp_caret caret;
  1132. os_box extent = { 0, 0, 0, 0 };
  1133. os_error *error;
  1134. wimp_outline outline;
  1135. wimp_window_state state;
  1136. int height = -1;
  1137. int throbber_x = -1;
  1138. int left_edge, right_edge, bottom_edge;
  1139. int old_height;
  1140. int old_width;
  1141. struct toolbar_icon *toolbar_icon;
  1142. bool visible_icon = false;
  1143. int collapse_height;
  1144. int xeig, yeig;
  1145. os_coord pixel = {1, 1};
  1146. int top, bottom, right;
  1147. if (!toolbar)
  1148. return false;
  1149. old_height = toolbar->height;
  1150. old_width = toolbar->toolbar_current;
  1151. /* calculate 1px in OS units */
  1152. ro_convert_pixels_to_os_units(&pixel, (os_mode)-1);
  1153. xeig = pixel.x;
  1154. yeig = pixel.y;
  1155. /* find the parent window handle if we need to process the status
  1156. * window, or the caller has requested we calculate the width ourself */
  1157. if ((toolbar->parent_handle) && (width == -1)) {
  1158. outline.w = toolbar->parent_handle;
  1159. error = xwimp_get_window_outline(&outline);
  1160. if (error) {
  1161. LOG(("xwimp_get_window_outline: 0x%x: %s",
  1162. error->errnum, error->errmess));
  1163. warn_user("WimpError", error->errmess);
  1164. return false;
  1165. }
  1166. if (width == -1)
  1167. width = outline.outline.x1 - outline.outline.x0 - 2;
  1168. }
  1169. /* Find the parent visible height to clip our toolbar height to
  1170. */
  1171. if ((toolbar->toolbar_handle) && (toolbar->parent_handle)) {
  1172. /* Get the current state
  1173. */
  1174. state.w = toolbar->parent_handle;
  1175. error = xwimp_get_window_state(&state);
  1176. if (error) {
  1177. LOG(("xwimp_get_window_state: 0x%x: %s",
  1178. error->errnum, error->errmess));
  1179. warn_user("WimpError", error->errmess);
  1180. return false;
  1181. }
  1182. height = state.visible.y1 - state.visible.y0 + 2;
  1183. /* We can't obscure the height of the scroll bar as we
  1184. lose the resize icon if we do.
  1185. */
  1186. if ((state.flags & wimp_WINDOW_SIZE_ICON) &&
  1187. !(state.flags & wimp_WINDOW_HSCROLL))
  1188. height -= ro_get_hscroll_height(0) - 2;
  1189. /* Update our position
  1190. */
  1191. if (height != toolbar->max_height) {
  1192. if ((state.flags & wimp_WINDOW_SIZE_ICON) &&
  1193. !(state.flags & wimp_WINDOW_HSCROLL) &&
  1194. (toolbar->height > toolbar->max_height))
  1195. xwimp_force_redraw(toolbar->parent_handle,
  1196. 0, -16384, 16384, 16384);
  1197. toolbar->max_height = height;
  1198. collapse_height = toolbar->height +
  1199. (toolbar->editor ? toolbar->editor->height : 0);
  1200. ro_gui_theme_attach_toolbar(toolbar, toolbar->parent_handle);
  1201. if ((state.flags & wimp_WINDOW_SIZE_ICON) &&
  1202. !(state.flags & wimp_WINDOW_HSCROLL) &&
  1203. (collapse_height > toolbar->max_height))
  1204. xwimp_force_redraw(toolbar->parent_handle,
  1205. 0, -16384, 16384, 16384);
  1206. }
  1207. }
  1208. /* Reformat the buttons starting with the throbber
  1209. */
  1210. if ((width != old_width) || (toolbar->reformat_buttons)) {
  1211. left_edge = 6;
  1212. right_edge = width - 8;
  1213. toolbar->height = 0;
  1214. if ((toolbar->descriptor) && (toolbar->descriptor->theme) &&
  1215. (toolbar->type == THEME_BROWSER_TOOLBAR) &&
  1216. (toolbar->display_throbber)) {
  1217. if (!toolbar->descriptor->throbber_right) {
  1218. throbber_x = left_edge;
  1219. left_edge += toolbar->descriptor->theme->throbber_width + 8;
  1220. }
  1221. toolbar->height = toolbar->descriptor->theme->throbber_height + 8;
  1222. }
  1223. if ((toolbar->type == THEME_BROWSER_TOOLBAR) && (toolbar->display_url)) {
  1224. if (toolbar->height < 52 + 8)
  1225. toolbar->height = 52 + 8;
  1226. if ((toolbar->suggest) && (toolbar->height <
  1227. (toolbar->suggest->height + 8)))
  1228. toolbar->height = toolbar->suggest->height + 8;
  1229. }
  1230. /* Get the minimum height of the icons
  1231. */
  1232. bottom_edge = left_edge;
  1233. if ((toolbar->display_buttons || toolbar->editor) && (toolbar->descriptor) &&
  1234. (toolbar->descriptor->theme)) {
  1235. toolbar_icon = toolbar->icon;
  1236. while (toolbar_icon) {
  1237. if (toolbar_icon->display) {
  1238. bottom_edge += toolbar_icon->width;
  1239. visible_icon = true;
  1240. if ((toolbar_icon->height != 0) &&
  1241. (toolbar->height < toolbar_icon->height + 8)) {
  1242. toolbar->height = toolbar_icon->height + 8;
  1243. }
  1244. }
  1245. toolbar_icon = toolbar_icon->next;
  1246. }
  1247. if (visible_icon) bottom_edge += 8;
  1248. }
  1249. /* Check for minimum widths
  1250. */
  1251. if (toolbar->type == THEME_BROWSER_TOOLBAR) {
  1252. if (!toolbar->reformat_buttons) left_edge = bottom_edge;
  1253. if (toolbar->display_url) {
  1254. bottom_edge += 112;
  1255. if (toolbar->suggest)
  1256. bottom_edge += toolbar->suggest->width + 8;
  1257. }
  1258. if (bottom_edge > right_edge)
  1259. right_edge = bottom_edge;
  1260. if ((toolbar->descriptor) && (toolbar->descriptor->theme) &&
  1261. (toolbar->display_throbber) &&
  1262. (toolbar->descriptor->throbber_right)) {
  1263. bottom_edge += toolbar->descriptor->theme->throbber_width;
  1264. if (bottom_edge > right_edge) right_edge = bottom_edge;
  1265. throbber_x = right_edge -
  1266. toolbar->descriptor->theme->throbber_width;
  1267. right_edge -= toolbar->descriptor->theme->throbber_width + 8;
  1268. }
  1269. }
  1270. if (toolbar->height != 0)
  1271. toolbar->height += 2;
  1272. if (toolbar->reformat_buttons) {
  1273. /* Hide the URL bar if we should
  1274. */
  1275. if ((!toolbar->display_url) &&
  1276. (toolbar->type == THEME_BROWSER_TOOLBAR)) {
  1277. if (!xwimp_get_caret_position(&caret)) {
  1278. if ((caret.w == toolbar->toolbar_handle) &&
  1279. (caret.i == ICON_TOOLBAR_URL)) {
  1280. if (toolbar->parent_handle)
  1281. xwimp_set_caret_position(
  1282. toolbar->parent_handle,
  1283. wimp_ICON_WINDOW,
  1284. -100, -100, 32, -1);
  1285. else
  1286. xwimp_set_caret_position((wimp_w)-1,
  1287. 0, 0, 0, 0, 0);
  1288. }
  1289. }
  1290. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_SURROUND,
  1291. 0, -16384, 0, -16384);
  1292. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_FAVICON,
  1293. 0, -16384, 0, -16384);
  1294. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_URL,
  1295. 0, -16384, 0, -16384);
  1296. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_SUGGEST,
  1297. 0, -16384, 0, -16384);
  1298. } else if (toolbar->type == THEME_BROWSER_TOOLBAR) {
  1299. ro_gui_set_icon_shaded_state(toolbar->toolbar_handle,
  1300. ICON_TOOLBAR_URL, !toolbar->display_url);
  1301. }
  1302. xwimp_force_redraw(toolbar->toolbar_handle,
  1303. 0, 0, 16384, 16384);
  1304. /* Move the buttons
  1305. */
  1306. toolbar_icon = toolbar->icon;
  1307. while (toolbar_icon) {
  1308. if ((toolbar->display_buttons || toolbar->editor) &&
  1309. (toolbar_icon->display)
  1310. && (toolbar_icon->width > 0)) {
  1311. visible_icon = true;
  1312. bottom_edge = (toolbar->height -
  1313. toolbar_icon->height) / 2;
  1314. toolbar_icon->x = left_edge;
  1315. toolbar_icon->y = bottom_edge;
  1316. xwimp_resize_icon(toolbar->toolbar_handle,
  1317. toolbar_icon->icon_number,
  1318. left_edge, bottom_edge,
  1319. left_edge + toolbar_icon->width,
  1320. bottom_edge + toolbar_icon->height);
  1321. left_edge += toolbar_icon->width;
  1322. } else {
  1323. xwimp_resize_icon(toolbar->toolbar_handle,
  1324. toolbar_icon->icon_number,
  1325. 0, -16384, 0, -16384);
  1326. }
  1327. toolbar_icon = toolbar_icon->next;
  1328. }
  1329. if (visible_icon) left_edge += 8;
  1330. }
  1331. if (toolbar->type == THEME_BROWSER_TOOLBAR) {
  1332. /* Move the URL bar
  1333. */
  1334. if (toolbar->display_url) {
  1335. top = (toolbar->height / 2) + 26;
  1336. bottom = (toolbar->height / 2) - 26;
  1337. if (toolbar->suggest) {
  1338. right = right_edge - toolbar->suggest->width - 8;
  1339. xwimp_resize_icon(toolbar->toolbar_handle,
  1340. ICON_TOOLBAR_SUGGEST,
  1341. right_edge - toolbar->suggest->width,
  1342. (toolbar->height - toolbar->suggest->height) / 2,
  1343. right_edge,
  1344. (toolbar->height + toolbar->suggest->height) / 2);
  1345. } else {
  1346. right = right_edge;
  1347. }
  1348. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_URL,
  1349. left_edge + 52,
  1350. bottom + yeig,
  1351. right - xeig,
  1352. top - yeig);
  1353. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_FAVICON,
  1354. left_edge + xeig,
  1355. bottom + yeig,
  1356. left_edge + 52,
  1357. top - yeig);
  1358. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_SURROUND,
  1359. left_edge,
  1360. bottom,
  1361. right,
  1362. top);
  1363. xwimp_force_redraw(toolbar->toolbar_handle,
  1364. right - xeig, 0, 16384, 16384);
  1365. xwimp_force_redraw(toolbar->toolbar_handle,
  1366. left_edge,
  1367. bottom,
  1368. right,
  1369. bottom + yeig);
  1370. xwimp_force_redraw(toolbar->toolbar_handle,
  1371. left_edge,
  1372. top - yeig,
  1373. right,
  1374. top);
  1375. if (!xwimp_get_caret_position(&caret)) {
  1376. if ((caret.w == toolbar->toolbar_handle) &&
  1377. (caret.i == ICON_TOOLBAR_URL)) {
  1378. xwimp_set_caret_position(toolbar->toolbar_handle,
  1379. ICON_TOOLBAR_URL,
  1380. caret.pos.x, caret.pos.y,
  1381. -1, caret.index);
  1382. }
  1383. }
  1384. ro_gui_redraw_icon(toolbar->toolbar_handle, ICON_TOOLBAR_URL);
  1385. }
  1386. /* Move the throbber
  1387. */
  1388. if ((toolbar->descriptor) && (toolbar->descriptor->theme) &&
  1389. (throbber_x >= 0) && (toolbar->display_throbber)) {
  1390. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_THROBBER,
  1391. throbber_x, 0,
  1392. throbber_x + toolbar->descriptor->theme->throbber_width,
  1393. toolbar->height);
  1394. if (toolbar->descriptor->throbber_right) {
  1395. xwimp_force_redraw(toolbar->toolbar_handle,
  1396. old_width - width + throbber_x, 0, 16384, 16384);
  1397. xwimp_force_redraw(toolbar->toolbar_handle,
  1398. throbber_x, 0, 16384, 16384);
  1399. }
  1400. } else {
  1401. xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_THROBBER,
  1402. 0, -16384, 0, -16384);
  1403. }
  1404. }
  1405. /* Re-attach to the parent
  1406. */
  1407. toolbar->toolbar_current = width;
  1408. if (toolbar->reformat_buttons) {
  1409. extent.x1 = 16384;
  1410. extent.y0 = (toolbar->editor ? -toolbar->editor->height : 0);
  1411. extent.y1 = toolbar->height - 2;
  1412. xwimp_set_extent(toolbar->toolbar_handle, &extent);
  1413. if ((toolbar->parent_handle) && (old_height != toolbar->height))
  1414. ro_gui_theme_attach_toolbar(toolbar, toolbar->parent_handle);
  1415. }
  1416. toolbar->reformat_buttons = false;
  1417. }
  1418. return true;
  1419. }
  1420. /**
  1421. * Destroys a toolbar and frees any associated memory.
  1422. *
  1423. * \param toolbar the toolbar to destroy
  1424. */
  1425. void ro_gui_theme_destroy_toolbar(struct toolbar *toolbar)
  1426. {
  1427. struct toolbar_icon *icon;
  1428. struct toolbar_icon *next_icon;
  1429. if (!toolbar) return;
  1430. /* Destroy our editor
  1431. */
  1432. if (toolbar->editor) {
  1433. toolbar->editor = NULL;
  1434. ro_gui_theme_destroy_toolbar(toolbar->editor);
  1435. }
  1436. /* Delete our windows
  1437. */
  1438. if (toolbar->toolbar_handle) {
  1439. xwimp_delete_window(toolbar->toolbar_handle);
  1440. ro_gui_wimp_event_finalise(toolbar->toolbar_handle);
  1441. }
  1442. /* Free the Wimp buffer (we only created one for them all)
  1443. */
  1444. free(toolbar->url_buffer);
  1445. /* Free all the icons
  1446. */
  1447. next_icon = toolbar->icon;
  1448. while ((icon = next_icon) != NULL) {
  1449. next_icon = icon->next;
  1450. ro_gui_theme_destroy_toolbar_icon(icon);
  1451. }
  1452. ro_gui_theme_destroy_toolbar_icon(toolbar->suggest);
  1453. free(toolbar);
  1454. }
  1455. /**
  1456. * Toggles the toolbar editing mode
  1457. *
  1458. * \param toolbar the toolbar to toggle editing for
  1459. */
  1460. void ro_gui_theme_toggle_edit(struct toolbar *toolbar)
  1461. {
  1462. int icons = 0;
  1463. struct toolbar_icon *icon;
  1464. struct gui_window *g = NULL;
  1465. wimp_window_state state;
  1466. os_error *error;
  1467. char *option;
  1468. char hex_no[4];
  1469. if (!toolbar)
  1470. return;
  1471. if ((toolbar->type == THEME_BROWSER_TOOLBAR) &&
  1472. (toolbar->parent_handle))
  1473. g = ro_gui_window_lookup(toolbar->parent_handle);
  1474. if (toolbar->editor) {
  1475. /* save options */
  1476. icons = 0;
  1477. for (icon = toolbar->icon; icon; icon = icon->next)
  1478. if (icon->display) icons++;
  1479. option = calloc(icons + 1, 1);
  1480. if (!option) {
  1481. LOG(("No memory to save toolbar options"));
  1482. warn_user("NoMemory", 0);
  1483. } else {
  1484. icons = 0;
  1485. for (icon = toolbar->icon; icon; icon = icon->next)
  1486. if (icon->display) {
  1487. if (icon->icon_number == -1) {
  1488. option[icons] = '|';
  1489. } else {
  1490. sprintf(hex_no, "%x", icon->icon_number);
  1491. option[icons] = hex_no[0];
  1492. }
  1493. icons++;
  1494. }
  1495. switch (toolbar->type) {
  1496. case THEME_BROWSER_TOOLBAR:
  1497. free(option_toolbar_browser);
  1498. option_toolbar_browser = option;
  1499. break;
  1500. case THEME_HOTLIST_TOOLBAR:
  1501. free(option_toolbar_hotlist);
  1502. option_toolbar_hotlist = option;
  1503. break;
  1504. case THEME_HISTORY_TOOLBAR:
  1505. free(option_toolbar_history);
  1506. option_toolbar_history = option;
  1507. break;
  1508. case THEME_COOKIES_TOOLBAR:
  1509. free(option_toolbar_cookies);
  1510. option_toolbar_cookies = option;
  1511. break;
  1512. default:
  1513. break;
  1514. }
  1515. ro_gui_save_options();
  1516. }
  1517. /* turn off editing */
  1518. ro_gui_theme_destroy_toolbar(toolbar->editor);
  1519. toolbar->editor = NULL;
  1520. ro_gui_theme_update_toolbar(toolbar->descriptor, toolbar);
  1521. switch (toolbar->type) {
  1522. case THEME_BROWSER_TOOLBAR:
  1523. if (g)
  1524. gui_window_update_extent(g);
  1525. break;
  1526. default:
  1527. if (toolbar->parent_handle)
  1528. xwimp_force_redraw(toolbar->parent_handle,
  1529. 0, -16384, 16384, 16384);
  1530. break;
  1531. }
  1532. } else {
  1533. /* create/initialise the toolbar editor */
  1534. switch (toolbar->type) {
  1535. case THEME_BROWSER_TOOLBAR:
  1536. toolbar->editor = ro_gui_theme_create_toolbar(
  1537. toolbar->descriptor,
  1538. THEME_BROWSER_EDIT_TOOLBAR);
  1539. break;
  1540. case THEME_HOTLIST_TOOLBAR:
  1541. toolbar->editor = ro_gui_theme_create_toolbar(
  1542. toolbar->descriptor,
  1543. THEME_HOTLIST_EDIT_TOOLBAR);
  1544. break;
  1545. case THEME_HISTORY_TOOLBAR:
  1546. toolbar->editor = ro_gui_theme_create_toolbar(
  1547. toolbar->descriptor,
  1548. THEME_HISTORY_EDIT_TOOLBAR);
  1549. break;
  1550. case THEME_COOKIES_TOOLBAR:
  1551. toolbar->editor = ro_gui_theme_create_toolbar(
  1552. toolbar->descriptor,
  1553. THEME_COOKIES_EDIT_TOOLBAR);
  1554. break;
  1555. default:
  1556. return;
  1557. }
  1558. if (!toolbar->editor) {
  1559. LOG(("Unable to create toolbar editor"));
  1560. return;
  1561. }
  1562. ro_gui_wimp_event_set_user_data(toolbar->editor->toolbar_handle,
  1563. ro_gui_wimp_event_get_user_data(toolbar->toolbar_handle));
  1564. ro_gui_theme_update_toolbar(toolbar->descriptor, toolbar);
  1565. switch (toolbar->type) {
  1566. case THEME_BROWSER_TOOLBAR:
  1567. if (g)
  1568. gui_window_update_extent(g);
  1569. break;
  1570. default:
  1571. if (toolbar->parent_handle) {
  1572. state.w = toolbar->parent_handle;
  1573. error = xwimp_get_window_state(&state);
  1574. if (error) {
  1575. LOG(("xwimp_get_window_state: 0x%x: %s",
  1576. error->errnum, error->errmess));
  1577. warn_user("WimpError", error->errmess);
  1578. return;
  1579. }
  1580. ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
  1581. xwimp_force_redraw(toolbar->parent_handle,
  1582. 0, -16384, 16384, 16384);
  1583. }
  1584. break;
  1585. }
  1586. ro_gui_theme_process_toolbar(toolbar, -1);
  1587. ro_gui_theme_toolbar_editor_sync(toolbar);
  1588. }
  1589. ro_gui_theme_set_help

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