Subversion Repositories Kolibri OS

Rev

Rev 3624 | 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 = "kolibri";
  431.         febpp = 32;
  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 = 790; //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.         char p[256];
  545.         char **z;
  546.         z=0x20;
  547.         strcpy(p, *z);
  548.        
  549.         __menuet__debug_out("PATH1...\n");
  550.         __menuet__debug_out(p);
  551.         __menuet__debug_out("PATH1...\n");
  552.        
  553.         *(strrchr(p, '/')+1)='\0';
  554.        
  555.         strcpy(strrchr(p, '/')+1, "res/");
  556.        
  557.         __menuet__debug_out("PATH1...\n");
  558.         __menuet__debug_out(p);
  559.         __menuet__debug_out("PATH1...\n");
  560.  
  561.         asm volatile ("int $0x40"::"a"(30), "b"(1), "c"(p));
  562.        
  563.         LOG(("Registering surfaces for SDL and RAM.."));
  564.        
  565.         //extern nsfb_surface_rtns_t sdl_rtns;
  566.         extern nsfb_surface_rtns_t ram_rtns;
  567.         extern nsfb_surface_rtns_t able_rtns;
  568.         extern nsfb_surface_rtns_t kolibri_rtns;
  569.        
  570.         //_nsfb_register_surface(NSFB_SURFACE_SDL, &sdl_rtns, "sdl");
  571.         _nsfb_register_surface(NSFB_SURFACE_RAM, &ram_rtns, "ram");
  572.         _nsfb_register_surface(NSFB_SURFACE_ABLE, &able_rtns, "able");
  573.         _nsfb_register_surface(NSFB_SURFACE_KOLIBRI, &kolibri_rtns, "kolibri");
  574.        
  575.        
  576.         //respaths = fb_init_resource("/kolibrios/:/hd0/1/res/:/bd0/1/res/:/tmp9/1/netsurf/res/:res/:fonts/:");
  577.         respaths = fb_init_resource(p);
  578.  
  579.         options = filepath_find(respaths, "Choices");
  580.         messages = filepath_find(respaths, "messages");
  581.  
  582.         __menuet__debug_out("===path to msg\n");
  583.         __menuet__debug_out(messages);
  584.         __menuet__debug_out("\n===path to msg\n");
  585.        
  586.         //netsurf_init(&argc, &argv, options, "res/messages");
  587.         netsurf_init(&argc, &argv, options, messages);
  588.         extern HTTP_INIT();
  589.         HTTP_INIT();
  590.         LOG(("NS init okay"));
  591.        
  592.         free(messages);
  593.         free(options);
  594.  
  595.         LOG(("freed opts and msgs, start gui init"));
  596.        
  597.  
  598.         gui_init(argc, argv);
  599.  
  600.         LOG(("calling browser_window_create in MAIN()"));
  601.         bw = browser_window_create(feurl, 0, 0, true, false);
  602.  
  603.  
  604.         LOG(("NS main loop..."));
  605.        
  606.         netsurf_main_loop();
  607.  
  608.         browser_window_destroy(bw);
  609.  
  610.         netsurf_exit();
  611.  
  612.         return 0;
  613. }
  614.  
  615.  
  616. void
  617. gui_poll(bool active)
  618. {
  619.         LOG(("GUI poll in"));
  620.  
  621.         nsfb_event_t event;
  622.         int timeout; /* timeout in miliseconds */
  623.  
  624. LOG(("schedule run"));
  625.         /* run the scheduler and discover how long to wait for the next event */
  626.         timeout = schedule_run();
  627.  
  628.         /* if active do not wait for event, return immediately */
  629.         if (active)
  630.                 timeout = 0;
  631.  
  632. LOG(("redraw pending"));
  633.         /* if redraws are pending do not wait for event, return immediately */
  634.         if (fbtk_get_redraw_pending(fbtk))
  635.                 timeout = 0;
  636.  
  637. LOG(("fbtk event"));
  638.         if (fbtk_event(fbtk, &event, timeout)) {
  639.                 if ((event.type == NSFB_EVENT_CONTROL) &&
  640.                     (event.value.controlcode ==  NSFB_CONTROL_QUIT))
  641.                         netsurf_quit = true;
  642.         }
  643.  
  644. LOG(("fbtk redraw"));
  645.         fbtk_redraw(fbtk);
  646.  
  647. LOG(("GUI poll out success"));
  648. }
  649.  
  650. void
  651. gui_quit(void)
  652. {
  653.         LOG(("gui_quit"));
  654.  
  655.         urldb_save_cookies(nsoption_charp(cookie_jar));
  656.  
  657.         framebuffer_finalise();
  658. }
  659.  
  660. /* called back when click in browser window */
  661. static int
  662. fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  663. {
  664.         struct gui_window *gw = cbi->context;
  665.         struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
  666.         float scale = gw->bw->scale;
  667.         int x = (cbi->x + bwidget->scrollx) / scale;
  668.         int y = (cbi->y + bwidget->scrolly) / scale;
  669.  
  670.         if (cbi->event->type != NSFB_EVENT_KEY_DOWN &&
  671.             cbi->event->type != NSFB_EVENT_KEY_UP)
  672.                 return 0;
  673.  
  674.         LOG(("browser window clicked at %d,%d", cbi->x, cbi->y));
  675.  
  676.         switch (cbi->event->type) {
  677.         case NSFB_EVENT_KEY_DOWN:
  678.                 switch (cbi->event->value.keycode) {
  679.                 case NSFB_KEY_MOUSE_1:
  680.                         browser_window_mouse_click(gw->bw,
  681.                                         BROWSER_MOUSE_PRESS_1, x, y);
  682.                         gui_drag.state = GUI_DRAG_PRESSED;
  683.                         gui_drag.button = 1;
  684.                         gui_drag.x = x;
  685.                         gui_drag.y = y;
  686.                         break;
  687.  
  688.                 case NSFB_KEY_MOUSE_3:
  689.                         browser_window_mouse_click(gw->bw,
  690.                                         BROWSER_MOUSE_PRESS_2, x, y);
  691.                         gui_drag.state = GUI_DRAG_PRESSED;
  692.                         gui_drag.button = 2;
  693.                         gui_drag.x = x;
  694.                         gui_drag.y = y;
  695.                         break;
  696.  
  697.                 case NSFB_KEY_MOUSE_4:
  698.                         /* scroll up */
  699.                         if (browser_window_scroll_at_point(gw->bw, x, y,
  700.                                         0, -100) == false)
  701.                                 widget_scroll_y(gw, -100, false);
  702.                         break;
  703.  
  704.                 case NSFB_KEY_MOUSE_5:
  705.                         /* scroll down */
  706.                         if (browser_window_scroll_at_point(gw->bw, x, y,
  707.                                         0, 100) == false)
  708.                                 widget_scroll_y(gw, 100, false);
  709.                         break;
  710.  
  711.                 default:
  712.                         break;
  713.  
  714.                 }
  715.  
  716.                 break;
  717.         case NSFB_EVENT_KEY_UP:
  718.                 switch (cbi->event->value.keycode) {
  719.                 case NSFB_KEY_MOUSE_1:
  720.                         if (gui_drag.state == GUI_DRAG_DRAG) {
  721.                                 /* End of a drag, rather than click */
  722.  
  723.                                 if (gui_drag.grabbed_pointer) {
  724.                                         /* need to ungrab pointer */
  725.                                         fbtk_tgrab_pointer(widget);
  726.                                         gui_drag.grabbed_pointer = false;
  727.                                 }
  728.  
  729.                                 gui_drag.state = GUI_DRAG_NONE;
  730.  
  731.                                 /* Tell core */
  732.                                 browser_window_mouse_track(gw->bw, 0, x, y);
  733.                                 break;
  734.                         }
  735.                         /* This is a click;
  736.                          * clear PRESSED state and pass to core */
  737.                         gui_drag.state = GUI_DRAG_NONE;
  738.                         browser_window_mouse_click(gw->bw,
  739.                                         BROWSER_MOUSE_CLICK_1, x, y);
  740.                         break;
  741.  
  742.                 case NSFB_KEY_MOUSE_3:
  743.                         if (gui_drag.state == GUI_DRAG_DRAG) {
  744.                                 /* End of a drag, rather than click */
  745.                                 gui_drag.state = GUI_DRAG_NONE;
  746.  
  747.                                 if (gui_drag.grabbed_pointer) {
  748.                                         /* need to ungrab pointer */
  749.                                         fbtk_tgrab_pointer(widget);
  750.                                         gui_drag.grabbed_pointer = false;
  751.                                 }
  752.  
  753.                                 /* Tell core */
  754.                                 browser_window_mouse_track(gw->bw, 0, x, y);
  755.                                 break;
  756.                         }
  757.                         /* This is a click;
  758.                          * clear PRESSED state and pass to core */
  759.                         gui_drag.state = GUI_DRAG_NONE;
  760.                         browser_window_mouse_click(gw->bw,
  761.                                         BROWSER_MOUSE_CLICK_2, x, y);
  762.                         break;
  763.  
  764.                 default:
  765.                         break;
  766.  
  767.                 }
  768.  
  769.                 break;
  770.         default:
  771.                 break;
  772.  
  773.         }
  774.         return 1;
  775. }
  776.  
  777. /* called back when movement in browser window */
  778. static int
  779. fb_browser_window_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  780. {
  781.         browser_mouse_state mouse = 0;
  782.         struct gui_window *gw = cbi->context;
  783.         struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
  784.         int x = (cbi->x + bwidget->scrollx) / gw->bw->scale;
  785.         int y = (cbi->y + bwidget->scrolly) / gw->bw->scale;
  786.  
  787.         if (gui_drag.state == GUI_DRAG_PRESSED &&
  788.                         (abs(x - gui_drag.x) > 5 ||
  789.                          abs(y - gui_drag.y) > 5)) {
  790.                 /* Drag started */
  791.                 if (gui_drag.button == 1) {
  792.                         browser_window_mouse_click(gw->bw,
  793.                                         BROWSER_MOUSE_DRAG_1,
  794.                                         gui_drag.x, gui_drag.y);
  795.                 } else {
  796.                         browser_window_mouse_click(gw->bw,
  797.                                         BROWSER_MOUSE_DRAG_2,
  798.                                         gui_drag.x, gui_drag.y);
  799.                 }
  800.                 gui_drag.grabbed_pointer = fbtk_tgrab_pointer(widget);
  801.                 gui_drag.state = GUI_DRAG_DRAG;
  802.         }
  803.  
  804.         if (gui_drag.state == GUI_DRAG_DRAG) {
  805.                 /* set up mouse state */
  806.                 mouse |= BROWSER_MOUSE_DRAG_ON;
  807.  
  808.                 if (gui_drag.button == 1)
  809.                         mouse |= BROWSER_MOUSE_HOLDING_1;
  810.                 else
  811.                         mouse |= BROWSER_MOUSE_HOLDING_2;
  812.         }
  813.  
  814.         browser_window_mouse_track(gw->bw, mouse, x, y);
  815.  
  816.         return 0;
  817. }
  818.  
  819.  
  820. static int
  821. fb_browser_window_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  822. {
  823.         struct gui_window *gw = cbi->context;
  824.         static fbtk_modifier_type modifier = FBTK_MOD_CLEAR;
  825.         int ucs4 = -1;
  826.  
  827.         LOG(("got value %d", cbi->event->value.keycode));
  828.  
  829.         switch (cbi->event->type) {
  830.         case NSFB_EVENT_KEY_DOWN:
  831.                 switch (cbi->event->value.keycode) {
  832.  
  833.                 case NSFB_KEY_PAGEUP:
  834.                         if (browser_window_key_press(gw->bw,
  835.                                         KEY_PAGE_UP) == false)
  836.                                 widget_scroll_y(gw, -fbtk_get_height(
  837.                                                 gw->browser), false);
  838.                         break;
  839.  
  840.                 case NSFB_KEY_PAGEDOWN:
  841.                         if (browser_window_key_press(gw->bw,
  842.                                         KEY_PAGE_DOWN) == false)
  843.                                 widget_scroll_y(gw, fbtk_get_height(
  844.                                                 gw->browser), false);
  845.                         break;
  846.  
  847.                 case NSFB_KEY_RIGHT:
  848.                         if (modifier & FBTK_MOD_RCTRL ||
  849.                                         modifier & FBTK_MOD_LCTRL) {
  850.                                 /* CTRL held */
  851.                                 if (browser_window_key_press(gw->bw,
  852.                                                 KEY_LINE_END) == false)
  853.                                         widget_scroll_x(gw, INT_MAX, true);
  854.  
  855.                         } else if (modifier & FBTK_MOD_RSHIFT ||
  856.                                         modifier & FBTK_MOD_LSHIFT) {
  857.                                 /* SHIFT held */
  858.                                 if (browser_window_key_press(gw->bw,
  859.                                                 KEY_WORD_RIGHT) == false)
  860.                                         widget_scroll_x(gw, fbtk_get_width(
  861.                                                 gw->browser), false);
  862.  
  863.                         } else {
  864.                                 /* no modifier */
  865.                                 if (browser_window_key_press(gw->bw,
  866.                                                 KEY_RIGHT) == false)
  867.                                         widget_scroll_x(gw, 100, false);
  868.                         }
  869.                         break;
  870.  
  871.                 case NSFB_KEY_LEFT:
  872.                         if (modifier & FBTK_MOD_RCTRL ||
  873.                                         modifier & FBTK_MOD_LCTRL) {
  874.                                 /* CTRL held */
  875.                                 if (browser_window_key_press(gw->bw,
  876.                                                 KEY_LINE_START) == false)
  877.                                         widget_scroll_x(gw, 0, true);
  878.  
  879.                         } else if (modifier & FBTK_MOD_RSHIFT ||
  880.                                         modifier & FBTK_MOD_LSHIFT) {
  881.                                 /* SHIFT held */
  882.                                 if (browser_window_key_press(gw->bw,
  883.                                                 KEY_WORD_LEFT) == false)
  884.                                         widget_scroll_x(gw, -fbtk_get_width(
  885.                                                 gw->browser), false);
  886.  
  887.                         } else {
  888.                                 /* no modifier */
  889.                                 if (browser_window_key_press(gw->bw,
  890.                                                 KEY_LEFT) == false)
  891.                                         widget_scroll_x(gw, -100, false);
  892.                         }
  893.                         break;
  894.  
  895.                 case NSFB_KEY_UP:
  896.                         if (browser_window_key_press(gw->bw,
  897.                                         KEY_UP) == false)
  898.                                 widget_scroll_y(gw, -100, false);
  899.                         break;
  900.  
  901.                 case NSFB_KEY_DOWN:
  902.                         if (browser_window_key_press(gw->bw,
  903.                                         KEY_DOWN) == false)
  904.                                 widget_scroll_y(gw, 100, false);
  905.                         break;
  906.  
  907.                 case NSFB_KEY_RSHIFT:
  908.                         modifier |= FBTK_MOD_RSHIFT;
  909.                         break;
  910.  
  911.                 case NSFB_KEY_LSHIFT:
  912.                         modifier |= FBTK_MOD_LSHIFT;
  913.                         break;
  914.  
  915.                 case NSFB_KEY_RCTRL:
  916.                         modifier |= FBTK_MOD_RCTRL;
  917.                         break;
  918.  
  919.                 case NSFB_KEY_LCTRL:
  920.                         modifier |= FBTK_MOD_LCTRL;
  921.                         break;
  922.  
  923.                 default:
  924.                         ucs4 = fbtk_keycode_to_ucs4(cbi->event->value.keycode,
  925.                                                     modifier);
  926.                         if (ucs4 != -1)
  927.                                 browser_window_key_press(gw->bw, ucs4);
  928.                         break;
  929.                 }
  930.                 break;
  931.  
  932.         case NSFB_EVENT_KEY_UP:
  933.                 switch (cbi->event->value.keycode) {
  934.                 case NSFB_KEY_RSHIFT:
  935.                         modifier &= ~FBTK_MOD_RSHIFT;
  936.                         break;
  937.  
  938.                 case NSFB_KEY_LSHIFT:
  939.                         modifier &= ~FBTK_MOD_LSHIFT;
  940.                         break;
  941.  
  942.                 case NSFB_KEY_RCTRL:
  943.                         modifier &= ~FBTK_MOD_RCTRL;
  944.                         break;
  945.  
  946.                 case NSFB_KEY_LCTRL:
  947.                         modifier &= ~FBTK_MOD_LCTRL;
  948.                         break;
  949.  
  950.                 default:
  951.                         break;
  952.                 }
  953.                 break;
  954.  
  955.         default:
  956.                 break;
  957.         }
  958.  
  959.         return 0;
  960. }
  961.  
  962. static void
  963. fb_update_back_forward(struct gui_window *gw)
  964. {
  965.         struct browser_window *bw = gw->bw;
  966.  
  967.         fbtk_set_bitmap(gw->back,
  968.                         (browser_window_back_available(bw)) ?
  969.                         &left_arrow : &left_arrow_g);
  970.         fbtk_set_bitmap(gw->forward,
  971.                         (browser_window_forward_available(bw)) ?
  972.                         &right_arrow : &right_arrow_g);
  973. }
  974.  
  975. /* left icon click routine */
  976. static int
  977. fb_leftarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  978. {
  979.         struct gui_window *gw = cbi->context;
  980.         struct browser_window *bw = gw->bw;
  981.  
  982.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  983.                 return 0;
  984.  
  985.         if (history_back_available(bw->history))
  986.                 history_back(bw, bw->history);
  987.  
  988.         fb_update_back_forward(gw);
  989.  
  990.         return 1;
  991. }
  992.  
  993. /* right arrow icon click routine */
  994. static int
  995. fb_rightarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  996. {
  997.         struct gui_window *gw = cbi->context;
  998.         struct browser_window *bw = gw->bw;
  999.  
  1000.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1001.                 return 0;
  1002.  
  1003.         if (history_forward_available(bw->history))
  1004.                 history_forward(bw, bw->history);
  1005.  
  1006.         fb_update_back_forward(gw);
  1007.         return 1;
  1008.  
  1009. }
  1010.  
  1011. /* reload icon click routine */
  1012. static int
  1013. fb_reload_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1014. {
  1015.         struct browser_window *bw = cbi->context;
  1016.  
  1017.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1018.                 return 0;
  1019.  
  1020.         browser_window_reload(bw, true);
  1021.         return 1;
  1022. }
  1023.  
  1024. /* stop icon click routine */
  1025. static int
  1026. fb_stop_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1027. {
  1028.         struct browser_window *bw = cbi->context;
  1029.  
  1030.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1031.                 return 0;
  1032.  
  1033.         browser_window_stop(bw);
  1034.         return 0;
  1035. }
  1036.  
  1037. static int
  1038. fb_osk_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1039. {
  1040.  
  1041.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1042.                 return 0;
  1043.  
  1044.         map_osk();
  1045.  
  1046.         return 0;
  1047. }
  1048.  
  1049. /* close browser window icon click routine */
  1050. static int
  1051. fb_close_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1052. {
  1053.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1054.                 return 0;
  1055.  
  1056.         netsurf_quit = true;
  1057.         return 0;
  1058. }
  1059.  
  1060. static int
  1061. fb_scroll_callback(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1062. {
  1063.         struct gui_window *gw = cbi->context;
  1064.  
  1065.         switch (cbi->type) {
  1066.         case FBTK_CBT_SCROLLY:
  1067.                 widget_scroll_y(gw, cbi->y, true);
  1068.                 break;
  1069.  
  1070.         case FBTK_CBT_SCROLLX:
  1071.                 widget_scroll_x(gw, cbi->x, true);
  1072.                 break;
  1073.  
  1074.         default:
  1075.                 break;
  1076.         }
  1077.         return 0;
  1078. }
  1079.  
  1080. static int
  1081. fb_url_enter(void *pw, char *text)
  1082. {
  1083.         struct browser_window *bw = pw;
  1084.         browser_window_go(bw, text, 0, true);
  1085.         return 0;
  1086. }
  1087.  
  1088. static int
  1089. fb_url_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1090. {
  1091.         framebuffer_set_cursor(&caret_image);
  1092.         return 0;
  1093. }
  1094.  
  1095. static int
  1096. set_ptr_default_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1097. {
  1098.         framebuffer_set_cursor(&pointer_image);
  1099.         return 0;
  1100. }
  1101.  
  1102. static int
  1103. fb_localhistory_btn_clik(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1104. {
  1105.         struct gui_window *gw = cbi->context;
  1106.  
  1107.         if (cbi->event->type != NSFB_EVENT_KEY_UP)
  1108.                 return 0;
  1109.  
  1110.         fb_localhistory_map(gw->localhistory);
  1111.  
  1112.         return 0;
  1113. }
  1114.  
  1115.  
  1116. /** Create a toolbar window and populate it with buttons.
  1117.  *
  1118.  * The toolbar layout uses a character to define buttons type and position:
  1119.  * b - back
  1120.  * l - local history
  1121.  * f - forward
  1122.  * s - stop
  1123.  * r - refresh
  1124.  * u - url bar expands to fit remaining space
  1125.  * t - throbber/activity indicator
  1126.  * c - close the current window
  1127.  *
  1128.  * The default layout is "blfsrut" there should be no more than a
  1129.  * single url bar entry or behaviour will be undefined.
  1130.  *
  1131.  * @param gw Parent window
  1132.  * @param toolbar_height The height in pixels of the toolbar
  1133.  * @param padding The padding in pixels round each element of the toolbar
  1134.  * @param frame_col Frame colour.
  1135.  * @param toolbar_layout A string defining which buttons and controls
  1136.  *                       should be added to the toolbar. May be empty
  1137.  *                       string to disable the bar..
  1138.  *
  1139.  */
  1140. static fbtk_widget_t *
  1141. create_toolbar(struct gui_window *gw,
  1142.                int toolbar_height,
  1143.                int padding,
  1144.                colour frame_col,
  1145.                const char *toolbar_layout)
  1146. {
  1147.         fbtk_widget_t *toolbar;
  1148.         fbtk_widget_t *widget;
  1149.  
  1150.         int xpos; /* The position of the next widget. */
  1151.         int xlhs = 0; /* extent of the left hand side widgets */
  1152.         int xdir = 1; /* the direction of movement + or - 1 */
  1153.         const char *itmtype; /* type of the next item */
  1154.  
  1155.         if (toolbar_layout == NULL) {
  1156.                 toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT;
  1157.         }
  1158.  
  1159.         LOG(("Using toolbar layout %s", toolbar_layout));
  1160.  
  1161.         itmtype = toolbar_layout;
  1162.  
  1163.         if (*itmtype == 0) {
  1164.                 return NULL;
  1165.         }
  1166.  
  1167.         toolbar = fbtk_create_window(gw->window, 0, 0, 0,
  1168.                                      toolbar_height,
  1169.                                      frame_col);
  1170.  
  1171.         if (toolbar == NULL) {
  1172.                 return NULL;
  1173.         }
  1174.  
  1175.         fbtk_set_handler(toolbar,
  1176.                          FBTK_CBT_POINTERENTER,
  1177.                          set_ptr_default_move,
  1178.                          NULL);
  1179.  
  1180.  
  1181.         xpos = padding;
  1182.  
  1183.         /* loop proceeds creating widget on the left hand side until
  1184.          * it runs out of layout or encounters a url bar declaration
  1185.          * wherupon it works backwards from the end of the layout
  1186.          * untill the space left is for the url bar
  1187.          */
  1188.         while ((itmtype >= toolbar_layout) &&
  1189.                (*itmtype != 0) &&
  1190.                (xdir !=0)) {
  1191.  
  1192.                 LOG(("toolbar adding %c", *itmtype));
  1193.  
  1194.  
  1195.                 switch (*itmtype) {
  1196.  
  1197.                 case 'b': /* back */
  1198.                         widget = fbtk_create_button(toolbar,
  1199.                                                     (xdir == 1) ? xpos :
  1200.                                                      xpos - left_arrow.width,
  1201.                                                     padding,
  1202.                                                     left_arrow.width,
  1203.                                                     -padding,
  1204.                                                     frame_col,
  1205.                                                     &left_arrow,
  1206.                                                     fb_leftarrow_click,
  1207.                                                     gw);
  1208.                         gw->back = widget; /* keep reference */
  1209.                         break;
  1210.  
  1211.                 case 'l': /* local history */
  1212.                         widget = fbtk_create_button(toolbar,
  1213.                                                     (xdir == 1) ? xpos :
  1214.                                                      xpos - history_image.width,
  1215.                                                     padding,
  1216.                                                     history_image.width,
  1217.                                                     -padding,
  1218.                                                     frame_col,
  1219.                                                     &history_image,
  1220.                                                     fb_localhistory_btn_clik,
  1221.                                                     gw);
  1222.                         break;
  1223.  
  1224.                 case 'f': /* forward */
  1225.                         widget = fbtk_create_button(toolbar,
  1226.                                                     (xdir == 1)?xpos :
  1227.                                                      xpos - right_arrow.width,
  1228.                                                     padding,
  1229.                                                     right_arrow.width,
  1230.                                                     -padding,
  1231.                                                     frame_col,
  1232.                                                     &right_arrow,
  1233.                                                     fb_rightarrow_click,
  1234.                                                     gw);
  1235.                         gw->forward = widget;
  1236.                         break;
  1237.  
  1238.                 case 'c': /* close the current window */
  1239.                         widget = fbtk_create_button(toolbar,
  1240.                                                     (xdir == 1)?xpos :
  1241.                                                      xpos - stop_image_g.width,
  1242.                                                     padding,
  1243.                                                     stop_image_g.width,
  1244.                                                     -padding,
  1245.                                                     frame_col,
  1246.                                                     &stop_image_g,
  1247.                                                     fb_close_click,
  1248.                                                     gw->bw);
  1249.                         break;
  1250.  
  1251.                 case 's': /* stop  */
  1252.                         widget = fbtk_create_button(toolbar,
  1253.                                                     (xdir == 1)?xpos :
  1254.                                                      xpos - stop_image.width,
  1255.                                                     padding,
  1256.                                                     stop_image.width,
  1257.                                                     -padding,
  1258.                                                     frame_col,
  1259.                                                     &stop_image,
  1260.                                                     fb_stop_click,
  1261.                                                     gw->bw);
  1262.                         break;
  1263.  
  1264.                 case 'r': /* reload */
  1265.                         widget = fbtk_create_button(toolbar,
  1266.                                                     (xdir == 1)?xpos :
  1267.                                                      xpos - reload.width,
  1268.                                                     padding,
  1269.                                                     reload.width,
  1270.                                                     -padding,
  1271.                                                     frame_col,
  1272.                                                     &reload,
  1273.                                                     fb_reload_click,
  1274.                                                     gw->bw);
  1275.                         break;
  1276.  
  1277.                 case 't': /* throbber/activity indicator */
  1278.                         widget = fbtk_create_bitmap(toolbar,
  1279.                                                     (xdir == 1)?xpos :
  1280.                                                      xpos - throbber0.width,
  1281.                                                     padding,
  1282.                                                     throbber0.width,
  1283.                                                     -padding,
  1284.                                                     frame_col,
  1285.                                                     &throbber0);
  1286.                         gw->throbber = widget;
  1287.                         break;
  1288.  
  1289.  
  1290.                 case 'u': /* url bar*/
  1291.                         if (xdir == -1) {
  1292.                                 /* met the u going backwards add url
  1293.                                  * now we know available extent
  1294.                                  */
  1295.  
  1296.                                 widget = fbtk_create_writable_text(toolbar,
  1297.                                                    xlhs,
  1298.                                                    padding,
  1299.                                                    xpos - xlhs,
  1300.                                                    -padding,
  1301.                                                    FB_COLOUR_WHITE,
  1302.                                                    FB_COLOUR_BLACK,
  1303.                                                    true,
  1304.                                                    fb_url_enter,
  1305.                                                    gw->bw);
  1306.  
  1307.                                 fbtk_set_handler(widget,
  1308.                                                  FBTK_CBT_POINTERENTER,
  1309.                                                  fb_url_move, gw->bw);
  1310.  
  1311.                                 gw->url = widget; /* keep reference */
  1312.  
  1313.                                 /* toolbar is complete */
  1314.                                 xdir = 0;
  1315.                                 break;
  1316.                         }
  1317.                         /* met url going forwards, note position and
  1318.                          * reverse direction
  1319.                          */
  1320.                         itmtype = toolbar_layout + strlen(toolbar_layout);
  1321.                         xdir = -1;
  1322.                         xlhs = xpos;
  1323.                         xpos = (2 * fbtk_get_width(toolbar));
  1324.                         widget = toolbar;
  1325.                         break;
  1326.  
  1327.                 default:
  1328.                         widget = NULL;
  1329.                         xdir = 0;
  1330.                         LOG(("Unknown element %c in toolbar layout", *itmtype));
  1331.                         break;
  1332.  
  1333.                 }
  1334.  
  1335.                 if (widget != NULL) {
  1336.                         xpos += (xdir * (fbtk_get_width(widget) + padding));
  1337.                 }
  1338.  
  1339.                 LOG(("xpos is %d",xpos));
  1340.  
  1341.                 itmtype += xdir;
  1342.         }
  1343.  
  1344.         fbtk_set_mapping(toolbar, true);
  1345.  
  1346.         return toolbar;
  1347. }
  1348.  
  1349. /** Routine called when "stripped of focus" event occours for browser widget.
  1350.  *
  1351.  * @param widget The widget reciving "stripped of focus" event.
  1352.  * @param cbi The callback parameters.
  1353.  * @return The callback result.
  1354.  */
  1355. static int
  1356. fb_browser_window_strip_focus(fbtk_widget_t *widget, fbtk_callback_info *cbi)
  1357. {
  1358.         fbtk_set_caret(widget, false, 0, 0, 0, NULL);
  1359.  
  1360.         return 0;
  1361. }
  1362.  
  1363. static void
  1364. create_browser_widget(struct gui_window *gw, int toolbar_height, int furniture_width)
  1365. {
  1366.         struct browser_widget_s *browser_widget;
  1367.         browser_widget = calloc(1, sizeof(struct browser_widget_s));
  1368.  
  1369.         gw->browser = fbtk_create_user(gw->window,
  1370.                                        0,
  1371.                                        toolbar_height,
  1372.                                        -furniture_width,
  1373.                                        -furniture_width,
  1374.                                        browser_widget);
  1375.  
  1376.         fbtk_set_handler(gw->browser, FBTK_CBT_REDRAW, fb_browser_window_redraw, gw);
  1377.         fbtk_set_handler(gw->browser, FBTK_CBT_INPUT, fb_browser_window_input, gw);
  1378.         fbtk_set_handler(gw->browser, FBTK_CBT_CLICK, fb_browser_window_click, gw);
  1379.         fbtk_set_handler(gw->browser, FBTK_CBT_STRIP_FOCUS, fb_browser_window_strip_focus, gw);
  1380.         fbtk_set_handler(gw->browser, FBTK_CBT_POINTERMOVE, fb_browser_window_move, gw);
  1381. }
  1382.  
  1383. static void
  1384. create_normal_browser_window(struct gui_window *gw, int furniture_width)
  1385. {
  1386.         LOG(("enter norm win"));
  1387.         fbtk_widget_t *widget;
  1388.         fbtk_widget_t *toolbar;
  1389.         int statusbar_width = 0;
  1390.         int toolbar_height = 30; //nsoption_int(fb_toolbar_size);
  1391.  
  1392.         LOG(("Normal window"));
  1393.  
  1394.         gw->window = fbtk_create_window(fbtk, 0, 0, 0, 0, 0);
  1395.  
  1396.         statusbar_width = nsoption_int(toolbar_status_width) *
  1397.                 fbtk_get_width(gw->window) / 10000;
  1398.  
  1399. LOG(("STUB options"));
  1400.  
  1401.                  
  1402.                          
  1403.         nsoptions.fb_depth = 16;                                       
  1404.         nsoptions.fb_refresh = 70;                             
  1405.         nsoptions.fb_device = NULL;                            
  1406.         nsoptions.fb_input_devpath = NULL;                     
  1407.         nsoptions.fb_input_glob = NULL;                        
  1408.         nsoptions.fb_furniture_size = 18;                      
  1409.         nsoptions.fb_toolbar_size = 30;                        
  1410.         nsoptions.fb_toolbar_layout = NULL;                            
  1411.         nsoptions.fb_osk = false;                              
  1412.  
  1413.  
  1414.  
  1415.         /* toolbar */
  1416.         LOG(("toolbar"));
  1417.        
  1418.        
  1419.        
  1420.         toolbar = create_toolbar(gw,
  1421.                                  toolbar_height,
  1422.                                  2,
  1423.                                  FB_FRAME_COLOUR,
  1424.                                  nsoption_charp(fb_toolbar_layout));
  1425.  
  1426.         /* set the actually created toolbar height */
  1427.         if (toolbar != NULL) {
  1428.                 toolbar_height = fbtk_get_height(toolbar);
  1429.         } else {
  1430.                 toolbar_height = 0;
  1431.         }
  1432.  
  1433.         LOG(("statbar"));
  1434.         /* status bar */
  1435.         gw->status = fbtk_create_text(gw->window,
  1436.                                       0,
  1437.                                       fbtk_get_height(gw->window) - furniture_width,
  1438.                                       statusbar_width, furniture_width,
  1439.                                       FB_FRAME_COLOUR, FB_COLOUR_BLACK,
  1440.                                       false);
  1441.        
  1442.         LOG(("handler"));
  1443.         fbtk_set_handler(gw->status, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
  1444.  
  1445.         LOG(("status bar %p at %d,%d", gw->status, fbtk_get_absx(gw->status), fbtk_get_absy(gw->status)));
  1446.  
  1447.         /* create horizontal scrollbar */
  1448.         LOG(("hor sb"));
  1449.        
  1450.         gw->hscroll = fbtk_create_hscroll(gw->window,
  1451.                                           statusbar_width,
  1452.                                           fbtk_get_height(gw->window) - furniture_width,
  1453.                                           fbtk_get_width(gw->window) - statusbar_width - furniture_width,
  1454.                                           furniture_width,
  1455.                                           FB_SCROLL_COLOUR,
  1456.                                           FB_FRAME_COLOUR,
  1457.                                           fb_scroll_callback,
  1458.                                           gw);
  1459.  
  1460.         /* fill bottom right area */
  1461.         LOG(("fill bottom"));
  1462.  
  1463.         if (nsoption_bool(fb_osk) == true) {
  1464.                 widget = fbtk_create_text_button(gw->window,
  1465.                                                  fbtk_get_width(gw->window) - furniture_width,
  1466.                                                  fbtk_get_height(gw->window) - furniture_width,
  1467.                                                  furniture_width,
  1468.                                                  furniture_width,
  1469.                                                  FB_FRAME_COLOUR, FB_COLOUR_BLACK,
  1470.                                                  fb_osk_click,
  1471.                                                  NULL);
  1472.                 widget = fbtk_create_button(gw->window,
  1473.                                 fbtk_get_width(gw->window) - furniture_width,
  1474.                                 fbtk_get_height(gw->window) - furniture_width,
  1475.                                 furniture_width,
  1476.                                 furniture_width,
  1477.                                 FB_FRAME_COLOUR,
  1478.                                 &osk_image,
  1479.                                 fb_osk_click,
  1480.                                 NULL);
  1481.         } else {
  1482.                 widget = fbtk_create_fill(gw->window,
  1483.                                           fbtk_get_width(gw->window) - furniture_width,
  1484.                                           fbtk_get_height(gw->window) - furniture_width,
  1485.                                           furniture_width,
  1486.                                           furniture_width,
  1487.                                           FB_FRAME_COLOUR);
  1488.  
  1489.                 fbtk_set_handler(widget, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
  1490.         }
  1491.  
  1492.         LOG(("vsb GUI"));
  1493.         /* create vertical scrollbar */
  1494.         gw->vscroll = fbtk_create_vscroll(gw->window,
  1495.                                           fbtk_get_width(gw->window) - furniture_width,
  1496.                                           toolbar_height,
  1497.                                           furniture_width,
  1498.                                           fbtk_get_height(gw->window) - toolbar_height - furniture_width,
  1499.                                           FB_SCROLL_COLOUR,
  1500.                                           FB_FRAME_COLOUR,
  1501.                                           fb_scroll_callback,
  1502.                                           gw);
  1503.  
  1504.         LOG(("BRO widget"));
  1505.         /* browser widget */
  1506.         create_browser_widget(gw, toolbar_height, nsoption_int(fb_furniture_size));
  1507.  
  1508.         LOG(("set focus"));
  1509.         /* Give browser_window's user widget input focus */
  1510.         fbtk_set_focus(gw->browser);
  1511.         LOG(("GUI OK"));
  1512. }
  1513.  
  1514.  
  1515. struct gui_window *
  1516. gui_create_browser_window(struct browser_window *bw,
  1517.                           struct browser_window *clone,
  1518.                           bool new_tab)
  1519. {
  1520.         struct gui_window *gw;
  1521.         LOG(("GCBW calloc"));
  1522.        
  1523.         gw = calloc(1, sizeof(struct gui_window));
  1524.  
  1525.         if (gw == NULL)
  1526.                 return NULL;
  1527.  
  1528.         /* seems we need to associate the gui window with the underlying
  1529.          * browser window
  1530.          */
  1531.         LOG(("GCBW next.."));
  1532.        
  1533.        
  1534.         gw->bw = bw;
  1535.  
  1536.         LOG(("fb_furn_size is STUB now!..."));
  1537.        
  1538.          //nsoption_int(fb_furniture_size);
  1539.         LOG(("GCBW create normal window..."));
  1540.        
  1541.        
  1542.         create_normal_browser_window(gw, 18); //nsoption_int(fb_furniture_size));
  1543.         LOG(("GCBW create local history..."));
  1544.        
  1545.         gw->localhistory = fb_create_localhistory(bw, fbtk, nsoption_int(fb_furniture_size));
  1546.  
  1547.         /* map and request redraw of gui window */
  1548.         LOG(("GCBW set mapping"));
  1549.        
  1550.         fbtk_set_mapping(gw->window, true);
  1551.         LOG(("GCBW OK!"));
  1552.        
  1553.  
  1554.         return gw;
  1555. }
  1556.  
  1557. void
  1558. gui_window_destroy(struct gui_window *gw)
  1559. {
  1560.         fbtk_destroy_widget(gw->window);
  1561.  
  1562.         free(gw);
  1563.  
  1564.  
  1565. }
  1566.  
  1567. void
  1568. gui_window_set_title(struct gui_window *g, const char *title)
  1569. {
  1570.         LOG(("%p, %s", g, title));
  1571. }
  1572.  
  1573. void
  1574. gui_window_redraw_window(struct gui_window *g)
  1575. {
  1576.         fb_queue_redraw(g->browser, 0, 0, fbtk_get_width(g->browser), fbtk_get_height(g->browser) );
  1577. }
  1578.  
  1579. void
  1580. gui_window_update_box(struct gui_window *g, const struct rect *rect)
  1581. {
  1582.         struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
  1583.         fb_queue_redraw(g->browser,
  1584.                         rect->x0 - bwidget->scrollx,
  1585.                         rect->y0 - bwidget->scrolly,
  1586.                         rect->x1 - bwidget->scrollx,
  1587.                         rect->y1 - bwidget->scrolly);
  1588. }
  1589.  
  1590. bool
  1591. gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
  1592. {
  1593.         struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
  1594.  
  1595.         *sx = bwidget->scrollx / g->bw->scale;
  1596.         *sy = bwidget->scrolly / g->bw->scale;
  1597.  
  1598.         return true;
  1599. }
  1600.  
  1601. void
  1602. gui_window_set_scroll(struct gui_window *gw, int sx, int sy)
  1603. {
  1604.         struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
  1605.  
  1606.         assert(bwidget);
  1607.  
  1608.         widget_scroll_x(gw, sx * gw->bw->scale, true);
  1609.         widget_scroll_y(gw, sy * gw->bw->scale, true);
  1610. }
  1611.  
  1612. void
  1613. gui_window_scroll_visible(struct gui_window *g, int x0, int y0,
  1614.                           int x1, int y1)
  1615. {
  1616.         LOG(("%s:(%p, %d, %d, %d, %d)", __func__, g, x0, y0, x1, y1));
  1617. }
  1618.  
  1619. void
  1620. gui_window_get_dimensions(struct gui_window *g,
  1621.                           int *width,
  1622.                           int *height,
  1623.                           bool scaled)
  1624. {
  1625.         *width = fbtk_get_width(g->browser);
  1626.         *height = fbtk_get_height(g->browser);
  1627.  
  1628.         if (scaled) {
  1629.                 *width /= g->bw->scale;
  1630.                 *height /= g->bw->scale;
  1631.         }
  1632. }
  1633.  
  1634. void
  1635. gui_window_update_extent(struct gui_window *gw)
  1636. {
  1637.         float scale = gw->bw->scale;
  1638.  
  1639.         fbtk_set_scroll_parameters(gw->hscroll, 0,
  1640.                         content_get_width(gw->bw->current_content) * scale,
  1641.                         fbtk_get_width(gw->browser), 100);
  1642.  
  1643.         fbtk_set_scroll_parameters(gw->vscroll, 0,
  1644.                         content_get_height(gw->bw->current_content) * scale,
  1645.                         fbtk_get_height(gw->browser), 100);
  1646. }
  1647.  
  1648. void
  1649. gui_window_set_status(struct gui_window *g, const char *text)
  1650. {
  1651.         fbtk_set_text(g->status, text);
  1652. }
  1653.  
  1654. void
  1655. gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
  1656. {
  1657.         switch (shape) {
  1658.         case GUI_POINTER_POINT:
  1659.                 framebuffer_set_cursor(&hand_image);
  1660.                 break;
  1661.  
  1662.         case GUI_POINTER_CARET:
  1663.                 framebuffer_set_cursor(&caret_image);
  1664.                 break;
  1665.  
  1666.         case GUI_POINTER_MENU:
  1667.                 framebuffer_set_cursor(&menu_image);
  1668.                 break;
  1669.  
  1670.         case GUI_POINTER_PROGRESS:
  1671.                 framebuffer_set_cursor(&progress_image);
  1672.                 break;
  1673.  
  1674.         case GUI_POINTER_MOVE:
  1675.                 framebuffer_set_cursor(&move_image);
  1676.                 break;
  1677.  
  1678.         default:
  1679.                 framebuffer_set_cursor(&pointer_image);
  1680.                 break;
  1681.         }
  1682. }
  1683.  
  1684. void
  1685. gui_window_hide_pointer(struct gui_window *g)
  1686. {
  1687. }
  1688.  
  1689. void
  1690. gui_window_set_url(struct gui_window *g, const char *url)
  1691. {
  1692.         fbtk_set_text(g->url, url);
  1693. }
  1694.  
  1695. static void
  1696. throbber_advance(void *pw)
  1697. {
  1698.         struct gui_window *g = pw;
  1699.         struct fbtk_bitmap *image;
  1700.  
  1701.         switch (g->throbber_index) {
  1702.         case 0:
  1703.                 image = &throbber1;
  1704.                 g->throbber_index = 1;
  1705.                 break;
  1706.  
  1707.         case 1:
  1708.                 image = &throbber2;
  1709.                 g->throbber_index = 2;
  1710.                 break;
  1711.  
  1712.         case 2:
  1713.                 image = &throbber3;
  1714.                 g->throbber_index = 3;
  1715.                 break;
  1716.  
  1717.         case 3:
  1718.                 image = &throbber4;
  1719.                 g->throbber_index = 4;
  1720.                 break;
  1721.  
  1722.         case 4:
  1723.                 image = &throbber5;
  1724.                 g->throbber_index = 5;
  1725.                 break;
  1726.  
  1727.         case 5:
  1728.                 image = &throbber6;
  1729.                 g->throbber_index = 6;
  1730.                 break;
  1731.  
  1732.         case 6:
  1733.                 image = &throbber7;
  1734.                 g->throbber_index = 7;
  1735.                 break;
  1736.  
  1737.         case 7:
  1738.                 image = &throbber8;
  1739.                 g->throbber_index = 0;
  1740.                 break;
  1741.  
  1742.         default:
  1743.                 return;
  1744.         }
  1745.  
  1746.         if (g->throbber_index >= 0) {
  1747.                 fbtk_set_bitmap(g->throbber, image);
  1748.                 schedule(10, throbber_advance, g);
  1749.         }
  1750. }
  1751.  
  1752. void
  1753. gui_window_start_throbber(struct gui_window *g)
  1754. {
  1755.         g->throbber_index = 0;
  1756.         schedule(10, throbber_advance, g);
  1757. }
  1758.  
  1759. void
  1760. gui_window_stop_throbber(struct gui_window *gw)
  1761. {
  1762.         gw->throbber_index = -1;
  1763.         fbtk_set_bitmap(gw->throbber, &throbber0);
  1764.  
  1765.         fb_update_back_forward(gw);
  1766.  
  1767. }
  1768.  
  1769. static void
  1770. gui_window_remove_caret_cb(fbtk_widget_t *widget)
  1771. {
  1772.         struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
  1773.         int c_x, c_y, c_h;
  1774.  
  1775.         if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
  1776.                 /* browser window already had caret:
  1777.                  * redraw its area to remove it first */
  1778.                 fb_queue_redraw(widget,
  1779.                                 c_x - bwidget->scrollx,
  1780.                                 c_y - bwidget->scrolly,
  1781.                                 c_x + 1 - bwidget->scrollx,
  1782.                                 c_y + c_h - bwidget->scrolly);
  1783.         }
  1784. }
  1785.  
  1786. void
  1787. gui_window_place_caret(struct gui_window *g, int x, int y, int height)
  1788. {
  1789.         struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
  1790.  
  1791.         /* set new pos */
  1792.         fbtk_set_caret(g->browser, true, x, y, height,
  1793.                         gui_window_remove_caret_cb);
  1794.  
  1795.         /* redraw new caret pos */
  1796.         fb_queue_redraw(g->browser,
  1797.                         x - bwidget->scrollx,
  1798.                         y - bwidget->scrolly,
  1799.                         x + 1 - bwidget->scrollx,
  1800.                         y + height - bwidget->scrolly);
  1801. }
  1802.  
  1803. void
  1804. gui_window_remove_caret(struct gui_window *g)
  1805. {
  1806.         int c_x, c_y, c_h;
  1807.  
  1808.         if (fbtk_get_caret(g->browser, &c_x, &c_y, &c_h)) {
  1809.                 /* browser window owns the caret, so can remove it */
  1810.                 fbtk_set_caret(g->browser, false, 0, 0, 0, NULL);
  1811.         }
  1812. }
  1813.  
  1814. void
  1815. gui_window_new_content(struct gui_window *g)
  1816. {
  1817. }
  1818.  
  1819. bool
  1820. gui_window_scroll_start(struct gui_window *g)
  1821. {
  1822.         return true;
  1823. }
  1824.  
  1825. bool
  1826. gui_window_drag_start(struct gui_window *g, gui_drag_type type,
  1827.                       const struct rect *rect)
  1828. {
  1829.         return true;
  1830. }
  1831.  
  1832. void
  1833. gui_window_save_link(struct gui_window *g, const char *url, const char *title)
  1834. {
  1835. }
  1836.  
  1837. /**
  1838.  * set favicon
  1839.  */
  1840. void
  1841. gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
  1842. {
  1843. }
  1844.  
  1845. /**
  1846.  * set gui display of a retrieved favicon representing the search provider
  1847.  * \param ico may be NULL for local calls; then access current cache from
  1848.  * search_web_ico()
  1849.  */
  1850. void
  1851. gui_window_set_search_ico(hlcache_handle *ico)
  1852. {
  1853. }
  1854.  
  1855. struct gui_download_window *
  1856. gui_download_window_create(download_context *ctx, struct gui_window *parent)
  1857. {
  1858.         return NULL;
  1859. }
  1860.  
  1861. nserror
  1862. gui_download_window_data(struct gui_download_window *dw,
  1863.                          const char *data,
  1864.                          unsigned int size)
  1865. {
  1866.         return NSERROR_OK;
  1867. }
  1868.  
  1869. void
  1870. gui_download_window_error(struct gui_download_window *dw,
  1871.                           const char *error_msg)
  1872. {
  1873. }
  1874.  
  1875. void
  1876. gui_download_window_done(struct gui_download_window *dw)
  1877. {
  1878. }
  1879.  
  1880. void
  1881. gui_drag_save_object(gui_save_type type,
  1882.                      hlcache_handle *c,
  1883.                      struct gui_window *w)
  1884. {
  1885. }
  1886.  
  1887. void
  1888. gui_drag_save_selection(struct selection *s, struct gui_window *g)
  1889. {
  1890. }
  1891.  
  1892. void
  1893. gui_start_selection(struct gui_window *g)
  1894. {
  1895. }
  1896.  
  1897. void
  1898. gui_clear_selection(struct gui_window *g)
  1899. {
  1900. }
  1901.  
  1902. void
  1903. gui_create_form_select_menu(struct browser_window *bw,
  1904.                             struct form_control *control)
  1905. {
  1906. }
  1907.  
  1908. void
  1909. gui_launch_url(const char *url)
  1910. {
  1911. }
  1912.  
  1913. void
  1914. gui_cert_verify(nsurl *url,
  1915.                 const struct ssl_cert_info *certs,
  1916.                 unsigned long num,
  1917.                 nserror (*cb)(bool proceed, void *pw),
  1918.                 void *cbpw)
  1919. {
  1920.         cb(false, cbpw);
  1921. }
  1922.  
  1923. /*
  1924.  * Local Variables:
  1925.  * c-basic-offset:8
  1926.  * End:
  1927.  */
  1928.