/* queue a window scroll */ static void widget_scroll_x(struct gui_window *gw, int x, bool abs) { struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser); int content_width; int width; float scale = gw->bw->scale; if (abs) { bwidget->panx = x - bwidget->scrollx; } else { bwidget->panx += x; } content_width = content_get_width(gw->bw->current_content) * scale; width = fbtk_get_width(gw->browser); /* dont pan off the left */ if ((bwidget->scrollx + bwidget->panx) < 0) bwidget->panx = - bwidget->scrollx; /* do not pan off the right of the content */ if ((bwidget->scrollx + bwidget->panx) > (content_width - width)) bwidget->panx = (content_width - width) - bwidget->scrollx; if (bwidget->panx == 0) return; bwidget->pan_required = true; fbtk_request_redraw(gw->browser); fbtk_set_scroll_position(gw->hscroll, bwidget->scrollx + bwidget->panx); }
static void gui_window_update_box(struct gui_window *g, const struct rect *rect) { struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser); fb_queue_redraw(g->browser, rect->x0 - bwidget->scrollx, rect->y0 - bwidget->scrolly, rect->x1 - bwidget->scrollx, rect->y1 - bwidget->scrolly); }
void gui_window_set_scroll(struct gui_window *gw, int sx, int sy) { struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser); assert(bwidget); widget_scroll_x(gw, sx * gw->bw->scale, true); widget_scroll_y(gw, sy * gw->bw->scale, true); }
bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) { struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser); *sx = bwidget->scrollx / g->bw->scale; *sy = bwidget->scrolly / g->bw->scale; return true; }
static void gui_window_remove_caret_cb(fbtk_widget_t *widget) { struct browser_widget_s *bwidget = fbtk_get_userpw(widget); int c_x, c_y, c_h; if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) { /* browser window already had caret: * redraw its area to remove it first */ fb_queue_redraw(widget, c_x - bwidget->scrollx, c_y - bwidget->scrolly, c_x + 1 - bwidget->scrollx, c_y + c_h - bwidget->scrolly); } }
void gui_window_place_caret(struct gui_window *g, int x, int y, int height) { struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser); /* set new pos */ fbtk_set_caret(g->browser, true, x, y, height, gui_window_remove_caret_cb); /* redraw new caret pos */ fb_queue_redraw(g->browser, x - bwidget->scrollx, y - bwidget->scrolly, x + 1 - bwidget->scrollx, y + height - bwidget->scrolly); }
/* queue a redraw operation, co-ordinates are relative to the window */ static void fb_queue_redraw(struct fbtk_widget_s *widget, int x0, int y0, int x1, int y1) { struct browser_widget_s *bwidget = fbtk_get_userpw(widget); bwidget->redraw_box.x0 = min(bwidget->redraw_box.x0, x0); bwidget->redraw_box.y0 = min(bwidget->redraw_box.y0, y0); bwidget->redraw_box.x1 = max(bwidget->redraw_box.x1, x1); bwidget->redraw_box.y1 = max(bwidget->redraw_box.y1, y1); if (fbtk_clip_to_widget(widget, &bwidget->redraw_box)) { bwidget->redraw_required = true; fbtk_request_redraw(widget); } else { bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX; bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = -(INT_MAX); bwidget->redraw_required = false; } }
/* called back when movement in browser window */ static int fb_browser_window_move(fbtk_widget_t *widget, fbtk_callback_info *cbi) { browser_mouse_state mouse = 0; struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget = fbtk_get_userpw(widget); float scale = browser_window_get_scale(gw->bw); int x = (cbi->x + bwidget->scrollx) / scale; int y = (cbi->y + bwidget->scrolly) / scale; if (gui_drag.state == GUI_DRAG_PRESSED && (abs(x - gui_drag.x) > 5 || abs(y - gui_drag.y) > 5)) { /* Drag started */ if (gui_drag.button == 1) { browser_window_mouse_click(gw->bw, BROWSER_MOUSE_DRAG_1, gui_drag.x, gui_drag.y); } else { browser_window_mouse_click(gw->bw, BROWSER_MOUSE_DRAG_2, gui_drag.x, gui_drag.y); } gui_drag.grabbed_pointer = fbtk_tgrab_pointer(widget); gui_drag.state = GUI_DRAG_DRAG; } if (gui_drag.state == GUI_DRAG_DRAG) { /* set up mouse state */ mouse |= BROWSER_MOUSE_DRAG_ON; if (gui_drag.button == 1) mouse |= BROWSER_MOUSE_HOLDING_1; else mouse |= BROWSER_MOUSE_HOLDING_2; } browser_window_mouse_track(gw->bw, mouse, x, y); return 0; }
/* queue a window scroll */ static void widget_scroll_y(struct gui_window *gw, int y, bool abs) { struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser); int content_width, content_height; int height; LOG(("window scroll")); if (abs) { bwidget->pany = y - bwidget->scrolly; } else { bwidget->pany += y; } browser_window_get_extents(gw->bw, true, &content_width, &content_height); height = fbtk_get_height(gw->browser); /* dont pan off the top */ if ((bwidget->scrolly + bwidget->pany) < 0) bwidget->pany = -bwidget->scrolly; /* do not pan off the bottom of the content */ if ((bwidget->scrolly + bwidget->pany) > (content_height - height)) bwidget->pany = (content_height - height) - bwidget->scrolly; if (bwidget->pany == 0) { return; } bwidget->pan_required = true; fbtk_request_redraw(gw->browser); fbtk_set_scroll_position(gw->vscroll, bwidget->scrolly + bwidget->pany); }
/* queue a window scroll */ static void widget_scroll_x(struct gui_window *gw, int x, bool abs) { struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser); int content_width, content_height; int width; if (abs) { bwidget->panx = x - bwidget->scrollx; } else { bwidget->panx += x; } browser_window_get_extents(gw->bw, true, &content_width, &content_height); width = fbtk_get_width(gw->browser); /* dont pan off the left */ if ((bwidget->scrollx + bwidget->panx) < 0) bwidget->panx = - bwidget->scrollx; /* do not pan off the right of the content */ if ((bwidget->scrollx + bwidget->panx) > (content_width - width)) bwidget->panx = (content_width - width) - bwidget->scrollx; if (bwidget->panx == 0) { return; } bwidget->pan_required = true; fbtk_request_redraw(gw->browser); fbtk_set_scroll_position(gw->hscroll, bwidget->scrollx + bwidget->panx); }
/* called back when click in browser window */ static int fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget = fbtk_get_userpw(widget); browser_mouse_state mouse; float scale = browser_window_get_scale(gw->bw); int x = (cbi->x + bwidget->scrollx) / scale; int y = (cbi->y + bwidget->scrolly) / scale; unsigned int time_now; static struct { enum { CLICK_SINGLE, CLICK_DOUBLE, CLICK_TRIPLE } type; unsigned int time; } last_click; if (cbi->event->type != NSFB_EVENT_KEY_DOWN && cbi->event->type != NSFB_EVENT_KEY_UP) return 0; LOG(("browser window clicked at %d,%d", cbi->x, cbi->y)); switch (cbi->event->type) { case NSFB_EVENT_KEY_DOWN: switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_1, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 1; gui_drag.x = x; gui_drag.y = y; break; #if 0 case NSFB_KEY_MOUSE_3: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_2, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 2; gui_drag.x = x; gui_drag.y = y; break; #else case NSFB_KEY_MOUSE_2: /* scroll right */ if (browser_window_scroll_at_point(gw->bw, x, y, 100, 0) == false) widget_scroll_x(gw, 100, false); break; case NSFB_KEY_MOUSE_3: /* scroll left */ if (browser_window_scroll_at_point(gw->bw, x, y, -100, 0) == false) widget_scroll_x(gw, -100, false); break; #endif case NSFB_KEY_MOUSE_4: /* scroll up */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, -100) == false) { widget_scroll_y(gw, -100, false); } break; case NSFB_KEY_MOUSE_5: /* scroll down */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, 100) == false) { widget_scroll_y(gw, 100, false); } break; default: break; } break; case NSFB_EVENT_KEY_UP: mouse = 0; time_now = wallclock(); switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } gui_drag.state = GUI_DRAG_NONE; /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; mouse = BROWSER_MOUSE_CLICK_1; break; #if 0 case NSFB_KEY_MOUSE_3: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ gui_drag.state = GUI_DRAG_NONE; if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; mouse = BROWSER_MOUSE_CLICK_2; break; #endif default: break; } /* Determine if it's a double or triple click, allowing * 0.5 seconds (50cs) between clicks */ if (time_now < last_click.time + 50 && cbi->event->value.keycode != NSFB_KEY_MOUSE_4 && cbi->event->value.keycode != NSFB_KEY_MOUSE_5) { if (last_click.type == CLICK_SINGLE) { /* Set double click */ mouse |= BROWSER_MOUSE_DOUBLE_CLICK; last_click.type = CLICK_DOUBLE; } else if (last_click.type == CLICK_DOUBLE) { /* Set triple click */ mouse |= BROWSER_MOUSE_TRIPLE_CLICK; last_click.type = CLICK_TRIPLE; } else { /* Set normal click */ last_click.type = CLICK_SINGLE; } } else { last_click.type = CLICK_SINGLE; } if (mouse) browser_window_mouse_click(gw->bw, mouse, x, y); last_click.time = time_now; break; default: break; } return 1; }
static void fb_redraw(fbtk_widget_t *widget, struct browser_widget_s *bwidget, struct browser_window *bw) { int x; int y; int caret_x, caret_y, caret_h; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &fb_plotters }; nsfb_t *nsfb = fbtk_get_nsfb(widget); float scale = browser_window_get_scale(bw); LOG(("%d,%d to %d,%d", bwidget->redraw_box.x0, bwidget->redraw_box.y0, bwidget->redraw_box.x1, bwidget->redraw_box.y1)); x = fbtk_get_absx(widget); y = fbtk_get_absy(widget); /* adjust clipping co-ordinates according to window location */ bwidget->redraw_box.y0 += y; bwidget->redraw_box.y1 += y; bwidget->redraw_box.x0 += x; bwidget->redraw_box.x1 += x; nsfb_claim(nsfb, &bwidget->redraw_box); /* redraw bounding box is relative to window */ clip.x0 = bwidget->redraw_box.x0; clip.y0 = bwidget->redraw_box.y0; clip.x1 = bwidget->redraw_box.x1; clip.y1 = bwidget->redraw_box.y1; browser_window_redraw(bw, (x - bwidget->scrollx) / scale, (y - bwidget->scrolly) / scale, &clip, &ctx); if (fbtk_get_caret(widget, &caret_x, &caret_y, &caret_h)) { /* This widget has caret, so render it */ nsfb_bbox_t line; nsfb_plot_pen_t pen; line.x0 = x - bwidget->scrollx + caret_x; line.y0 = y - bwidget->scrolly + caret_y; line.x1 = x - bwidget->scrollx + caret_x; line.y1 = y - bwidget->scrolly + caret_y + caret_h; pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID; pen.stroke_width = 1; pen.stroke_colour = 0xFF0000FF; nsfb_plot_line(nsfb, &line, &pen); } nsfb_update(fbtk_get_nsfb(widget), &bwidget->redraw_box); bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX; bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = INT_MIN; bwidget->redraw_required = false; } static int fb_browser_window_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget; bwidget = fbtk_get_userpw(widget); if (bwidget == NULL) { LOG(("browser widget from widget %p was null", widget)); return -1; } if (bwidget->pan_required) { fb_pan(widget, bwidget, gw->bw); } if (bwidget->redraw_required) { fb_redraw(widget, bwidget, gw->bw); } else { bwidget->redraw_box.x0 = 0; bwidget->redraw_box.y0 = 0; bwidget->redraw_box.x1 = fbtk_get_width(widget); bwidget->redraw_box.y1 = fbtk_get_height(widget); fb_redraw(widget, bwidget, gw->bw); } return 0; } static int fb_browser_window_destroy(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct browser_widget_s *browser_widget; if (widget == NULL) { return 0; } /* Free private data */ browser_widget = fbtk_get_userpw(widget); free(browser_widget); return 0; } static const char *fename; static int febpp; static int fewidth; static int feheight; static const char *feurl; static bool process_cmdline(int argc, char** argv) { int opt; LOG(("argc %d, argv %p", argc, argv)); fename = "mtl"; febpp = 32; fewidth = nsoption_int(window_width); if (fewidth <= 0) { fewidth = 800; } feheight = nsoption_int(window_height); if (feheight <= 0) { feheight = 480; } if ((nsoption_charp(homepage_url) != NULL) && (nsoption_charp(homepage_url)[0] != '\0')) { feurl = nsoption_charp(homepage_url); } else { feurl = NETSURF_HOMEPAGE; } while((opt = getopt(argc, argv, "f:b:w:h:")) != -1) { switch (opt) { case 'f': fename = optarg; break; case 'b': febpp = atoi(optarg); break; case 'w': fewidth = atoi(optarg); break; case 'h': feheight = atoi(optarg); break; default: fprintf(stderr, "Usage: %s [-f frontend] [-b bpp] url\n", argv[0]); return false; } } if (optind < argc) { feurl = argv[optind]; } return true; }
/* called back when click in browser window */ static int fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget = fbtk_get_userpw(widget); float scale = gw->bw->scale; int x = (cbi->x + bwidget->scrollx) / scale; int y = (cbi->y + bwidget->scrolly) / scale; if (cbi->event->type != NSFB_EVENT_KEY_DOWN && cbi->event->type != NSFB_EVENT_KEY_UP) return 0; LOG(("browser window clicked at %d,%d", cbi->x, cbi->y)); switch (cbi->event->type) { case NSFB_EVENT_KEY_DOWN: switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_1, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 1; gui_drag.x = x; gui_drag.y = y; break; case NSFB_KEY_MOUSE_3: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_2, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 2; gui_drag.x = x; gui_drag.y = y; break; case NSFB_KEY_MOUSE_4: /* scroll up */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, -100) == false) widget_scroll_y(gw, -100, false); break; case NSFB_KEY_MOUSE_5: /* scroll down */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, 100) == false) widget_scroll_y(gw, 100, false); break; default: break; } break; case NSFB_EVENT_KEY_UP: switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } gui_drag.state = GUI_DRAG_NONE; /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; browser_window_mouse_click(gw->bw, BROWSER_MOUSE_CLICK_1, x, y); break; case NSFB_KEY_MOUSE_3: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ gui_drag.state = GUI_DRAG_NONE; if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; browser_window_mouse_click(gw->bw, BROWSER_MOUSE_CLICK_2, x, y); break; default: break; } break; default: break; } return 1; }