Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
  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.  
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <fcntl.h>
  22. #include <sys/ioctl.h>
  23. #include <limits.h>
  24. #include <unistd.h>
  25. #include <assert.h>
  26. #include <string.h>
  27. #include <stdbool.h>
  28. #include <stdlib.h>
  29.  
  30. #include <libnsfb.h>
  31. #include <libnsfb_plot.h>
  32. #include <libnsfb_event.h>
  33.  
  34. #include "desktop/browser_private.h"
  35. #include "desktop/gui.h"
  36. #include "desktop/mouse.h"
  37. #include "desktop/plotters.h"
  38. #include "desktop/netsurf.h"
  39. #include "desktop/options.h"
  40. #include "utils/filepath.h"
  41. #include "utils/log.h"
  42. #include "utils/messages.h"
  43. #include "utils/schedule.h"
  44. #include "utils/types.h"
  45. #include "utils/url.h"
  46. #include "utils/utils.h"
  47. #include "desktop/textinput.h"
  48. #include "render/form.h"
  49.  
  50. #include "framebuffer/gui.h"
  51. #include "framebuffer/fbtk.h"
  52. #include "framebuffer/framebuffer.h"
  53. #include "framebuffer/schedule.h"
  54. #include "framebuffer/findfile.h"
  55. #include "framebuffer/image_data.h"
  56. #include "framebuffer/font.h"
  57.  
  58.  
  59.  
  60.  
  61. #include "content/urldb.h"
  62. #include "desktop/history_core.h"
  63. #include "content/fetch.h"
  64.  
  65. #define NSFB_TOOLBAR_DEFAULT_LAYOUT "blfsrut"
  66.  
  67. fbtk_widget_t *fbtk;
  68.  
  69. struct gui_window *input_window = NULL;
  70. struct gui_window *search_current_window;
  71. struct gui_window *window_list = NULL;
  72.  
  73. /* private data for browser user widget */
  74. struct browser_widget_s {
  75.         struct browser_window *bw; /**< The browser window connected to this gui window */
  76.         int scrollx, scrolly; /**< scroll offsets. */
  77.  
  78.         /* Pending window redraw state. */
  79.         bool redraw_required; /**< flag indicating the foreground loop
  80.                                * needs to redraw the browser widget.
  81.                                */
  82.         bbox_t redraw_box; /**< Area requiring redraw. */
  83.         bool pan_required; /**< flag indicating the foreground loop
  84.                             * needs to pan the window.
  85.                             */
  86.         int panx, pany; /**< Panning required. */
  87. };
  88.  
  89. static struct gui_drag {
  90.         enum state {
  91.                 GUI_DRAG_NONE,
  92.                 GUI_DRAG_PRESSED,
  93.                 GUI_DRAG_DRAG
  94.         } state;
  95.         int button;
  96.         int x;
  97.         int y;
  98.         bool grabbed_pointer;
  99. } gui_drag;
  100.  
  101.  
  102. /* queue a redraw operation, co-ordinates are relative to the window */
  103. static void
  104. fb_queue_redraw(struct fbtk_widget_s *widget, int x0, int y0, int x1, int y1)
  105. {
  106.         struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
  107.  
  108.         bwidget->redraw_box.x0 = min(bwidget->redraw_box.x0, x0);
  109.         bwidget->redraw_box.y0 = min(bwidget->redraw_box.y0, y0);
  110.         bwidget->redraw_box.x1 = max(bwidget->redraw_box.x1, x1);
  111.         bwidget->redraw_box.y1 = max(bwidget->redraw_box.y1, y1);
  112.  
  113.         if (fbtk_clip_to_widget(widget, &bwidget->redraw_box)) {
  114.                 bwidget->redraw_required = true;
  115.                 fbtk_request_redraw(widget);
  116.         } else {
  117.                 bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX;
  118.                 bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = -(INT_MAX);
  119.                 bwidget->redraw_required = false;
  120.         }
  121. }
  122.  
  123. /* queue a window scroll */
  124. static void
  125. widget_scroll_y(struct gui_window *gw, int y, bool abs)
  126. {
  127.         struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
  128.         int content_height;
  129.         int height;
  130.         float scale = gw->bw->scale;
  131.  
  132.         LOG(("window scroll"));
  133.         if (abs) {
  134.                 bwidget->pany = y - bwidget->scrolly;
  135.         } else {
  136.                 bwidget->pany += y;
  137.         }
  138.  
  139.         content_height = content_get_height(gw->bw->current_content) * scale;
  140.  
  141.         height = fbtk_get_height(gw->browser);
  142.  
  143.         /* dont pan off the top */
  144.         if ((bwidget->scrolly + bwidget->pany) < 0)
  145.                 bwidget->pany = -bwidget->scrolly;
  146.  
  147.         /* do not pan off the bottom of the content */
  148.         if ((bwidget->scrolly + bwidget->pany) > (content_height - height))
  149.                 bwidget->pany = (content_height - height) - bwidget->scrolly;
  150.  
  151.         if (bwidget->pany == 0)
  152.                 return;
  153.  
  154.         bwidget->pan_required = true;
  155.  
  156.         fbtk_request_redraw(gw->browser);
  157.  
  158.         fbtk_set_scroll_position(gw->vscroll, bwidget->scrolly + bwidget->pany);
  159. }
  160.  
  161. /* queue a window scroll */
  162. static void
  163. widget_scroll_x(struct gui_window *gw, int x, bool abs)
  164. {
  165.         struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
  166.         int content_width;
  167.         int width;
  168.         float scale = gw->bw->scale;
  169.  
  170.         if (abs) {
  171.                 bwidget->panx = x - bwidget->scrollx;
  172.         } else {
  173.                 bwidget->panx += x;
  174.         }
  175.  
  176.         content_width = content_get_width(gw->bw->current_content) * scale;
  177.  
  178.         width = fbtk_get_width(gw->browser);
  179.  
  180.         /* dont pan off the left */
  181.         if ((bwidget->scrollx + bwidget->panx) < 0)
  182.                 bwidget->panx = - bwidget->scrollx;
  183.  
  184.         /* do not pan off the right of the content */
  185.         if ((bwidget->scrollx + bwidget->panx) > (content_width - width))
  186.                 bwidget->panx = (content_width - width) - bwidget->scrollx;
  187.  
  188.         if (bwidget->panx == 0)
  189.                 return;
  190.  
  191.         bwidget->pan_required = true;
  192.  
  193.         fbtk_request_redraw(gw->browser);
  194.  
  195.         fbtk_set_scroll_position(gw->hscroll, bwidget->scrollx + bwidget->panx);
  196. }
  197.  
  198. static void
  199. fb_pan(fbtk_widget_t *widget,
  200.        struct browser_widget_s *bwidget,
  201.        struct browser_window *bw)
  202. {
  203.         int x;
  204.         int y;
  205.         int width;
  206.         int height;
  207.         nsfb_bbox_t srcbox;
  208.         nsfb_bbox_t dstbox;
  209.  
  210.         nsfb_t *nsfb = fbtk_get_nsfb(widget);
  211.  
  212.         height = fbtk_get_height(widget);
  213.         width = fbtk_get_width(widget);
  214.  
  215.         LOG(("panning %d, %d", bwidget->panx, bwidget->pany));
  216.  
  217.         x = fbtk_get_absx(widget);
  218.         y = fbtk_get_absy(widget);
  219.  
  220.         /* if the pan exceeds the viewport size just redraw the whole area */
  221.         if (bwidget->pany >= height || bwidget->pany <= -height ||
  222.             bwidget->panx >= width || bwidget->panx <= -width) {
  223.  
  224.                 bwidget->scrolly += bwidget->pany;
  225.                 bwidget->scrollx += bwidget->panx;
  226.                 fb_queue_redraw(widget, 0, 0, width, height);
  227.  
  228.                 /* ensure we don't try to scroll again */
  229.                 bwidget->panx = 0;
  230.                 bwidget->pany = 0;
  231.                 bwidget->pan_required = false;
  232.                 return;
  233.         }
  234.  
  235.         if (bwidget->pany < 0) {
  236.                 /* pan up by less then viewport height */
  237.                 srcbox.x0 = x;
  238.                 srcbox.y0 = y;
  239.                 srcbox.x1 = srcbox.x0 + width;
  240.                 srcbox.y1 = srcbox.y0 + height + bwidget->pany;
  241.  
  242.                 dstbox.x0 = x;
  243.                 dstbox.y0 = y - bwidget->pany;
  244.                 dstbox.x1 = dstbox.x0 + width;
  245.                 dstbox.y1 = dstbox.y0 + height + bwidget->pany;
  246.  
  247.                 /* move part that remains visible up */
  248.                 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
  249.  
  250.                 /* redraw newly exposed area */
  251.                 bwidget->scrolly += bwidget->pany;
  252.                 fb_queue_redraw(widget, 0, 0, width, - bwidget->pany);
  253.  
  254.         } else if (bwidget->pany > 0) {
  255.                 /* pan down by less then viewport height */
  256.                 srcbox.x0 = x;
  257.                 srcbox.y0 = y + bwidget->pany;
  258.                 srcbox.x1 = srcbox.x0 + width;
  259.                 srcbox.y1 = srcbox.y0 + height - bwidget->pany;
  260.  
  261.                 dstbox.x0 = x;
  262.                 dstbox.y0 = y;
  263.                 dstbox.x1 = dstbox.x0 + width;
  264.                 dstbox.y1 = dstbox.y0 + height - bwidget->pany;
  265.  
  266.                 /* move part that remains visible down */
  267.                 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
  268.  
  269.                 /* redraw newly exposed area */
  270.                 bwidget->scrolly += bwidget->pany;
  271.                 fb_queue_redraw(widget, 0, height - bwidget->pany,
  272.                                 width, height);
  273.         }
  274.  
  275.         if (bwidget->panx < 0) {
  276.                 /* pan left by less then viewport width */
  277.                 srcbox.x0 = x;
  278.                 srcbox.y0 = y;
  279.                 srcbox.x1 = srcbox.x0 + width + bwidget->panx;
  280.                 srcbox.y1 = srcbox.y0 + height;
  281.  
  282.                 dstbox.x0 = x - bwidget->panx;
  283.                 dstbox.y0 = y;
  284.                 dstbox.x1 = dstbox.x0 + width + bwidget->panx;
  285.                 dstbox.y1 = dstbox.y0 + height;
  286.  
  287.                 /* move part that remains visible left */
  288.                 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
  289.  
  290.                 /* redraw newly exposed area */
  291.                 bwidget->scrollx += bwidget->panx;
  292.                 fb_queue_redraw(widget, 0, 0, -bwidget->panx, height);
  293.  
  294.         } else if (bwidget->panx > 0) {
  295.                 /* pan right by less then viewport width */
  296.                 srcbox.x0 = x + bwidget->panx;
  297.                 srcbox.y0 = y;
  298.                 srcbox.x1 = srcbox.x0 + width - bwidget->panx;
  299.                 srcbox.y1 = srcbox.y0 + height;
  300.  
  301.                 dstbox.x0 = x;
  302.                 dstbox.y0 = y;
  303.                 dstbox.x1 = dstbox.x0 + width - bwidget->panx;
  304.                 dstbox.y1 = dstbox.y0 + height;
  305.  
  306.                 /* move part that remains visible right */
  307.                 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
  308.  
  309.                 /* redraw newly exposed area */
  310.                 bwidget->scrollx += bwidget->panx;
  311.                 fb_queue_redraw(widget, width - bwidget->panx, 0,
  312.                                 width, height);
  313.         }
  314.  
  315.         bwidget->pan_required = false;
  316.         bwidget->panx = 0;
  317.         bwidget->pany = 0;
  318. }
  319.  
  320. static void
  321. fb_redraw(fbtk_widget_t *widget,
  322.           struct browser_widget_s *bwidget,
  323.           struct browser_window *bw)
  324. {
  325.         int x;
  326.         int y;
  327.         int caret_x, caret_y, caret_h;
  328.         struct rect clip;
  329.         struct redraw_context ctx = {
  330.                 .interactive = true,
  331.                 .background_images = true,
  332.                 .plot = &fb_plotters
  333.         };
  334.         nsfb_t *nsfb = fbtk_get_nsfb(widget);
  335.  
  336.         LOG(("%d,%d to %d,%d",
  337.              bwidget->redraw_box.x0,
  338.              bwidget->redraw_box.y0,
  339.              bwidget->redraw_box.x1,
  340.              bwidget->redraw_box.y1));
  341.  
  342.         x = fbtk_get_absx(widget);
  343.         y = fbtk_get_absy(widget);
  344.  
  345.         /* adjust clipping co-ordinates according to window location */
  346.         bwidget->redraw_box.y0 += y;
  347.         bwidget->redraw_box.y1 += y;
  348.         bwidget->redraw_box.x0 += x;
  349.         bwidget->redraw_box.x1 += x;
  350.  
  351.         nsfb_claim(nsfb, &bwidget->redraw_box);
  352.  
  353.         /* redraw bounding box is relative to window */
  354.         clip.x0 = bwidget->redraw_box.x0;
  355.         clip.y0 = bwidget->redraw_box.y0;
  356.         clip.x1 = bwidget->redraw_box.x1;
  357.         clip.y1 = bwidget->redraw_box.y1;
  358.  
  359.         browser_window_redraw(bw,
  360.                         (x - bwidget->scrollx) / bw->scale,
  361.                         (y - bwidget->scrolly) / bw->scale,
  362.                         &clip, &ctx);
  363.  
  364.         if (fbtk_get_caret(widget, &caret_x, &caret_y, &caret_h)) {
  365.                 /* This widget has caret, so render it */
  366.                 nsfb_bbox_t line;
  367.                 nsfb_plot_pen_t pen;
  368.  
  369.                 line.x0 = x - bwidget->scrollx + caret_x;
  370.                 line.y0 = y - bwidget->scrolly + caret_y;
  371.                 line.x1 = x - bwidget->scrollx + caret_x;
  372.                 line.y1 = y - bwidget->scrolly + caret_y + caret_h;
  373.  
  374.                 pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
  375.                 pen.stroke_width = 1;
  376.                 pen.stroke_colour = 0xFF0000FF;
  377.  
  378.                 nsfb_plot_line(nsfb, &line, &pen);
  379.         }
  380.         ///STUB???
  381.         nsfb_update(fbtk_get_nsfb(widget), &bwidget->redraw_box);
  382.  
  383.         bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX;
  384.         bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = INT_MIN;
  385.         bwidget->redraw_required = false;
  386. }
  387.  
  388. static int
  389. fb_browser_window_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  390. {
  391.         struct gui_window *gw = cbi->context;
  392.         struct browser_widget_s *bwidget;
  393.  
  394.         bwidget = fbtk_get_userpw(widget);
  395.         if (bwidget == NULL) {
  396.                 LOG(("browser widget from widget %p was null", widget));
  397.                 return -1;
  398.         }
  399.  
  400.         if (bwidget->pan_required) {
  401.                 fb_pan(widget, bwidget, gw->bw);
  402.         }
  403.  
  404.         if (bwidget->redraw_required) {
  405.                 fb_redraw(widget, bwidget, gw->bw);
  406.         } else {
  407.                 bwidget->redraw_box.x0 = 0;
  408.                 bwidget->redraw_box.y0 = 0;
  409.                 bwidget->redraw_box.x1 = fbtk_get_width(widget);
  410.                 bwidget->redraw_box.y1 = fbtk_get_height(widget);
  411.                 fb_redraw(widget, bwidget, gw->bw);
  412.         }
  413.         return 0;
  414. }
  415.  
  416.  
  417. static const char *fename;
  418. static int febpp;
  419. static int fewidth;
  420. static int feheight;
  421. static const char *feurl;
  422.  
  423. static bool
  424. process_cmdline(int argc, char** argv)
  425. {
  426.         int opt;
  427.  
  428.         LOG(("argc %d, argv %p", argc, argv));
  429.  
  430.         fename = "sdl";
  431.         febpp = 16;
  432.  
  433.         if ((nsoption_int(window_width) != 0) &&
  434.             (nsoption_int(window_height) != 0)) {
  435.                 fewidth = nsoption_int(window_width);
  436.                 feheight = nsoption_int(window_height);
  437.         } else {
  438.                 fewidth = 800; //640;
  439.                 feheight = 560; //400;
  440.         }
  441.  
  442.         if ((nsoption_charp(homepage_url) != NULL) &&
  443.             (nsoption_charp(homepage_url)[0] != '\0')) {
  444.                 feurl = nsoption_charp(homepage_url);
  445.         } else {
  446.                 feurl = "about:about";
  447.         }
  448.  
  449.         while((opt = getopt(argc, argv, "f:b:w:h:")) != -1) {
  450.                 switch (opt) {
  451.                 case 'f':
  452.                         fename = optarg;
  453.                         break;
  454.  
  455.                 case 'b':
  456.                         febpp = atoi(optarg);
  457.                         break;
  458.  
  459.                 case 'w':
  460.                         fewidth = atoi(optarg);
  461.                         break;
  462.  
  463.                 case 'h':
  464.                         feheight = atoi(optarg);
  465.                         break;
  466.  
  467.                 default:
  468.                         fprintf(stderr,
  469.                                 "Usage: %s [-f frontend] [-b bpp] url\n",
  470.                                 argv[0]);
  471.                         return false;
  472.                 }
  473.         }
  474.  
  475.         if (optind < argc) {
  476.                 feurl = argv[optind];
  477.         }
  478.  
  479.         return true;
  480. }
  481.  
  482. /* Documented in desktop/options.h */
  483. void gui_options_init_defaults(void)
  484. {
  485.         /* Set defaults for absent option strings */
  486.         nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies"));
  487.         nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies"));
  488.  
  489.         if (nsoption_charp(cookie_file) == NULL ||
  490.                         nsoption_charp(cookie_jar == NULL)) {
  491.                 die("Failed initialising cookie options");
  492.         }
  493. }
  494.  
  495. static void
  496. gui_init(int argc, char** argv)
  497. {
  498.         nsfb_t *nsfb;
  499.  
  500.         /* Override, since we have no support for non-core SELECT menu */
  501.         nsoption_set_bool(core_select_menu, true);
  502.  
  503.         if (process_cmdline(argc,argv) != true)
  504.                 die("unable to process command line.\n");
  505.  
  506.         nsfb = framebuffer_initialise(fename, fewidth, feheight, febpp);
  507.         if (nsfb == NULL)
  508.                 die("Unable to initialise framebuffer");
  509.  
  510.         framebuffer_set_cursor(&pointer_image);
  511.  
  512.         if (fb_font_init() == false)
  513.                 die("Unable to initialise the font system");
  514.  
  515.         fbtk = fbtk_init(nsfb);
  516.  
  517.         fbtk_enable_oskb(fbtk);
  518.  
  519.         urldb_load_cookies(nsoption_charp(cookie_file));
  520. }
  521.  
  522. /** Entry point from OS.
  523.  *
  524.  * /param argc The number of arguments in the string vector.
  525.  * /param argv The argument string vector.
  526.  * /return The return code to the OS
  527.  */
  528.  
  529. #include <surface.h>
  530.  
  531. int
  532. main(int argc, char** argv)
  533. {
  534.         struct browser_window *bw;
  535.         char *options;
  536.         char *messages;
  537.  
  538.         setbuf(stderr, NULL);
  539.  
  540.         freopen( "stderr.log", "w", stderr );
  541.         freopen( "stdout.log", "w", stdout );
  542.        
  543.        
  544.         LOG(("Registering surfaces for SDL and RAM.."));
  545.        
  546.         extern nsfb_surface_rtns_t sdl_rtns;
  547.         extern nsfb_surface_rtns_t ram_rtns;
  548.         extern nsfb_surface_rtns_t able_rtns;
  549.        
  550.         _nsfb_register_surface(NSFB_SURFACE_SDL, &sdl_rtns, "sdl");
  551.         _nsfb_register_surface(NSFB_SURFACE_RAM, &ram_rtns, "ram");
  552.         _nsfb_register_surface(NSFB_SURFACE_RAM, &able_rtns, "able");
  553.  
  554.         respaths = fb_init_resource("/tmp9/1/netsurf/res/:res/:fonts/");
  555.  
  556.         options = filepath_find(respaths, "Choices");
  557.         messages = filepath_find(respaths, "messages");
  558.  
  559.         netsurf_init(&argc, &argv, options, "res/messages");
  560.        
  561.         LOG(("NS init okay"));
  562.        
  563.         free(messages);
  564.         free(options);
  565.  
  566.         LOG(("freed opts and msgs, start gui init"));
  567.        
  568.  
  569.         gui_init(argc, argv);
  570.  
  571.         LOG(("calling browser_window_create in MAIN()"));
  572.         bw = browser_window_create(feurl, 0, 0, true, false);
  573.  
  574.  
  575.         LOG(("NS main loop..."));
  576.        
  577.         netsurf_main_loop();
  578.  
  579.         browser_window_destroy(bw);
  580.  
  581.         netsurf_exit();
  582.  
  583.         return 0;
  584. }
  585.  
  586.  
  587. void
  588. gui_poll(bool active)
  589. {
  590.         LOG(("GUI poll in"));
  591.  
  592.         nsfb_event_t event;
  593.         int timeout; /* timeout in miliseconds */
  594.  
  595. LOG(("schedule run"));
  596.         /* run the scheduler and discover how long to wait for the next event */
  597.         timeout = schedule_run();
  598.  
  599.         /* if active do not wait for event, return immediately */
  600.         if (active)
  601.                 timeout = 0;
  602.  
  603. LOG(("redraw pending"));
  604.         /* if redraws are pending do not wait for event, return immediately */
  605.         if (fbtk_get_redraw_pending(fbtk))
  606.                 timeout = 0;
  607.  
  608. LOG(("fbtk event"));
  609.         if (fbtk_event(fbtk, &event, timeout)) {
  610.                 if ((event.type == NSFB_EVENT_CONTROL) &&
  611.                     (event.value.controlcode ==  NSFB_CONTROL_QUIT))
  612.                         netsurf_quit = true;
  613.         }
  614.  
  615. LOG(("fbtk redraw"));
  616.         fbtk_redraw(fbtk);
  617.  
  618. LOG(("GUI poll out success"));
  619. }
  620.  
  621. void
  622. gui_quit(void)
  623. {
  624.         LOG(("gui_quit"));
  625.  
  626.         urldb_save_cookies(nsoption_charp(cookie_jar));
  627.  
  628.         framebuffer_finalise();
  629. }
  630.  
  631. /* called back when click in browser window */
  632. static int
  633. fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  634. {
  635.         struct gui_window *gw = cbi->context;
  636.         struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
  637.         float scale = gw->bw->scale;
  638.         int x = (cbi->x + bwidget->scrollx) / scale;
  639.         int y = (cbi->y + bwidget->scrolly) / scale;
  640.  
  641.         if (cbi->event->type != NSFB_EVENT_KEY_DOWN &&
  642.             cbi->event->type != NSFB_EVENT_KEY_UP)
  643.                 return 0;
  644.  
  645.         LOG(("browser window clicked at %d,%d", cbi->x, cbi->y));
  646.  
  647.         switch (cbi->event->type) {
  648.         case NSFB_EVENT_KEY_DOWN:
  649.                 switch (cbi->event->value.keycode) {
  650.                 case NSFB_KEY_MOUSE_1:
  651.                         browser_window_mouse_click(gw->bw,
  652.                                         BROWSER_MOUSE_PRESS_1, x, y);
  653.                         gui_drag.state = GUI_DRAG_PRESSED;
  654.                         gui_drag.button = 1;
  655.                         gui_drag.x = x;
  656.                         gui_drag.y = y;
  657.                         break;
  658.  
  659.                 case NSFB_KEY_MOUSE_3:
  660.                         browser_window_mouse_click(gw->bw,
  661.                                         BROWSER_MOUSE_PRESS_2, x, y);
  662.                         gui_drag.state = GUI_DRAG_PRESSED;
  663.                         gui_drag.button = 2;
  664.                         gui_drag.x = x;
  665.                         gui_drag.y = y;
  666.                         break;
  667.  
  668.                 case NSFB_KEY_MOUSE_4:
  669.                         /* scroll up */
  670.                         if (browser_window_scroll_at_point(gw->bw, x, y,
  671.                                         0, -100) == false)
  672.                                 widget_scroll_y(gw, -100, false);
  673.                         break;
  674.  
  675.                 case NSFB_KEY_MOUSE_5:
  676.                         /* scroll down */
  677.                         if (browser_window_scroll_at_point(gw->bw, x, y,
  678.                                         0, 100) == false)
  679.                                 widget_scroll_y(gw, 100, false);
  680.                         break;
  681.  
  682.                 default:
  683.                         break;
  684.  
  685.                 }
  686.  
  687.                 break;
  688.         case NSFB_EVENT_KEY_UP:
  689.                 switch (cbi->event->value.keycode) {
  690.                 case NSFB_KEY_MOUSE_1:
  691.                         if (gui_drag.state == GUI_DRAG_DRAG) {
  692.                                 /* End of a drag, rather than click */
  693.  
  694.                                 if (gui_drag.grabbed_pointer) {
  695.                                         /* need to ungrab pointer */
  696.                                         fbtk_tgrab_pointer(widget);
  697.                                         gui_drag.grabbed_pointer = false;
  698.                                 }
  699.  
  700.                                 gui_drag.state = GUI_DRAG_NONE;
  701.  
  702.                                 /* Tell core */
  703.                                 browser_window_mouse_track(gw->bw, 0, x, y);
  704.                                 break;
  705.                         }
  706.                         /* This is a click;
  707.                          * clear PRESSED state and pass to core */
  708.                         gui_drag.state = GUI_DRAG_NONE;
  709.                         browser_window_mouse_click(gw->bw,
  710.                                         BROWSER_MOUSE_CLICK_1, x, y);
  711.                         break;
  712.  
  713.                 case NSFB_KEY_MOUSE_3:
  714.                         if (gui_drag.state == GUI_DRAG_DRAG) {
  715.                                 /* End of a drag, rather than click */
  716.                                 gui_drag.state = GUI_DRAG_NONE;
  717.  
  718.                                 if (gui_drag.grabbed_pointer) {
  719.                                         /* need to ungrab pointer */
  720.                                         fbtk_tgrab_pointer(widget);
  721.                                         gui_drag.grabbed_pointer = false;
  722.                                 }
  723.  
  724.                                 /* Tell core */
  725.                                 browser_window_mouse_track(gw->bw, 0, x, y);
  726.                                 break;
  727.                         }
  728.                         /* This is a click;
  729.                          * clear PRESSED state and pass to core */
  730.                         gui_drag.state = GUI_DRAG_NONE;
  731.                         browser_window_mouse_click(gw->bw,
  732.                                         BROWSER_MOUSE_CLICK_2, x, y);
  733.                         break;
  734.  
  735.                 default:
  736.                         break;
  737.  
  738.                 }
  739.  
  740.                 break;
  741.         default:
  742.                 break;
  743.  
  744.         }
  745.         return 1;
  746. }
  747.  
  748. /* called back when movement in browser window */
  749. static int
  750. fb_browser_window_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  751. {
  752.         browser_mouse_state mouse = 0;
  753.         struct gui_window *gw = cbi->context;
  754.         struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
  755.         int x = (cbi->x + bwidget->scrollx) / gw->bw->scale;
  756.         int y = (cbi->y + bwidget->scrolly) / gw->bw->scale;
  757.  
  758.         if (gui_drag.state == GUI_DRAG_PRESSED &&
  759.                         (abs(x - gui_drag.x) > 5 ||
  760.                          abs(y - gui_drag.y) > 5)) {
  761.                 /* Drag started */
  762.                 if (gui_drag.button == 1) {
  763.                         browser_window_mouse_click(gw->bw,
  764.                                         BROWSER_MOUSE_DRAG_1,
  765.                                         gui_drag.x, gui_drag.y);
  766.                 } else {
  767.                         browser_window_mouse_click(gw->bw,
  768.                                         BROWSER_MOUSE_DRAG_2,
  769.                                         gui_drag.x, gui_drag.y);
  770.                 }
  771.                 gui_drag.grabbed_pointer = fbtk_tgrab_pointer(widget);
  772.                 gui_drag.state = GUI_DRAG_DRAG;
  773.         }
  774.  
  775.         if (gui_drag.state == GUI_DRAG_DRAG) {
  776.                 /* set up mouse state */
  777.                 mouse |= BROWSER_MOUSE_DRAG_ON;
  778.  
  779.                 if (gui_drag.button == 1)
  780.                         mouse |= BROWSER_MOUSE_HOLDING_1;
  781.                 else
  782.                         mouse |= BROWSER_MOUSE_HOLDING_2;
  783.         }
  784.  
  785.         browser_window_mouse_track(gw->bw, mouse, x, y);
  786.  
  787.         return 0;
  788. }
  789.  
  790.  
  791. static int
  792. fb_browser_window_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  793. {
  794.         struct gui_window *gw = cbi->context;
  795.         static fbtk_modifier_type modifier = FBTK_MOD_CLEAR;
  796.         int ucs4 = -1;
  797.  
  798.         LOG(("got value %d", cbi->event->value.keycode));
  799.  
  800.         switch (cbi->event->type) {
  801.         case NSFB_EVENT_KEY_DOWN:
  802.                 switch (cbi->event->value.keycode) {
  803.  
  804.                 case NSFB_KEY_PAGEUP:
  805.                         if (browser_window_key_press(gw->bw,
  806.                                         KEY_PAGE_UP) == false)
  807.                                 widget_scroll_y(gw, -fbtk_get_height(
  808.                                                 gw->browser), false);
  809.                         break;
  810.  
  811.                 case NSFB_KEY_PAGEDOWN:
  812.                         if (browser_window_key_press(gw->bw,
  813.                                         KEY_PAGE_DOWN) == false)
  814.                                 widget_scroll_y(gw, fbtk_get_height(
  815.                                                 gw->browser), false);
  816.                         break;
  817.  
  818.                 case NSFB_KEY_RIGHT:
  819.                         if (modifier & FBTK_MOD_RCTRL ||
  820.                                         modifier & FBTK_MOD_LCTRL) {
  821.                                 /* CTRL held */
  822.                                 if (browser_window_key_press(gw->bw,
  823.                                                 KEY_LINE_END) == false)
  824.                                         widget_scroll_x(gw, INT_MAX, true);
  825.  
  826.                         } else if (modifier & FBTK_MOD_RSHIFT ||
  827.                                         modifier & FBTK_MOD_LSHIFT) {
  828.                                 /* SHIFT held */
  829.                                 if (browser_window_key_press(gw->bw,
  830.                                                 KEY_WORD_RIGHT) == false)
  831.                                         widget_scroll_x(gw, fbtk_get_width(
  832.                                                 gw->browser), false);
  833.  
  834.                         } else {
  835.                                 /* no modifier */
  836.                                 if (browser_window_key_press(gw->bw,
  837.                                                 KEY_RIGHT) == false)
  838.                                         widget_scroll_x(gw, 100, false);
  839.                         }
  840.                         break;
  841.  
  842.                 case NSFB_KEY_LEFT:
  843.                         if (modifier & FBTK_MOD_RCTRL ||
  844.                                         modifier & FBTK_MOD_LCTRL) {
  845.                                 /* CTRL held */
  846.                                 if (browser_window_key_press(gw->bw,
  847.                                                 KEY_LINE_START) == false)
  848.                                         widget_scroll_x(gw, 0, true);
  849.  
  850.                         } else if (modifier & FBTK_MOD_RSHIFT ||
  851.                                         modifier & FBTK_MOD_LSHIFT) {
  852.                                 /* SHIFT held */
  853.                                 if (browser_window_key_press(gw->bw,
  854.                                                 KEY_WORD_LEFT) == false)
  855.                                         widget_scroll_x(gw, -fbtk_get_width(
  856.                                                 gw->browser), false);
  857.  
  858.                         } else {
  859.                                 /* no modifier */
  860.                                 if (browser_window_key_press(gw->bw,
  861.                                                 KEY_LEFT) == false)
  862.                                         widget_scroll_x(gw, -100, false);
  863.                         }
  864.                         break;
  865.  
  866.                 case NSFB_KEY_UP:
  867.                         if (browser_window_key_press(gw->bw,
  868.                                         KEY_UP) == false)
  869.                                 widget_scroll_y(gw, -100, false);
  870.                         break;
  871.  
  872.                 case NSFB_KEY_DOWN:
  873.                         if (browser_window_key_press(gw->bw,
  874.                                         KEY_DOWN) == false)
  875.                                 widget_scroll_y(gw, 100, false);
  876.                         break;
  877.  
  878.                 case NSFB_KEY_RSHIFT:
  879.                         modifier |= FBTK_MOD_RSHIFT;
  880.                         break;
  881.  
  882.                 case NSFB_KEY_LSHIFT:
  883.                         modifier |= FBTK_MOD_LSHIFT;
  884.                         break;
  885.  
  886.                 case NSFB_KEY_RCTRL:
  887.                         modifier |= FBTK_MOD_RCTRL;
  888.                         break;
  889.  
  890.                 case NSFB_KEY_LCTRL:
  891.                         modifier |= FBTK_MOD_LCTRL;
  892.                         break;
  893.  
  894.                 default:
  895.                         ucs4 = fbtk_keycode_to_ucs4(cbi->event->value.keycode,
  896.                                                     modifier);
  897.                         if (ucs4 != -1)
  898.                                 browser_window_key_press(gw->bw, ucs4);
  899.                         break;
  900.                 }
  901.                 break;
  902.  
  903.         case NSFB_EVENT_KEY_UP:
  904.                 switch (cbi->event->value.keycode) {
  905.                 case NSFB_KEY_RSHIFT:
  906.                         modifier &= ~FBTK_MOD_RSHIFT;
  907.                         break;
  908.  
  909.                 case NSFB_KEY_LSHIFT:
  910.                         modifier &= ~FBTK_MOD_LSHIFT;
  911.                         break;
  912.  
  913.                 case NSFB_KEY_RCTRL:
  914.                         modifier &= ~FBTK_MOD_RCTRL;
  915.                         break;
  916.  
  917.                 case NSFB_KEY_LCTRL:
  918.                         modifier &= ~FBTK_MOD_LCTRL;
  919.                         break;
  920.  
  921.                 default:
  922.                         break;
  923.                 }
  924.                 break;
  925.  
  926.         default:
  927.                 break;
  928.         }
  929.  
  930.         return 0;
  931. }
  932.  
  933. static void
  934. fb_update_back_forward(struct gui_window *gw)
  935. {
  936.         struct browser_window *bw = gw->bw;
  937.  
  938.         fbtk_set_bitmap(gw->back,
  939.                         (browser_window_back_available(bw)) ?
  940.                         &left_arrow : &left_arrow_g);
  941.         fbtk_set_bitmap(gw->forward,
  942.                         (browser_window_forward_available(bw)) ?
  943.                         &right_arrow : &right_arrow_g);
  944. }
  945.  
  946. /* left icon click routine */
  947. static int
  948. fb_leftarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  949. {
  950.         struct gui_window *gw = cbi->context;
  951.         struct browser_window *bw = gw->bw;
  952.  
  953.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  954.                 return 0;
  955.  
  956.         if (history_back_available(bw->history))
  957.                 history_back(bw, bw->history);
  958.  
  959.         fb_update_back_forward(gw);
  960.  
  961.         return 1;
  962. }
  963.  
  964. /* right arrow icon click routine */
  965. static int
  966. fb_rightarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  967. {
  968.         struct gui_window *gw = cbi->context;
  969.         struct browser_window *bw = gw->bw;
  970.  
  971.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  972.                 return 0;
  973.  
  974.         if (history_forward_available(bw->history))
  975.                 history_forward(bw, bw->history);
  976.  
  977.         fb_update_back_forward(gw);
  978.         return 1;
  979.  
  980. }
  981.  
  982. /* reload icon click routine */
  983. static int
  984. fb_reload_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  985. {
  986.         struct browser_window *bw = cbi->context;
  987.  
  988.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  989.                 return 0;
  990.  
  991.         browser_window_reload(bw, true);
  992.         return 1;
  993. }
  994.  
  995. /* stop icon click routine */
  996. static int
  997. fb_stop_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  998. {
  999.         struct browser_window *bw = cbi->context;
  1000.  
  1001.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1002.                 return 0;
  1003.  
  1004.         browser_window_stop(bw);
  1005.         return 0;
  1006. }
  1007.  
  1008. static int
  1009. fb_osk_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1010. {
  1011.  
  1012.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1013.                 return 0;
  1014.  
  1015.         map_osk();
  1016.  
  1017.         return 0;
  1018. }
  1019.  
  1020. /* close browser window icon click routine */
  1021. static int
  1022. fb_close_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1023. {
  1024.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1025.                 return 0;
  1026.  
  1027.         netsurf_quit = true;
  1028.         return 0;
  1029. }
  1030.  
  1031. static int
  1032. fb_scroll_callback(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1033. {
  1034.         struct gui_window *gw = cbi->context;
  1035.  
  1036.         switch (cbi->type) {
  1037.         case FBTK_CBT_SCROLLY:
  1038.                 widget_scroll_y(gw, cbi->y, true);
  1039.                 break;
  1040.  
  1041.         case FBTK_CBT_SCROLLX:
  1042.                 widget_scroll_x(gw, cbi->x, true);
  1043.                 break;
  1044.  
  1045.         default:
  1046.                 break;
  1047.         }
  1048.         return 0;
  1049. }
  1050.  
  1051. static int
  1052. fb_url_enter(void *pw, char *text)
  1053. {
  1054.         struct browser_window *bw = pw;
  1055.         browser_window_go(bw, text, 0, true);
  1056.         return 0;
  1057. }
  1058.  
  1059. static int
  1060. fb_url_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1061. {
  1062.         framebuffer_set_cursor(&caret_image);
  1063.         return 0;
  1064. }
  1065.  
  1066. static int
  1067. set_ptr_default_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1068. {
  1069.         framebuffer_set_cursor(&pointer_image);
  1070.         return 0;
  1071. }
  1072.  
  1073. static int
  1074. fb_localhistory_btn_clik(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1075. {
  1076.         struct gui_window *gw = cbi->context;
  1077.  
  1078.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1079.                 return 0;
  1080.  
  1081.         fb_localhistory_map(gw->localhistory);
  1082.  
  1083.         return 0;
  1084. }
  1085.  
  1086.  
  1087. /** Create a toolbar window and populate it with buttons.
  1088.  *
  1089.  * The toolbar layout uses a character to define buttons type and position:
  1090.  * b - back
  1091.  * l - local history
  1092.  * f - forward
  1093.  * s - stop
  1094.  * r - refresh
  1095.  * u - url bar expands to fit remaining space
  1096.  * t - throbber/activity indicator
  1097.  * c - close the current window
  1098.  *
  1099.  * The default layout is "blfsrut" there should be no more than a
  1100.  * single url bar entry or behaviour will be undefined.
  1101.  *
  1102.  * @param gw Parent window
  1103.  * @param toolbar_height The height in pixels of the toolbar
  1104.  * @param padding The padding in pixels round each element of the toolbar
  1105.  * @param frame_col Frame colour.
  1106.  * @param toolbar_layout A string defining which buttons and controls
  1107.  *                       should be added to the toolbar. May be empty
  1108.  *                       string to disable the bar..
  1109.  *
  1110.  */
  1111. static fbtk_widget_t *
  1112. create_toolbar(struct gui_window *gw,
  1113.                int toolbar_height,
  1114.                int padding,
  1115.                colour frame_col,
  1116.                const char *toolbar_layout)
  1117. {
  1118.         fbtk_widget_t *toolbar;
  1119.         fbtk_widget_t *widget;
  1120.  
  1121.         int xpos; /* The position of the next widget. */
  1122.         int xlhs = 0; /* extent of the left hand side widgets */
  1123.         int xdir = 1; /* the direction of movement + or - 1 */
  1124.         const char *itmtype; /* type of the next item */
  1125.  
  1126.         if (toolbar_layout == NULL) {
  1127.                 toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT;
  1128.         }
  1129.  
  1130.         LOG(("Using toolbar layout %s", toolbar_layout));
  1131.  
  1132.         itmtype = toolbar_layout;
  1133.  
  1134.         if (*itmtype == 0) {
  1135.                 return NULL;
  1136.         }
  1137.  
  1138.         toolbar = fbtk_create_window(gw->window, 0, 0, 0,
  1139.                                      toolbar_height,
  1140.                                      frame_col);
  1141.  
  1142.         if (toolbar == NULL) {
  1143.                 return NULL;
  1144.         }
  1145.  
  1146.         fbtk_set_handler(toolbar,
  1147.                          FBTK_CBT_POINTERENTER,
  1148.                          set_ptr_default_move,
  1149.                          NULL);
  1150.  
  1151.  
  1152.         xpos = padding;
  1153.  
  1154.         /* loop proceeds creating widget on the left hand side until
  1155.          * it runs out of layout or encounters a url bar declaration
  1156.          * wherupon it works backwards from the end of the layout
  1157.          * untill the space left is for the url bar
  1158.          */
  1159.         while ((itmtype >= toolbar_layout) &&
  1160.                (*itmtype != 0) &&
  1161.                (xdir !=0)) {
  1162.  
  1163.                 LOG(("toolbar adding %c", *itmtype));
  1164.  
  1165.  
  1166.                 switch (*itmtype) {
  1167.  
  1168.                 case 'b': /* back */
  1169.                         widget = fbtk_create_button(toolbar,
  1170.                                                     (xdir == 1) ? xpos :
  1171.                                                      xpos - left_arrow.width,
  1172.                                                     padding,
  1173.                                                     left_arrow.width,
  1174.                                                     -padding,
  1175.                                                     frame_col,
  1176.                                                     &left_arrow,
  1177.                                                     fb_leftarrow_click,
  1178.                                                     gw);
  1179.                         gw->back = widget; /* keep reference */
  1180.                         break;
  1181.  
  1182.                 case 'l': /* local history */
  1183.                         widget = fbtk_create_button(toolbar,
  1184.                                                     (xdir == 1) ? xpos :
  1185.                                                      xpos - history_image.width,
  1186.                                                     padding,
  1187.                                                     history_image.width,
  1188.                                                     -padding,
  1189.                                                     frame_col,
  1190.                                                     &history_image,
  1191.                                                     fb_localhistory_btn_clik,
  1192.                                                     gw);
  1193.                         break;
  1194.  
  1195.                 case 'f': /* forward */
  1196.                         widget = fbtk_create_button(toolbar,
  1197.                                                     (xdir == 1)?xpos :
  1198.                                                      xpos - right_arrow.width,
  1199.                                                     padding,
  1200.                                                     right_arrow.width,
  1201.                                                     -padding,
  1202.                                                     frame_col,
  1203.                                                     &right_arrow,
  1204.                                                     fb_rightarrow_click,
  1205.                                                     gw);
  1206.                         gw->forward = widget;
  1207.                         break;
  1208.  
  1209.                 case 'c': /* close the current window */
  1210.                         widget = fbtk_create_button(toolbar,
  1211.                                                     (xdir == 1)?xpos :
  1212.                                                      xpos - stop_image_g.width,
  1213.                                                     padding,
  1214.                                                     stop_image_g.width,
  1215.                                                     -padding,
  1216.                                                     frame_col,
  1217.                                                     &stop_image_g,
  1218.                                                     fb_close_click,
  1219.                                                     gw->bw);
  1220.                         break;
  1221.  
  1222.                 case 's': /* stop  */
  1223.                         widget = fbtk_create_button(toolbar,
  1224.                                                     (xdir == 1)?xpos :
  1225.                                                      xpos - stop_image.width,
  1226.                                                     padding,
  1227.                                                     stop_image.width,
  1228.                                                     -padding,
  1229.                                                     frame_col,
  1230.                                                     &stop_image,
  1231.                                                     fb_stop_click,
  1232.                                                     gw->bw);
  1233.                         break;
  1234.  
  1235.                 case 'r': /* reload */
  1236.                         widget = fbtk_create_button(toolbar,
  1237.                                                     (xdir == 1)?xpos :
  1238.                                                      xpos - reload.width,
  1239.                                                     padding,
  1240.                                                     reload.width,
  1241.                                                     -padding,
  1242.                                                     frame_col,
  1243.                                                     &reload,
  1244.                                                     fb_reload_click,
  1245.                                                     gw->bw);
  1246.                         break;
  1247.  
  1248.                 case 't': /* throbber/activity indicator */
  1249.                         widget = fbtk_create_bitmap(toolbar,
  1250.                                                     (xdir == 1)?xpos :
  1251.                                                      xpos - throbber0.width,
  1252.                                                     padding,
  1253.                                                     throbber0.width,
  1254.                                                     -padding,
  1255.                                                     frame_col,
  1256.                                                     &throbber0);
  1257.                         gw->throbber = widget;
  1258.                         break;
  1259.  
  1260.  
  1261.                 case 'u': /* url bar*/
  1262.                         if (xdir == -1) {
  1263.                                 /* met the u going backwards add url
  1264.                                  * now we know available extent
  1265.                                  */
  1266.  
  1267.                                 widget = fbtk_create_writable_text(toolbar,
  1268.                                                    xlhs,
  1269.                                                    padding,
  1270.                                                    xpos - xlhs,
  1271.                                                    -padding,
  1272.                                                    FB_COLOUR_WHITE,
  1273.                                                    FB_COLOUR_BLACK,
  1274.                                                    true,
  1275.                                                    fb_url_enter,
  1276.                                                    gw->bw);
  1277.  
  1278.                                 fbtk_set_handler(widget,
  1279.                                                  FBTK_CBT_POINTERENTER,
  1280.                                                  fb_url_move, gw->bw);
  1281.  
  1282.                                 gw->url = widget; /* keep reference */
  1283.  
  1284.                                 /* toolbar is complete */
  1285.                                 xdir = 0;
  1286.                                 break;
  1287.                         }
  1288.                         /* met url going forwards, note position and
  1289.                          * reverse direction
  1290.                          */
  1291.                         itmtype = toolbar_layout + strlen(toolbar_layout);
  1292.                         xdir = -1;
  1293.                         xlhs = xpos;
  1294.                         xpos = (2 * fbtk_get_width(toolbar));
  1295.                         widget = toolbar;
  1296.                         break;
  1297.  
  1298.                 default:
  1299.                         widget = NULL;
  1300.                         xdir = 0;
  1301.                         LOG(("Unknown element %c in toolbar layout", *itmtype));
  1302.                         break;
  1303.  
  1304.                 }
  1305.  
  1306.                 if (widget != NULL) {
  1307.                         xpos += (xdir * (fbtk_get_width(widget) + padding));
  1308.                 }
  1309.  
  1310.                 LOG(("xpos is %d",xpos));
  1311.  
  1312.                 itmtype += xdir;
  1313.         }
  1314.  
  1315.         fbtk_set_mapping(toolbar, true);
  1316.  
  1317.         return toolbar;
  1318. }
  1319.  
  1320. /** Routine called when "stripped of focus" event occours for browser widget.
  1321.  *
  1322.  * @param widget The widget reciving "stripped of focus" event.
  1323.  * @param cbi The callback parameters.
  1324.  * @return The callback result.
  1325.  */
  1326. static int
  1327. fb_browser_window_strip_focus(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1328. {
  1329.         fbtk_set_caret(widget, false, 0, 0, 0, NULL);
  1330.  
  1331.         return 0;
  1332. }
  1333.  
  1334. static void
  1335. create_browser_widget(struct gui_window *gw, int toolbar_height, int furniture_width)
  1336. {
  1337.         struct browser_widget_s *browser_widget;
  1338.         browser_widget = calloc(1, sizeof(struct browser_widget_s));
  1339.  
  1340.         gw->browser = fbtk_create_user(gw->window,
  1341.                                        0,
  1342.                                        toolbar_height,
  1343.                                        -furniture_width,
  1344.                                        -furniture_width,
  1345.                                        browser_widget);
  1346.  
  1347.         fbtk_set_handler(gw->browser, FBTK_CBT_REDRAW, fb_browser_window_redraw, gw);
  1348.         fbtk_set_handler(gw->browser, FBTK_CBT_INPUT, fb_browser_window_input, gw);
  1349.         fbtk_set_handler(gw->browser, FBTK_CBT_CLICK, fb_browser_window_click, gw);
  1350.         fbtk_set_handler(gw->browser, FBTK_CBT_STRIP_FOCUS, fb_browser_window_strip_focus, gw);
  1351.         fbtk_set_handler(gw->browser, FBTK_CBT_POINTERMOVE, fb_browser_window_move, gw);
  1352. }
  1353.  
  1354. static void
  1355. create_normal_browser_window(struct gui_window *gw, int furniture_width)
  1356. {
  1357.         LOG(("enter norm win"));
  1358.         fbtk_widget_t *widget;
  1359.         fbtk_widget_t *toolbar;
  1360.         int statusbar_width = 0;
  1361.         int toolbar_height = 30; //nsoption_int(fb_toolbar_size);
  1362.  
  1363.         LOG(("Normal window"));
  1364.  
  1365.         gw->window = fbtk_create_window(fbtk, 0, 0, 0, 0, 0);
  1366.  
  1367.         statusbar_width = nsoption_int(toolbar_status_width) *
  1368.                 fbtk_get_width(gw->window) / 10000;
  1369.  
  1370. LOG(("STUB options"));
  1371.  
  1372.                  
  1373.                          
  1374.         nsoptions.fb_depth = 16;                                       
  1375.         nsoptions.fb_refresh = 70;                             
  1376.         nsoptions.fb_device = NULL;                            
  1377.         nsoptions.fb_input_devpath = NULL;                     
  1378.         nsoptions.fb_input_glob = NULL;                        
  1379.         nsoptions.fb_furniture_size = 18;                      
  1380.         nsoptions.fb_toolbar_size = 30;                        
  1381.         nsoptions.fb_toolbar_layout = NULL;                            
  1382.         nsoptions.fb_osk = false;                              
  1383.  
  1384.  
  1385.  
  1386.         /* toolbar */
  1387.         LOG(("toolbar"));
  1388.        
  1389.        
  1390.        
  1391.         toolbar = create_toolbar(gw,
  1392.                                  toolbar_height,
  1393.                                  2,
  1394.                                  FB_FRAME_COLOUR,
  1395.                                  nsoption_charp(fb_toolbar_layout));
  1396.  
  1397.         /* set the actually created toolbar height */
  1398.         if (toolbar != NULL) {
  1399.                 toolbar_height = fbtk_get_height(toolbar);
  1400.         } else {
  1401.                 toolbar_height = 0;
  1402.         }
  1403.  
  1404.         LOG(("statbar"));
  1405.         /* status bar */
  1406.         gw->status = fbtk_create_text(gw->window,
  1407.                                       0,
  1408.                                       fbtk_get_height(gw->window) - furniture_width,
  1409.                                       statusbar_width, furniture_width,
  1410.                                       FB_FRAME_COLOUR, FB_COLOUR_BLACK,
  1411.                                       false);
  1412.        
  1413.         LOG(("handler"));
  1414.         fbtk_set_handler(gw->status, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
  1415.  
  1416.         LOG(("status bar %p at %d,%d", gw->status, fbtk_get_absx(gw->status), fbtk_get_absy(gw->status)));
  1417.  
  1418.         /* create horizontal scrollbar */
  1419.         LOG(("hor sb"));
  1420.        
  1421.         gw->hscroll = fbtk_create_hscroll(gw->window,
  1422.                                           statusbar_width,
  1423.                                           fbtk_get_height(gw->window) - furniture_width,
  1424.                                           fbtk_get_width(gw->window) - statusbar_width - furniture_width,
  1425.                                           furniture_width,
  1426.                                           FB_SCROLL_COLOUR,
  1427.                                           FB_FRAME_COLOUR,
  1428.                                           fb_scroll_callback,
  1429.                                           gw);
  1430.  
  1431.         /* fill bottom right area */
  1432.         LOG(("fill bottom"));
  1433.  
  1434.         if (nsoption_bool(fb_osk) == true) {
  1435.                 widget = fbtk_create_text_button(gw->window,
  1436.                                                  fbtk_get_width(gw->window) - furniture_width,
  1437.                                                  fbtk_get_height(gw->window) - furniture_width,
  1438.                                                  furniture_width,
  1439.                                                  furniture_width,
  1440.                                                  FB_FRAME_COLOUR, FB_COLOUR_BLACK,
  1441.                                                  fb_osk_click,
  1442.                                                  NULL);
  1443.                 widget = fbtk_create_button(gw->window,
  1444.                                 fbtk_get_width(gw->window) - furniture_width,
  1445.                                 fbtk_get_height(gw->window) - furniture_width,
  1446.                                 furniture_width,
  1447.                                 furniture_width,
  1448.                                 FB_FRAME_COLOUR,
  1449.                                 &osk_image,
  1450.                                 fb_osk_click,
  1451.                                 NULL);
  1452.         } else {
  1453.                 widget = fbtk_create_fill(gw->window,
  1454.                                           fbtk_get_width(gw->window) - furniture_width,
  1455.                                           fbtk_get_height(gw->window) - furniture_width,
  1456.                                           furniture_width,
  1457.                                           furniture_width,
  1458.                                           FB_FRAME_COLOUR);
  1459.  
  1460.                 fbtk_set_handler(widget, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
  1461.         }
  1462.  
  1463.         LOG(("vsb GUI"));
  1464.         /* create vertical scrollbar */
  1465.         gw->vscroll = fbtk_create_vscroll(gw->window,
  1466.                                           fbtk_get_width(gw->window) - furniture_width,
  1467.                                           toolbar_height,
  1468.                                           furniture_width,
  1469.                                           fbtk_get_height(gw->window) - toolbar_height - furniture_width,
  1470.                                           FB_SCROLL_COLOUR,
  1471.                                           FB_FRAME_COLOUR,
  1472.                                           fb_scroll_callback,
  1473.                                           gw);
  1474.  
  1475.         LOG(("BRO widget"));
  1476.         /* browser widget */
  1477.         create_browser_widget(gw, toolbar_height, nsoption_int(fb_furniture_size));
  1478.  
  1479.         LOG(("set focus"));
  1480.         /* Give browser_window's user widget input focus */
  1481.         fbtk_set_focus(gw->browser);
  1482.         LOG(("GUI OK"));
  1483. }
  1484.  
  1485.  
  1486. struct gui_window *
  1487. gui_create_browser_window(struct browser_window *bw,
  1488.                           struct browser_window *clone,
  1489.                           bool new_tab)
  1490. {
  1491.         struct gui_window *gw;
  1492.         LOG(("GCBW calloc"));
  1493.        
  1494.         gw = calloc(1, sizeof(struct gui_window));
  1495.  
  1496.         if (gw == NULL)
  1497.                 return NULL;
  1498.  
  1499.         /* seems we need to associate the gui window with the underlying
  1500.          * browser window
  1501.          */
  1502.         LOG(("GCBW next.."));
  1503.        
  1504.        
  1505.         gw->bw = bw;
  1506.  
  1507.         LOG(("fb_furn_size is STUB now!..."));
  1508.        
  1509.          //nsoption_int(fb_furniture_size);
  1510.         LOG(("GCBW create normal window..."));
  1511.        
  1512.        
  1513.         create_normal_browser_window(gw, 18); //nsoption_int(fb_furniture_size));
  1514.         LOG(("GCBW create local history..."));
  1515.        
  1516.         gw->localhistory = fb_create_localhistory(bw, fbtk, nsoption_int(fb_furniture_size));
  1517.  
  1518.         /* map and request redraw of gui window */
  1519.         LOG(("GCBW set mapping"));
  1520.        
  1521.         fbtk_set_mapping(gw->window, true);
  1522.         LOG(("GCBW OK!"));
  1523.        
  1524.  
  1525.         return gw;
  1526. }
  1527.  
  1528. void
  1529. gui_window_destroy(struct gui_window *gw)
  1530. {
  1531.         fbtk_destroy_widget(gw->window);
  1532.  
  1533.         free(gw);
  1534.  
  1535.  
  1536. }
  1537.  
  1538. void
  1539. gui_window_set_title(struct gui_window *g, const char *title)
  1540. {
  1541.         LOG(("%p, %s", g, title));
  1542. }
  1543.  
  1544. void
  1545. gui_window_redraw_window(struct gui_window *g)
  1546. {
  1547.         fb_queue_redraw(g->browser, 0, 0, fbtk_get_width(g->browser), fbtk_get_height(g->browser) );
  1548. }
  1549.  
  1550. void
  1551. gui_window_update_box(struct gui_window *g, const struct rect *rect)
  1552. {
  1553.         struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
  1554.         fb_queue_redraw(g->browser,
  1555.                         rect->x0 - bwidget->scrollx,
  1556.                         rect->y0 - bwidget->scrolly,
  1557.                         rect->x1 - bwidget->scrollx,
  1558.                         rect->y1 - bwidget->scrolly);
  1559. }
  1560.  
  1561. bool
  1562. gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
  1563. {
  1564.         struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
  1565.  
  1566.         *sx = bwidget->scrollx / g->bw->scale;
  1567.         *sy = bwidget->scrolly / g->bw->scale;
  1568.  
  1569.         return true;
  1570. }
  1571.  
  1572. void
  1573. gui_window_set_scroll(struct gui_window *gw, int sx, int sy)
  1574. {
  1575.         struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
  1576.  
  1577.         assert(bwidget);
  1578.  
  1579.         widget_scroll_x(gw, sx * gw->bw->scale, true);
  1580.         widget_scroll_y(gw, sy * gw->bw->scale, true);
  1581. }
  1582.  
  1583. void
  1584. gui_window_scroll_visible(struct gui_window *g, int x0, int y0,
  1585.                           int x1, int y1)
  1586. {
  1587.         LOG(("%s:(%p, %d, %d, %d, %d)", __func__, g, x0, y0, x1, y1));
  1588. }
  1589.  
  1590. void
  1591. gui_window_get_dimensions(struct gui_window *g,
  1592.                           int *width,
  1593.                           int *height,
  1594.                           bool scaled)
  1595. {
  1596.         *width = fbtk_get_width(g->browser);
  1597.         *height = fbtk_get_height(g->browser);
  1598.  
  1599.         if (scaled) {
  1600.                 *width /= g->bw->scale;
  1601.                 *height /= g->bw->scale;
  1602.         }
  1603. }
  1604.  
  1605. void
  1606. gui_window_update_extent(struct gui_window *gw)
  1607. {
  1608.         float scale = gw->bw->scale;
  1609.  
  1610.         fbtk_set_scroll_parameters(gw->hscroll, 0,
  1611.                         content_get_width(gw->bw->current_content) * scale,
  1612.                         fbtk_get_width(gw->browser), 100);
  1613.  
  1614.         fbtk_set_scroll_parameters(gw->vscroll, 0,
  1615.                         content_get_height(gw->bw->current_content) * scale,
  1616.                         fbtk_get_height(gw->browser), 100);
  1617. }
  1618.  
  1619. void
  1620. gui_window_set_status(struct gui_window *g, const char *text)
  1621. {
  1622.         fbtk_set_text(g->status, text);
  1623. }
  1624.  
  1625. void
  1626. gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
  1627. {
  1628.         switch (shape) {
  1629.         case GUI_POINTER_POINT:
  1630.                 framebuffer_set_cursor(&hand_image);
  1631.                 break;
  1632.  
  1633.         case GUI_POINTER_CARET:
  1634.                 framebuffer_set_cursor(&caret_image);
  1635.                 break;
  1636.  
  1637.         case GUI_POINTER_MENU:
  1638.                 framebuffer_set_cursor(&menu_image);
  1639.                 break;
  1640.  
  1641.         case GUI_POINTER_PROGRESS:
  1642.                 framebuffer_set_cursor(&progress_image);
  1643.                 break;
  1644.  
  1645.         case GUI_POINTER_MOVE:
  1646.                 framebuffer_set_cursor(&move_image);
  1647.                 break;
  1648.  
  1649.         default:
  1650.                 framebuffer_set_cursor(&pointer_image);
  1651.                 break;
  1652.         }
  1653. }
  1654.  
  1655. void
  1656. gui_window_hide_pointer(struct gui_window *g)
  1657. {
  1658. }
  1659.  
  1660. void
  1661. gui_window_set_url(struct gui_window *g, const char *url)
  1662. {
  1663.         fbtk_set_text(g->url, url);
  1664. }
  1665.  
  1666. static void
  1667. throbber_advance(void *pw)
  1668. {
  1669.         struct gui_window *g = pw;
  1670.         struct fbtk_bitmap *image;
  1671.  
  1672.         switch (g->throbber_index) {
  1673.         case 0:
  1674.                 image = &throbber1;
  1675.                 g->throbber_index = 1;
  1676.                 break;
  1677.  
  1678.         case 1:
  1679.                 image = &throbber2;
  1680.                 g->throbber_index = 2;
  1681.                 break;
  1682.  
  1683.         case 2:
  1684.                 image = &throbber3;
  1685.                 g->throbber_index = 3;
  1686.                 break;
  1687.  
  1688.         case 3:
  1689.                 image = &throbber4;
  1690.                 g->throbber_index = 4;
  1691.                 break;
  1692.  
  1693.         case 4:
  1694.                 image = &throbber5;
  1695.                 g->throbber_index = 5;
  1696.                 break;
  1697.  
  1698.         case 5:
  1699.                 image = &throbber6;
  1700.                 g->throbber_index = 6;
  1701.                 break;
  1702.  
  1703.         case 6:
  1704.                 image = &throbber7;
  1705.                 g->throbber_index = 7;
  1706.                 break;
  1707.  
  1708.         case 7:
  1709.                 image = &throbber8;
  1710.                 g->throbber_index = 0;
  1711.                 break;
  1712.  
  1713.         default:
  1714.                 return;
  1715.         }
  1716.  
  1717.         if (g->throbber_index >= 0) {
  1718.                 fbtk_set_bitmap(g->throbber, image);
  1719.                 schedule(10, throbber_advance, g);
  1720.         }
  1721. }
  1722.  
  1723. void
  1724. gui_window_start_throbber(struct gui_window *g)
  1725. {
  1726.         g->throbber_index = 0;
  1727.         schedule(10, throbber_advance, g);
  1728. }
  1729.  
  1730. void
  1731. gui_window_stop_throbber(struct gui_window *gw)
  1732. {
  1733.         gw->throbber_index = -1;
  1734.         fbtk_set_bitmap(gw->throbber, &throbber0);
  1735.  
  1736.         fb_update_back_forward(gw);
  1737.  
  1738. }
  1739.  
  1740. static void
  1741. gui_window_remove_caret_cb(fbtk_widget_t *widget)
  1742. {
  1743.         struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
  1744.         int c_x, c_y, c_h;
  1745.  
  1746.         if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
  1747.                 /* browser window already had caret:
  1748.                  * redraw its area to remove it first */
  1749.                 fb_queue_redraw(widget,
  1750.                                 c_x - bwidget->scrollx,
  1751.                                 c_y - bwidget->scrolly,
  1752.                                 c_x + 1 - bwidget->scrollx,
  1753.                                 c_y + c_h - bwidget->scrolly);
  1754.         }
  1755. }
  1756.  
  1757. void
  1758. gui_window_place_caret(struct gui_window *g, int x, int y, int height)
  1759. {
  1760.         struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
  1761.  
  1762.         /* set new pos */
  1763.         fbtk_set_caret(g->browser, true, x, y, height,
  1764.                         gui_window_remove_caret_cb);
  1765.  
  1766.         /* redraw new caret pos */
  1767.         fb_queue_redraw(g->browser,
  1768.                         x - bwidget->scrollx,
  1769.                         y - bwidget->scrolly,
  1770.                         x + 1 - bwidget->scrollx,
  1771.                         y + height - bwidget->scrolly);
  1772. }
  1773.  
  1774. void
  1775. gui_window_remove_caret(struct gui_window *g)
  1776. {
  1777.         int c_x, c_y, c_h;
  1778.  
  1779.         if (fbtk_get_caret(g->browser, &c_x, &c_y, &c_h)) {
  1780.                 /* browser window owns the caret, so can remove it */
  1781.                 fbtk_set_caret(g->browser, false, 0, 0, 0, NULL);
  1782.         }
  1783. }
  1784.  
  1785. void
  1786. gui_window_new_content(struct gui_window *g)
  1787. {
  1788. }
  1789.  
  1790. bool
  1791. gui_window_scroll_start(struct gui_window *g)
  1792. {
  1793.         return true;
  1794. }
  1795.  
  1796. bool
  1797. gui_window_drag_start(struct gui_window *g, gui_drag_type type,
  1798.                       const struct rect *rect)
  1799. {
  1800.         return true;
  1801. }
  1802.  
  1803. void
  1804. gui_window_save_link(struct gui_window *g, const char *url, const char *title)
  1805. {
  1806. }
  1807.  
  1808. /**
  1809.  * set favicon
  1810.  */
  1811. void
  1812. gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
  1813. {
  1814. }
  1815.  
  1816. /**
  1817.  * set gui display of a retrieved favicon representing the search provider
  1818.  * \param ico may be NULL for local calls; then access current cache from
  1819.  * search_web_ico()
  1820.  */
  1821. void
  1822. gui_window_set_search_ico(hlcache_handle *ico)
  1823. {
  1824. }
  1825.  
  1826. struct gui_download_window *
  1827. gui_download_window_create(download_context *ctx, struct gui_window *parent)
  1828. {
  1829.         return NULL;
  1830. }
  1831.  
  1832. nserror
  1833. gui_download_window_data(struct gui_download_window *dw,
  1834.                          const char *data,
  1835.                          unsigned int size)
  1836. {
  1837.         return NSERROR_OK;
  1838. }
  1839.  
  1840. void
  1841. gui_download_window_error(struct gui_download_window *dw,
  1842.                           const char *error_msg)
  1843. {
  1844. }
  1845.  
  1846. void
  1847. gui_download_window_done(struct gui_download_window *dw)
  1848. {
  1849. }
  1850.  
  1851. void
  1852. gui_drag_save_object(gui_save_type type,
  1853.                      hlcache_handle *c,
  1854.                      struct gui_window *w)
  1855. {
  1856. }
  1857.  
  1858. void
  1859. gui_drag_save_selection(struct selection *s, struct gui_window *g)
  1860. {
  1861. }
  1862.  
  1863. void
  1864. gui_start_selection(struct gui_window *g)
  1865. {
  1866. }
  1867.  
  1868. void
  1869. gui_clear_selection(struct gui_window *g)
  1870. {
  1871. }
  1872.  
  1873. void
  1874. gui_create_form_select_menu(struct browser_window *bw,
  1875.                             struct form_control *control)
  1876. {
  1877. }
  1878.  
  1879. void
  1880. gui_launch_url(const char *url)
  1881. {
  1882. }
  1883.  
  1884. void
  1885. gui_cert_verify(nsurl *url,
  1886.                 const struct ssl_cert_info *certs,
  1887.                 unsigned long num,
  1888.                 nserror (*cb)(bool proceed, void *pw),
  1889.                 void *cbpw)
  1890. {
  1891.         cb(false, cbpw);
  1892. }
  1893.  
  1894. /*
  1895.  * Local Variables:
  1896.  * c-basic-offset:8
  1897.  * End:
  1898.  */
  1899.