Bug Summary

File:frontends/framebuffer/gui.c
Warning:line 1700, column 3
Value stored to 'widget' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gui.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-19/lib/clang/19 -isystem /usr/include/mit-krb5 -I . -I include -I build/Linux-framebuffer -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -I /usr/include/p11-kit-1 -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -I /usr/include/webp -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NS_SVG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSSPRITE -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -D nsframebuffer -D small -D NETSURF_FB_RESPATH="${HOME}/.netsurf/:${NETSURFRES}:/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf:./frontends/framebuffer/res" -D NETSURF_FB_FONTPATH="/usr/share/fonts/truetype/dejavu:/usr/share/fonts/truetype/msttcorefonts" -D NETSURF_FB_FONT_SANS_SERIF="DejaVuSans.ttf" -D NETSURF_FB_FONT_SANS_SERIF_BOLD="DejaVuSans-Bold.ttf" -D NETSURF_FB_FONT_SANS_SERIF_ITALIC="DejaVuSans-Oblique.ttf" -D NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD="DejaVuSans-BoldOblique.ttf" -D NETSURF_FB_FONT_SERIF="DejaVuSerif.ttf" -D NETSURF_FB_FONT_SERIF_BOLD="DejaVuSerif-Bold.ttf" -D NETSURF_FB_FONT_MONOSPACE="DejaVuSansMono.ttf" -D NETSURF_FB_FONT_MONOSPACE_BOLD="DejaVuSansMono-Bold.ttf" -D NETSURF_FB_FONT_CURSIVE="Comic_Sans_MS.ttf" -D NETSURF_FB_FONT_FANTASY="Impact.ttf" -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D _POSIX_C_SOURCE=200809L -D _XOPEN_SOURCE=700 -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2025-11-24-121917-2152729-1 -x c frontends/framebuffer/gui.c
1/*
2 * Copyright 2008, 2014 Vincent Sanders <vince@netsurf-browser.org>
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 <stdint.h>
20#include <limits.h>
21#include <getopt.h>
22#include <assert.h>
23#include <string.h>
24#include <stdbool.h>
25#include <stdlib.h>
26#include <nsutils/time.h>
27
28#include <libnsfb.h>
29#include <libnsfb_plot.h>
30#include <libnsfb_event.h>
31
32#include "utils/utils.h"
33#include "utils/nsoption.h"
34#include "utils/filepath.h"
35#include "utils/log.h"
36#include "utils/messages.h"
37#include "netsurf/browser_window.h"
38#include "netsurf/keypress.h"
39#include "desktop/browser_history.h"
40#include "netsurf/plotters.h"
41#include "netsurf/window.h"
42#include "netsurf/misc.h"
43#include "netsurf/netsurf.h"
44#include "netsurf/cookie_db.h"
45#include "content/fetch.h"
46
47#include "framebuffer/gui.h"
48#include "framebuffer/fbtk.h"
49#include "framebuffer/framebuffer.h"
50#include "framebuffer/schedule.h"
51#include "framebuffer/findfile.h"
52#include "framebuffer/image_data.h"
53#include "framebuffer/font.h"
54#include "framebuffer/clipboard.h"
55#include "framebuffer/fetch.h"
56#include "framebuffer/bitmap.h"
57#include "framebuffer/local_history.h"
58#include "framebuffer/corewindow.h"
59
60
61#define NSFB_TOOLBAR_DEFAULT_LAYOUT"blfsrutc" "blfsrutc"
62
63fbtk_widget_t *fbtk;
64
65static bool_Bool fb_complete = false0;
66
67struct gui_window *input_window = NULL((void*)0);
68struct gui_window *search_current_window;
69struct gui_window *window_list = NULL((void*)0);
70
71/* private data for browser user widget */
72struct browser_widget_s {
73 struct browser_window *bw; /**< The browser window connected to this gui window */
74 int scrollx, scrolly; /**< scroll offsets. */
75
76 /* Pending window redraw state. */
77 bool_Bool redraw_required; /**< flag indicating the foreground loop
78 * needs to redraw the browser widget.
79 */
80 bbox_t redraw_box; /**< Area requiring redraw. */
81 bool_Bool pan_required; /**< flag indicating the foreground loop
82 * needs to pan the window.
83 */
84 int panx, pany; /**< Panning required. */
85};
86
87static struct gui_drag {
88 enum state {
89 GUI_DRAG_NONE,
90 GUI_DRAG_PRESSED,
91 GUI_DRAG_DRAG
92 } state;
93 int button;
94 int x;
95 int y;
96 bool_Bool grabbed_pointer;
97} gui_drag;
98
99
100/**
101 * Cause an abnormal program termination.
102 *
103 * \note This never returns and is intended to terminate without any cleanup.
104 *
105 * \param error The message to display to the user.
106 */
107static void die(const char *error)
108{
109 fprintf(stderrstderr, "%s\n", error);
110 exit(1);
111}
112
113
114/**
115 * Warn the user of an event.
116 *
117 * \param[in] warning A warning looked up in the message translation table
118 * \param[in] detail Additional text to be displayed or NULL.
119 * \return NSERROR_OK on success or error code if there was a
120 * faliure displaying the message to the user.
121 */
122static nserror fb_warn_user(const char *warning, const char *detail)
123{
124 NSLOG(netsurf, INFO, "%s %s", warning, detail)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 124
, }; nslog__log(&_nslog_ctx, "%s %s", warning, detail); }
} while(0)
;
125 return NSERROR_OK;
126}
127
128/* queue a redraw operation, co-ordinates are relative to the window */
129static void
130fb_queue_redraw(struct fbtk_widget_s *widget, int x0, int y0, int x1, int y1)
131{
132 struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
133
134 bwidget->redraw_box.x0 = min(bwidget->redraw_box.x0, x0)(((bwidget->redraw_box.x0)<(x0))?(bwidget->redraw_box
.x0):(x0))
;
135 bwidget->redraw_box.y0 = min(bwidget->redraw_box.y0, y0)(((bwidget->redraw_box.y0)<(y0))?(bwidget->redraw_box
.y0):(y0))
;
136 bwidget->redraw_box.x1 = max(bwidget->redraw_box.x1, x1)(((bwidget->redraw_box.x1)>(x1))?(bwidget->redraw_box
.x1):(x1))
;
137 bwidget->redraw_box.y1 = max(bwidget->redraw_box.y1, y1)(((bwidget->redraw_box.y1)>(y1))?(bwidget->redraw_box
.y1):(y1))
;
138
139 if (fbtk_clip_to_widget(widget, &bwidget->redraw_box)) {
140 bwidget->redraw_required = true1;
141 fbtk_request_redraw(widget);
142 } else {
143 bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX2147483647;
144 bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = -(INT_MAX2147483647);
145 bwidget->redraw_required = false0;
146 }
147}
148
149/* queue a window scroll */
150static void
151widget_scroll_y(struct gui_window *gw, int y, bool_Bool abs)
152{
153 struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
154 int content_width, content_height;
155 int height;
156
157 NSLOG(netsurf, DEEPDEBUG, "window scroll")do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "frontends/framebuffer/gui.c", sizeof
("frontends/framebuffer/gui.c") - 1, __PRETTY_FUNCTION__, sizeof
(__PRETTY_FUNCTION__) - 1, 157, }; nslog__log(&_nslog_ctx
, "window scroll"); } } while(0)
;
158 if (abs) {
159 bwidget->pany = y - bwidget->scrolly;
160 } else {
161 bwidget->pany += y;
162 }
163
164 browser_window_get_extents(gw->bw, true1,
165 &content_width, &content_height);
166
167 height = fbtk_get_height(gw->browser);
168
169 /* dont pan off the top */
170 if ((bwidget->scrolly + bwidget->pany) < 0)
171 bwidget->pany = -bwidget->scrolly;
172
173 /* do not pan off the bottom of the content */
174 if ((bwidget->scrolly + bwidget->pany) > (content_height - height))
175 bwidget->pany = (content_height - height) - bwidget->scrolly;
176
177 if (bwidget->pany == 0)
178 return;
179
180 bwidget->pan_required = true1;
181
182 fbtk_request_redraw(gw->browser);
183
184 fbtk_set_scroll_position(gw->vscroll, bwidget->scrolly + bwidget->pany);
185}
186
187/* queue a window scroll */
188static void
189widget_scroll_x(struct gui_window *gw, int x, bool_Bool abs)
190{
191 struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
192 int content_width, content_height;
193 int width;
194
195 if (abs) {
196 bwidget->panx = x - bwidget->scrollx;
197 } else {
198 bwidget->panx += x;
199 }
200
201 browser_window_get_extents(gw->bw, true1,
202 &content_width, &content_height);
203
204 width = fbtk_get_width(gw->browser);
205
206 /* dont pan off the left */
207 if ((bwidget->scrollx + bwidget->panx) < 0)
208 bwidget->panx = - bwidget->scrollx;
209
210 /* do not pan off the right of the content */
211 if ((bwidget->scrollx + bwidget->panx) > (content_width - width))
212 bwidget->panx = (content_width - width) - bwidget->scrollx;
213
214 if (bwidget->panx == 0)
215 return;
216
217 bwidget->pan_required = true1;
218
219 fbtk_request_redraw(gw->browser);
220
221 fbtk_set_scroll_position(gw->hscroll, bwidget->scrollx + bwidget->panx);
222}
223
224static void
225fb_pan(fbtk_widget_t *widget,
226 struct browser_widget_s *bwidget,
227 struct browser_window *bw)
228{
229 int x;
230 int y;
231 int width;
232 int height;
233 nsfb_bbox_t srcbox;
234 nsfb_bbox_t dstbox;
235
236 nsfb_t *nsfb = fbtk_get_nsfb(widget);
237
238 height = fbtk_get_height(widget);
239 width = fbtk_get_width(widget);
240
241 NSLOG(netsurf, DEEPDEBUG, "panning %d, %d",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "frontends/framebuffer/gui.c", sizeof
("frontends/framebuffer/gui.c") - 1, __PRETTY_FUNCTION__, sizeof
(__PRETTY_FUNCTION__) - 1, 242, }; nslog__log(&_nslog_ctx
, "panning %d, %d", bwidget->panx, bwidget->pany); } } while
(0)
242 bwidget->panx, bwidget->pany)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "frontends/framebuffer/gui.c", sizeof
("frontends/framebuffer/gui.c") - 1, __PRETTY_FUNCTION__, sizeof
(__PRETTY_FUNCTION__) - 1, 242, }; nslog__log(&_nslog_ctx
, "panning %d, %d", bwidget->panx, bwidget->pany); } } while
(0)
;
243
244 x = fbtk_get_absx(widget);
245 y = fbtk_get_absy(widget);
246
247 /* if the pan exceeds the viewport size just redraw the whole area */
248 if (bwidget->pany >= height || bwidget->pany <= -height ||
249 bwidget->panx >= width || bwidget->panx <= -width) {
250
251 bwidget->scrolly += bwidget->pany;
252 bwidget->scrollx += bwidget->panx;
253 fb_queue_redraw(widget, 0, 0, width, height);
254
255 /* ensure we don't try to scroll again */
256 bwidget->panx = 0;
257 bwidget->pany = 0;
258 bwidget->pan_required = false0;
259 return;
260 }
261
262 if (bwidget->pany < 0) {
263 /* pan up by less then viewport height */
264 srcbox.x0 = x;
265 srcbox.y0 = y;
266 srcbox.x1 = srcbox.x0 + width;
267 srcbox.y1 = srcbox.y0 + height + bwidget->pany;
268
269 dstbox.x0 = x;
270 dstbox.y0 = y - bwidget->pany;
271 dstbox.x1 = dstbox.x0 + width;
272 dstbox.y1 = dstbox.y0 + height + bwidget->pany;
273
274 /* move part that remains visible up */
275 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
276
277 /* redraw newly exposed area */
278 bwidget->scrolly += bwidget->pany;
279 fb_queue_redraw(widget, 0, 0, width, - bwidget->pany);
280
281 } else if (bwidget->pany > 0) {
282 /* pan down by less then viewport height */
283 srcbox.x0 = x;
284 srcbox.y0 = y + bwidget->pany;
285 srcbox.x1 = srcbox.x0 + width;
286 srcbox.y1 = srcbox.y0 + height - bwidget->pany;
287
288 dstbox.x0 = x;
289 dstbox.y0 = y;
290 dstbox.x1 = dstbox.x0 + width;
291 dstbox.y1 = dstbox.y0 + height - bwidget->pany;
292
293 /* move part that remains visible down */
294 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
295
296 /* redraw newly exposed area */
297 bwidget->scrolly += bwidget->pany;
298 fb_queue_redraw(widget, 0, height - bwidget->pany,
299 width, height);
300 }
301
302 if (bwidget->panx < 0) {
303 /* pan left by less then viewport width */
304 srcbox.x0 = x;
305 srcbox.y0 = y;
306 srcbox.x1 = srcbox.x0 + width + bwidget->panx;
307 srcbox.y1 = srcbox.y0 + height;
308
309 dstbox.x0 = x - bwidget->panx;
310 dstbox.y0 = y;
311 dstbox.x1 = dstbox.x0 + width + bwidget->panx;
312 dstbox.y1 = dstbox.y0 + height;
313
314 /* move part that remains visible left */
315 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
316
317 /* redraw newly exposed area */
318 bwidget->scrollx += bwidget->panx;
319 fb_queue_redraw(widget, 0, 0, -bwidget->panx, height);
320
321 } else if (bwidget->panx > 0) {
322 /* pan right by less then viewport width */
323 srcbox.x0 = x + bwidget->panx;
324 srcbox.y0 = y;
325 srcbox.x1 = srcbox.x0 + width - bwidget->panx;
326 srcbox.y1 = srcbox.y0 + height;
327
328 dstbox.x0 = x;
329 dstbox.y0 = y;
330 dstbox.x1 = dstbox.x0 + width - bwidget->panx;
331 dstbox.y1 = dstbox.y0 + height;
332
333 /* move part that remains visible right */
334 nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
335
336 /* redraw newly exposed area */
337 bwidget->scrollx += bwidget->panx;
338 fb_queue_redraw(widget, width - bwidget->panx, 0,
339 width, height);
340 }
341
342 bwidget->pan_required = false0;
343 bwidget->panx = 0;
344 bwidget->pany = 0;
345}
346
347static void
348fb_redraw(fbtk_widget_t *widget,
349 struct browser_widget_s *bwidget,
350 struct browser_window *bw)
351{
352 int x;
353 int y;
354 int caret_x, caret_y, caret_h;
355 struct rect clip;
356 struct redraw_context ctx = {
357 .interactive = true1,
358 .background_images = true1,
359 .plot = &fb_plotters
360 };
361 nsfb_t *nsfb = fbtk_get_nsfb(widget);
362
363 x = fbtk_get_absx(widget);
364 y = fbtk_get_absy(widget);
365
366 /* adjust clipping co-ordinates according to window location */
367 bwidget->redraw_box.y0 += y;
368 bwidget->redraw_box.y1 += y;
369 bwidget->redraw_box.x0 += x;
370 bwidget->redraw_box.x1 += x;
371
372 nsfb_claim(nsfb, &bwidget->redraw_box);
373
374 /* redraw bounding box is relative to window */
375 clip.x0 = bwidget->redraw_box.x0;
376 clip.y0 = bwidget->redraw_box.y0;
377 clip.x1 = bwidget->redraw_box.x1;
378 clip.y1 = bwidget->redraw_box.y1;
379
380 browser_window_redraw(bw,
381 x - bwidget->scrollx,
382 y - bwidget->scrolly,
383 &clip, &ctx);
384
385 if (fbtk_get_caret(widget, &caret_x, &caret_y, &caret_h)) {
386 /* This widget has caret, so render it */
387 nsfb_bbox_t line;
388 nsfb_plot_pen_t pen;
389
390 line.x0 = x - bwidget->scrollx + caret_x;
391 line.y0 = y - bwidget->scrolly + caret_y;
392 line.x1 = x - bwidget->scrollx + caret_x;
393 line.y1 = y - bwidget->scrolly + caret_y + caret_h;
394
395 pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
396 pen.stroke_width = 1;
397 pen.stroke_colour = 0xFF0000FF;
398
399 nsfb_plot_line(nsfb, &line, &pen);
400 }
401
402 nsfb_update(fbtk_get_nsfb(widget), &bwidget->redraw_box);
403
404 bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX2147483647;
405 bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = INT_MIN(-2147483647 -1);
406 bwidget->redraw_required = false0;
407}
408
409static int
410fb_browser_window_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
411{
412 struct gui_window *gw = cbi->context;
413 struct browser_widget_s *bwidget;
414
415 bwidget = fbtk_get_userpw(widget);
416 if (bwidget == NULL((void*)0)) {
417 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 418
, }; nslog__log(&_nslog_ctx, "browser widget from widget %p was null"
, widget); } } while(0)
418 "browser widget from widget %p was null", widget)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 418
, }; nslog__log(&_nslog_ctx, "browser widget from widget %p was null"
, widget); } } while(0)
;
419 return -1;
420 }
421
422 if (bwidget->pan_required) {
423 fb_pan(widget, bwidget, gw->bw);
424 }
425
426 if (bwidget->redraw_required) {
427 fb_redraw(widget, bwidget, gw->bw);
428 } else {
429 bwidget->redraw_box.x0 = 0;
430 bwidget->redraw_box.y0 = 0;
431 bwidget->redraw_box.x1 = fbtk_get_width(widget);
432 bwidget->redraw_box.y1 = fbtk_get_height(widget);
433 fb_redraw(widget, bwidget, gw->bw);
434 }
435 return 0;
436}
437
438static int fb_browser_window_destroy(fbtk_widget_t *widget,
439 fbtk_callback_info *cbi)
440{
441 struct browser_widget_s *browser_widget;
442
443 if (widget == NULL((void*)0)) {
444 return 0;
445 }
446
447 /* Free private data */
448 browser_widget = fbtk_get_userpw(widget);
449 free(browser_widget);
450
451 return 0;
452}
453
454static void
455framebuffer_surface_iterator(void *ctx, const char *name, enum nsfb_type_e type)
456{
457 const char *arg0 = ctx;
458
459 fprintf(stderrstderr, "%s: %s\n", arg0, name);
460}
461
462static enum nsfb_type_e fetype = NSFB_SURFACE_COUNT;
463static const char *fename;
464static int febpp;
465static int fewidth;
466static int feheight;
467static const char *feurl;
468
469static void
470framebuffer_pick_default_fename(void *ctx, const char *name, enum nsfb_type_e type)
471{
472 if (type < fetype) {
473 fename = name;
474 }
475}
476
477static bool_Bool
478process_cmdline(int argc, char** argv)
479{
480 int opt;
481 int option_index;
482 static struct option long_options[] = {
483 {0, 0, 0, 0 }
484 }; /* no long options */
485
486 NSLOG(netsurf, INFO, "argc %d, argv %p", argc, argv)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 486
, }; nslog__log(&_nslog_ctx, "argc %d, argv %p", argc, argv
); } } while(0)
;
487
488 nsfb_enumerate_surface_types(framebuffer_pick_default_fename, NULL((void*)0));
489
490 febpp = 32;
491
492 fewidth = nsoption_int(window_width)(nsoptions[NSOPTION_window_width].value.i);
493 if (fewidth <= 0) {
494 fewidth = 800;
495 }
496 feheight = nsoption_int(window_height)(nsoptions[NSOPTION_window_height].value.i);
497 if (feheight <= 0) {
498 feheight = 600;
499 }
500
501 if ((nsoption_charp(homepage_url)(nsoptions[NSOPTION_homepage_url].value.s) != NULL((void*)0)) &&
502 (nsoption_charp(homepage_url)(nsoptions[NSOPTION_homepage_url].value.s)[0] != '\0')) {
503 feurl = nsoption_charp(homepage_url)(nsoptions[NSOPTION_homepage_url].value.s);
504 } else {
505 feurl = NETSURF_HOMEPAGE"about:welcome";
506 }
507
508 while((opt = getopt_long(argc, argv, "f:b:w:h:",
509 long_options, &option_index)) != -1) {
510 switch (opt) {
511 case 'f':
512 fename = optarg;
513 break;
514
515 case 'b':
516 febpp = atoi(optarg);
517 break;
518
519 case 'w':
520 fewidth = atoi(optarg);
521 break;
522
523 case 'h':
524 feheight = atoi(optarg);
525 break;
526
527 default:
528 fprintf(stderrstderr,
529 "Usage: %s [-f frontend] [-b bpp] [-w width] [-h height] <url>\n",
530 argv[0]);
531 return false0;
532 }
533 }
534
535 if (optind < argc) {
536 feurl = argv[optind];
537 }
538
539 if (nsfb_type_from_name(fename) == NSFB_SURFACE_NONE) {
540 if (strcmp(fename, "?") != 0) {
541 fprintf(stderrstderr,
542 "%s: Unknown surface `%s`\n", argv[0], fename);
543 }
544 fprintf(stderrstderr, "%s: Valid surface names are:\n", argv[0]);
545 nsfb_enumerate_surface_types(framebuffer_surface_iterator, argv[0]);
546 return false0;
547 }
548
549 return true1;
550}
551
552/**
553 * Set option defaults for framebuffer frontend
554 *
555 * @param defaults The option table to update.
556 * @return error status.
557 */
558static nserror set_defaults(struct nsoption_s *defaults)
559{
560 int idx;
561 static const struct {
562 enum nsoption_e nsc;
563 colour c;
564 } sys_colour_defaults[]= {
565 { NSOPTION_sys_colour_AccentColor, 0x00666666},
566 { NSOPTION_sys_colour_AccentColorText, 0x00ffffff},
567 { NSOPTION_sys_colour_ActiveText, 0x000000ee},
568 { NSOPTION_sys_colour_ButtonBorder, 0x00aaaaaa},
569 { NSOPTION_sys_colour_ButtonFace, 0x00dddddd},
570 { NSOPTION_sys_colour_ButtonText, 0x00000000},
571 { NSOPTION_sys_colour_Canvas, 0x00aaaaaa},
572 { NSOPTION_sys_colour_CanvasText, 0x00000000},
573 { NSOPTION_sys_colour_Field, 0x00f1f1f1},
574 { NSOPTION_sys_colour_FieldText, 0x00000000},
575 { NSOPTION_sys_colour_GrayText, 0x00777777},
576 { NSOPTION_sys_colour_Highlight, 0x00ee0000},
577 { NSOPTION_sys_colour_HighlightText, 0x00000000},
578 { NSOPTION_sys_colour_LinkText, 0x00ee0000},
579 { NSOPTION_sys_colour_Mark, 0x0000ffff},
580 { NSOPTION_sys_colour_MarkText, 0x00000000},
581 { NSOPTION_sys_colour_SelectedItem, 0x00e48435},
582 { NSOPTION_sys_colour_SelectedItemText, 0x00ffffff},
583 { NSOPTION_sys_colour_VisitedText, 0x008b1a55},
584 { NSOPTION_LISTEND, 0},
585 };
586
587 /* Set defaults for absent option strings */
588 nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies"))do { if (nsoptions[NSOPTION_cookie_file].value.s == ((void*)0
)) { nsoption_set_tbl_charp(nsoptions, NSOPTION_cookie_file, strdup
("~/.netsurf/Cookies")); } else { free(strdup("~/.netsurf/Cookies"
)); } } while (0)
;
589 nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies"))do { if (nsoptions[NSOPTION_cookie_jar].value.s == ((void*)0)
) { nsoption_set_tbl_charp(nsoptions, NSOPTION_cookie_jar, strdup
("~/.netsurf/Cookies")); } else { free(strdup("~/.netsurf/Cookies"
)); } } while (0)
;
590
591 if (nsoption_charp(cookie_file)(nsoptions[NSOPTION_cookie_file].value.s) == NULL((void*)0) ||
592 nsoption_charp(cookie_jar)(nsoptions[NSOPTION_cookie_jar].value.s) == NULL((void*)0)) {
593 NSLOG(netsurf, INFO, "Failed initialising cookie options")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 593
, }; nslog__log(&_nslog_ctx, "Failed initialising cookie options"
); } } while(0)
;
594 return NSERROR_BAD_PARAMETER;
595 }
596
597 /* set system colours for framebuffer ui */
598 for (idx=0; sys_colour_defaults[idx].nsc != NSOPTION_LISTEND; idx++) {
599 defaults[sys_colour_defaults[idx].nsc].value.c = sys_colour_defaults[idx].c;
600 }
601 return NSERROR_OK;
602}
603
604
605/**
606 * Ensures output logging stream is correctly configured
607 */
608static bool_Bool nslog_stream_configure(FILE *fptr)
609{
610 /* set log stream to be non-buffering */
611 setbuf(fptr, NULL((void*)0));
612
613 return true1;
614}
615
616static void framebuffer_run(void)
617{
618 nsfb_event_t event;
619 int timeout; /* timeout in miliseconds */
620
621 while (fb_complete != true1) {
622 /* run the scheduler and discover how long to wait for
623 * the next event.
624 */
625 timeout = schedule_run();
626
627 /* if redraws are pending do not wait for event,
628 * return immediately
629 */
630 if (fbtk_get_redraw_pending(fbtk))
631 timeout = 0;
632
633 if (fbtk_event(fbtk, &event, timeout)) {
634 if ((event.type == NSFB_EVENT_CONTROL) &&
635 (event.value.controlcode == NSFB_CONTROL_QUIT))
636 fb_complete = true1;
637 }
638
639 fbtk_redraw(fbtk);
640 }
641}
642
643static void gui_quit(void)
644{
645 NSLOG(netsurf, INFO, "gui_quit")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 645
, }; nslog__log(&_nslog_ctx, "gui_quit"); } } while(0)
;
646
647 urldb_save_cookies(nsoption_charp(cookie_jar)(nsoptions[NSOPTION_cookie_jar].value.s));
648
649 framebuffer_finalise();
650}
651
652/* called back when click in browser window */
653static int
654fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
655{
656 struct gui_window *gw = cbi->context;
657 struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
658 browser_mouse_state mouse;
659 int x = cbi->x + bwidget->scrollx;
660 int y = cbi->y + bwidget->scrolly;
661 uint64_t time_now;
662 static struct {
663 enum { CLICK_SINGLE, CLICK_DOUBLE, CLICK_TRIPLE } type;
664 uint64_t time;
665 } last_click;
666
667 if (cbi->event->type != NSFB_EVENT_KEY_DOWN &&
668 cbi->event->type != NSFB_EVENT_KEY_UP)
669 return 0;
670
671 NSLOG(netsurf, DEEPDEBUG, "browser window clicked at %d,%d",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "frontends/framebuffer/gui.c", sizeof
("frontends/framebuffer/gui.c") - 1, __PRETTY_FUNCTION__, sizeof
(__PRETTY_FUNCTION__) - 1, 672, }; nslog__log(&_nslog_ctx
, "browser window clicked at %d,%d", cbi->x, cbi->y); }
} while(0)
672 cbi->x, cbi->y)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "frontends/framebuffer/gui.c", sizeof
("frontends/framebuffer/gui.c") - 1, __PRETTY_FUNCTION__, sizeof
(__PRETTY_FUNCTION__) - 1, 672, }; nslog__log(&_nslog_ctx
, "browser window clicked at %d,%d", cbi->x, cbi->y); }
} while(0)
;
673
674 switch (cbi->event->type) {
675 case NSFB_EVENT_KEY_DOWN:
676 switch (cbi->event->value.keycode) {
677 case NSFB_KEY_MOUSE_1:
678 browser_window_mouse_click(gw->bw,
679 BROWSER_MOUSE_PRESS_1, x, y);
680 gui_drag.state = GUI_DRAG_PRESSED;
681 gui_drag.button = 1;
682 gui_drag.x = x;
683 gui_drag.y = y;
684 break;
685
686 case NSFB_KEY_MOUSE_3:
687 browser_window_mouse_click(gw->bw,
688 BROWSER_MOUSE_PRESS_2, x, y);
689 gui_drag.state = GUI_DRAG_PRESSED;
690 gui_drag.button = 2;
691 gui_drag.x = x;
692 gui_drag.y = y;
693 break;
694
695 case NSFB_KEY_MOUSE_4:
696 /* scroll up */
697 if (browser_window_scroll_at_point(gw->bw,
698 x, y,
699 0, -100) == false0)
700 widget_scroll_y(gw, -100, false0);
701 break;
702
703 case NSFB_KEY_MOUSE_5:
704 /* scroll down */
705 if (browser_window_scroll_at_point(gw->bw,
706 x, y,
707 0, 100) == false0)
708 widget_scroll_y(gw, 100, false0);
709 break;
710
711 default:
712 break;
713
714 }
715
716 break;
717 case NSFB_EVENT_KEY_UP:
718
719 mouse = 0;
720 nsu_getmonotonic_ms(&time_now);
721
722 switch (cbi->event->value.keycode) {
723 case NSFB_KEY_MOUSE_1:
724 if (gui_drag.state == GUI_DRAG_DRAG) {
725 /* End of a drag, rather than click */
726
727 if (gui_drag.grabbed_pointer) {
728 /* need to ungrab pointer */
729 fbtk_tgrab_pointer(widget);
730 gui_drag.grabbed_pointer = false0;
731 }
732
733 gui_drag.state = GUI_DRAG_NONE;
734
735 /* Tell core */
736 browser_window_mouse_track(gw->bw, 0, x, y);
737 break;
738 }
739 /* This is a click;
740 * clear PRESSED state and pass to core */
741 gui_drag.state = GUI_DRAG_NONE;
742 mouse = BROWSER_MOUSE_CLICK_1;
743 break;
744
745 case NSFB_KEY_MOUSE_3:
746 if (gui_drag.state == GUI_DRAG_DRAG) {
747 /* End of a drag, rather than click */
748 gui_drag.state = GUI_DRAG_NONE;
749
750 if (gui_drag.grabbed_pointer) {
751 /* need to ungrab pointer */
752 fbtk_tgrab_pointer(widget);
753 gui_drag.grabbed_pointer = false0;
754 }
755
756 /* Tell core */
757 browser_window_mouse_track(gw->bw, 0, x, y);
758 break;
759 }
760 /* This is a click;
761 * clear PRESSED state and pass to core */
762 gui_drag.state = GUI_DRAG_NONE;
763 mouse = BROWSER_MOUSE_CLICK_2;
764 break;
765
766 default:
767 break;
768
769 }
770
771 /* Determine if it's a double or triple click, allowing
772 * 0.5 seconds (500ms) between clicks
773 */
774 if ((time_now < (last_click.time + 500)) &&
775 (cbi->event->value.keycode != NSFB_KEY_MOUSE_4) &&
776 (cbi->event->value.keycode != NSFB_KEY_MOUSE_5)) {
777 if (last_click.type == CLICK_SINGLE) {
778 /* Set double click */
779 mouse |= BROWSER_MOUSE_DOUBLE_CLICK;
780 last_click.type = CLICK_DOUBLE;
781
782 } else if (last_click.type == CLICK_DOUBLE) {
783 /* Set triple click */
784 mouse |= BROWSER_MOUSE_TRIPLE_CLICK;
785 last_click.type = CLICK_TRIPLE;
786 } else {
787 /* Set normal click */
788 last_click.type = CLICK_SINGLE;
789 }
790 } else {
791 last_click.type = CLICK_SINGLE;
792 }
793
794 if (mouse) {
795 browser_window_mouse_click(gw->bw, mouse, x, y);
796 }
797
798 last_click.time = time_now;
799
800 break;
801 default:
802 break;
803
804 }
805 return 1;
806}
807
808/* called back when movement in browser window */
809static int
810fb_browser_window_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
811{
812 browser_mouse_state mouse = 0;
813 struct gui_window *gw = cbi->context;
814 struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
815 int x = cbi->x + bwidget->scrollx;
816 int y = cbi->y + bwidget->scrolly;
817
818 if (gui_drag.state == GUI_DRAG_PRESSED &&
819 (abs(x - gui_drag.x) > 5 ||
820 abs(y - gui_drag.y) > 5)) {
821 /* Drag started */
822 if (gui_drag.button == 1) {
823 browser_window_mouse_click(gw->bw,
824 BROWSER_MOUSE_DRAG_1,
825 gui_drag.x, gui_drag.y);
826 } else {
827 browser_window_mouse_click(gw->bw,
828 BROWSER_MOUSE_DRAG_2,
829 gui_drag.x, gui_drag.y);
830 }
831 gui_drag.grabbed_pointer = fbtk_tgrab_pointer(widget);
832 gui_drag.state = GUI_DRAG_DRAG;
833 }
834
835 if (gui_drag.state == GUI_DRAG_DRAG) {
836 /* set up mouse state */
837 mouse |= BROWSER_MOUSE_DRAG_ON;
838
839 if (gui_drag.button == 1)
840 mouse |= BROWSER_MOUSE_HOLDING_1;
841 else
842 mouse |= BROWSER_MOUSE_HOLDING_2;
843 }
844
845 browser_window_mouse_track(gw->bw, mouse, x, y);
846
847 return 0;
848}
849
850
851static int
852fb_browser_window_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
853{
854 struct gui_window *gw = cbi->context;
855 static fbtk_modifier_type modifier = FBTK_MOD_CLEAR;
856 int ucs4 = -1;
857
858 NSLOG(netsurf, INFO, "got value %d", cbi->event->value.keycode)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 858
, }; nslog__log(&_nslog_ctx, "got value %d", cbi->event
->value.keycode); } } while(0)
;
859
860 switch (cbi->event->type) {
861 case NSFB_EVENT_KEY_DOWN:
862 switch (cbi->event->value.keycode) {
863
864 case NSFB_KEY_DELETE:
865 browser_window_key_press(gw->bw, NS_KEY_DELETE_RIGHT);
866 break;
867
868 case NSFB_KEY_PAGEUP:
869 if (browser_window_key_press(gw->bw,
870 NS_KEY_PAGE_UP) == false0)
871 widget_scroll_y(gw, -fbtk_get_height(
872 gw->browser), false0);
873 break;
874
875 case NSFB_KEY_PAGEDOWN:
876 if (browser_window_key_press(gw->bw,
877 NS_KEY_PAGE_DOWN) == false0)
878 widget_scroll_y(gw, fbtk_get_height(
879 gw->browser), false0);
880 break;
881
882 case NSFB_KEY_RIGHT:
883 if (modifier & FBTK_MOD_RCTRL ||
884 modifier & FBTK_MOD_LCTRL) {
885 /* CTRL held */
886 if (browser_window_key_press(gw->bw,
887 NS_KEY_LINE_END) == false0)
888 widget_scroll_x(gw, INT_MAX2147483647, true1);
889
890 } else if (modifier & FBTK_MOD_RSHIFT ||
891 modifier & FBTK_MOD_LSHIFT) {
892 /* SHIFT held */
893 if (browser_window_key_press(gw->bw,
894 NS_KEY_WORD_RIGHT) == false0)
895 widget_scroll_x(gw, fbtk_get_width(
896 gw->browser), false0);
897
898 } else {
899 /* no modifier */
900 if (browser_window_key_press(gw->bw,
901 NS_KEY_RIGHT) == false0)
902 widget_scroll_x(gw, 100, false0);
903 }
904 break;
905
906 case NSFB_KEY_LEFT:
907 if (modifier & FBTK_MOD_RCTRL ||
908 modifier & FBTK_MOD_LCTRL) {
909 /* CTRL held */
910 if (browser_window_key_press(gw->bw,
911 NS_KEY_LINE_START) == false0)
912 widget_scroll_x(gw, 0, true1);
913
914 } else if (modifier & FBTK_MOD_RSHIFT ||
915 modifier & FBTK_MOD_LSHIFT) {
916 /* SHIFT held */
917 if (browser_window_key_press(gw->bw,
918 NS_KEY_WORD_LEFT) == false0)
919 widget_scroll_x(gw, -fbtk_get_width(
920 gw->browser), false0);
921
922 } else {
923 /* no modifier */
924 if (browser_window_key_press(gw->bw,
925 NS_KEY_LEFT) == false0)
926 widget_scroll_x(gw, -100, false0);
927 }
928 break;
929
930 case NSFB_KEY_UP:
931 if (browser_window_key_press(gw->bw,
932 NS_KEY_UP) == false0)
933 widget_scroll_y(gw, -100, false0);
934 break;
935
936 case NSFB_KEY_DOWN:
937 if (browser_window_key_press(gw->bw,
938 NS_KEY_DOWN) == false0)
939 widget_scroll_y(gw, 100, false0);
940 break;
941
942 case NSFB_KEY_MINUS:
943 if (modifier & FBTK_MOD_RCTRL ||
944 modifier & FBTK_MOD_LCTRL) {
945 browser_window_set_scale(gw->bw, -0.1, false0);
946 }
947 break;
948
949 case NSFB_KEY_EQUALS: /* PLUS */
950 if (modifier & FBTK_MOD_RCTRL ||
951 modifier & FBTK_MOD_LCTRL) {
952 browser_window_set_scale(gw->bw, 0.1, false0);
953 }
954 break;
955
956 case NSFB_KEY_0:
957 if (modifier & FBTK_MOD_RCTRL ||
958 modifier & FBTK_MOD_LCTRL) {
959 browser_window_set_scale(gw->bw, 1.0, true1);
960 }
961 break;
962
963 case NSFB_KEY_RSHIFT:
964 modifier |= FBTK_MOD_RSHIFT;
965 break;
966
967 case NSFB_KEY_LSHIFT:
968 modifier |= FBTK_MOD_LSHIFT;
969 break;
970
971 case NSFB_KEY_RCTRL:
972 modifier |= FBTK_MOD_RCTRL;
973 break;
974
975 case NSFB_KEY_LCTRL:
976 modifier |= FBTK_MOD_LCTRL;
977 break;
978
979 case NSFB_KEY_y:
980 case NSFB_KEY_z:
981 if (cbi->event->value.keycode == NSFB_KEY_z &&
982 (modifier & FBTK_MOD_RCTRL ||
983 modifier & FBTK_MOD_LCTRL) &&
984 (modifier & FBTK_MOD_RSHIFT ||
985 modifier & FBTK_MOD_LSHIFT)) {
986 /* Z pressed with CTRL and SHIFT held */
987 browser_window_key_press(gw->bw, NS_KEY_REDO);
988 break;
989
990 } else if (cbi->event->value.keycode == NSFB_KEY_z &&
991 (modifier & FBTK_MOD_RCTRL ||
992 modifier & FBTK_MOD_LCTRL)) {
993 /* Z pressed with CTRL held */
994 browser_window_key_press(gw->bw, NS_KEY_UNDO);
995 break;
996
997 } else if (cbi->event->value.keycode == NSFB_KEY_y &&
998 (modifier & FBTK_MOD_RCTRL ||
999 modifier & FBTK_MOD_LCTRL)) {
1000 /* Y pressed with CTRL held */
1001 browser_window_key_press(gw->bw, NS_KEY_REDO);
1002 break;
1003 }
1004 /* Z or Y pressed but not undo or redo; */
1005 fallthrough__attribute__((__fallthrough__));
1006
1007 default:
1008 ucs4 = fbtk_keycode_to_ucs4(cbi->event->value.keycode,
1009 modifier);
1010 if (ucs4 != -1)
1011 browser_window_key_press(gw->bw, ucs4);
1012 break;
1013 }
1014 break;
1015
1016 case NSFB_EVENT_KEY_UP:
1017 switch (cbi->event->value.keycode) {
1018 case NSFB_KEY_RSHIFT:
1019 modifier &= ~FBTK_MOD_RSHIFT;
1020 break;
1021
1022 case NSFB_KEY_LSHIFT:
1023 modifier &= ~FBTK_MOD_LSHIFT;
1024 break;
1025
1026 case NSFB_KEY_RCTRL:
1027 modifier &= ~FBTK_MOD_RCTRL;
1028 break;
1029
1030 case NSFB_KEY_LCTRL:
1031 modifier &= ~FBTK_MOD_LCTRL;
1032 break;
1033
1034 default:
1035 break;
1036 }
1037 break;
1038
1039 default:
1040 break;
1041 }
1042
1043 return 0;
1044}
1045
1046static void
1047fb_update_back_forward(struct gui_window *gw)
1048{
1049 struct browser_window *bw = gw->bw;
1050
1051 fbtk_set_bitmap(gw->back,
1052 (browser_window_back_available(bw)) ?
1053 &left_arrow : &left_arrow_g);
1054 fbtk_set_bitmap(gw->forward,
1055 (browser_window_forward_available(bw)) ?
1056 &right_arrow : &right_arrow_g);
1057}
1058
1059/* left icon click routine */
1060static int
1061fb_leftarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1062{
1063 struct gui_window *gw = cbi->context;
1064 struct browser_window *bw = gw->bw;
1065
1066 if (cbi->event->type != NSFB_EVENT_KEY_UP)
1067 return 0;
1068
1069 if (browser_window_back_available(bw))
1070 browser_window_history_back(bw, false0);
1071
1072 fb_update_back_forward(gw);
1073
1074 return 1;
1075}
1076
1077/* right arrow icon click routine */
1078static int
1079fb_rightarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1080{
1081 struct gui_window *gw = cbi->context;
1082 struct browser_window *bw = gw->bw;
1083
1084 if (cbi->event->type != NSFB_EVENT_KEY_UP)
1085 return 0;
1086
1087 if (browser_window_forward_available(bw))
1088 browser_window_history_forward(bw, false0);
1089
1090 fb_update_back_forward(gw);
1091 return 1;
1092
1093}
1094
1095/* reload icon click routine */
1096static int
1097fb_reload_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1098{
1099 struct browser_window *bw = cbi->context;
1100
1101 if (cbi->event->type != NSFB_EVENT_KEY_UP)
1102 return 0;
1103
1104 browser_window_reload(bw, true1);
1105 return 1;
1106}
1107
1108/* stop icon click routine */
1109static int
1110fb_stop_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1111{
1112 struct browser_window *bw = cbi->context;
1113
1114 if (cbi->event->type != NSFB_EVENT_KEY_UP)
1115 return 0;
1116
1117 browser_window_stop(bw);
1118 return 0;
1119}
1120
1121static int
1122fb_osk_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1123{
1124
1125 if (cbi->event->type != NSFB_EVENT_KEY_UP)
1126 return 0;
1127
1128 map_osk();
1129
1130 return 0;
1131}
1132
1133/* close browser window icon click routine */
1134static int
1135fb_close_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1136{
1137 if (cbi->event->type != NSFB_EVENT_KEY_UP)
1138 return 0;
1139
1140 fb_complete = true1;
1141
1142 return 0;
1143}
1144
1145static int
1146fb_scroll_callback(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1147{
1148 struct gui_window *gw = cbi->context;
1149
1150 switch (cbi->type) {
1151 case FBTK_CBT_SCROLLY:
1152 widget_scroll_y(gw, cbi->y, true1);
1153 break;
1154
1155 case FBTK_CBT_SCROLLX:
1156 widget_scroll_x(gw, cbi->x, true1);
1157 break;
1158
1159 default:
1160 break;
1161 }
1162 return 0;
1163}
1164
1165static int
1166fb_url_enter(void *pw, char *text)
1167{
1168 struct browser_window *bw = pw;
1169 nsurl *url;
1170 nserror error;
1171
1172 error = nsurl_create(text, &url);
1173 if (error != NSERROR_OK) {
1174 fb_warn_user("Errorcode:", messages_get_errorcode(error));
1175 } else {
1176 browser_window_navigate(bw, url, NULL((void*)0), BW_NAVIGATE_HISTORY,
1177 NULL((void*)0), NULL((void*)0), NULL((void*)0));
1178 nsurl_unref(url);
1179 }
1180
1181 return 0;
1182}
1183
1184static int
1185fb_url_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1186{
1187 framebuffer_set_cursor(&caret_image);
1188 return 0;
1189}
1190
1191static int
1192set_ptr_default_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1193{
1194 framebuffer_set_cursor(&pointer_image);
1195 return 0;
1196}
1197
1198static int
1199fb_localhistory_btn_clik(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1200{
1201 struct gui_window *gw = cbi->context;
1202
1203 if (cbi->event->type != NSFB_EVENT_KEY_UP)
1204 return 0;
1205
1206 fb_local_history_present(fbtk, gw->bw);
1207
1208 return 0;
1209}
1210
1211
1212/** Create a toolbar window and populate it with buttons.
1213 *
1214 * The toolbar layout uses a character to define buttons type and position:
1215 * b - back
1216 * l - local history
1217 * f - forward
1218 * s - stop
1219 * r - refresh
1220 * u - url bar expands to fit remaining space
1221 * t - throbber/activity indicator
1222 * c - close the current window
1223 *
1224 * The default layout is "blfsrut" there should be no more than a
1225 * single url bar entry or behaviour will be undefined.
1226 *
1227 * @param gw Parent window
1228 * @param toolbar_height The height in pixels of the toolbar
1229 * @param padding The padding in pixels round each element of the toolbar
1230 * @param frame_col Frame colour.
1231 * @param toolbar_layout A string defining which buttons and controls
1232 * should be added to the toolbar. May be empty
1233 * string to disable the bar..
1234 *
1235 */
1236static fbtk_widget_t *
1237create_toolbar(struct gui_window *gw,
1238 int toolbar_height,
1239 int padding,
1240 colour frame_col,
1241 const char *toolbar_layout)
1242{
1243 fbtk_widget_t *toolbar;
1244 fbtk_widget_t *widget;
1245
1246 int xpos; /* The position of the next widget. */
1247 int xlhs = 0; /* extent of the left hand side widgets */
1248 int xdir = 1; /* the direction of movement + or - 1 */
1249 const char *itmtype; /* type of the next item */
1250
1251 if (toolbar_layout == NULL((void*)0)) {
1252 toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT"blfsrutc";
1253 }
1254
1255 NSLOG(netsurf, INFO, "Using toolbar layout %s", toolbar_layout)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1255
, }; nslog__log(&_nslog_ctx, "Using toolbar layout %s", toolbar_layout
); } } while(0)
;
1256
1257 itmtype = toolbar_layout;
1258
1259 /* check for the toolbar being disabled */
1260 if ((*itmtype == 0) || (*itmtype == 'q')) {
1261 return NULL((void*)0);
1262 }
1263
1264 toolbar = fbtk_create_window(gw->window, 0, 0, 0,
1265 toolbar_height,
1266 frame_col);
1267
1268 if (toolbar == NULL((void*)0)) {
1269 return NULL((void*)0);
1270 }
1271
1272 fbtk_set_handler(toolbar,
1273 FBTK_CBT_POINTERENTER,
1274 set_ptr_default_move,
1275 NULL((void*)0));
1276
1277
1278 xpos = padding;
1279
1280 /* loop proceeds creating widget on the left hand side until
1281 * it runs out of layout or encounters a url bar declaration
1282 * wherupon it works backwards from the end of the layout
1283 * untill the space left is for the url bar
1284 */
1285 while ((itmtype >= toolbar_layout) &&
1286 (*itmtype != 0) &&
1287 (xdir !=0)) {
1288
1289 NSLOG(netsurf, INFO, "toolbar adding %c", *itmtype)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1289
, }; nslog__log(&_nslog_ctx, "toolbar adding %c", *itmtype
); } } while(0)
;
1290
1291
1292 switch (*itmtype) {
1293
1294 case 'b': /* back */
1295 widget = fbtk_create_button(toolbar,
1296 (xdir == 1) ? xpos :
1297 xpos - left_arrow.width,
1298 padding,
1299 left_arrow.width,
1300 -padding,
1301 frame_col,
1302 &left_arrow,
1303 fb_leftarrow_click,
1304 gw);
1305 gw->back = widget; /* keep reference */
1306 break;
1307
1308 case 'l': /* local history */
1309 widget = fbtk_create_button(toolbar,
1310 (xdir == 1) ? xpos :
1311 xpos - history_image.width,
1312 padding,
1313 history_image.width,
1314 -padding,
1315 frame_col,
1316 &history_image,
1317 fb_localhistory_btn_clik,
1318 gw);
1319 gw->history = widget;
1320 break;
1321
1322 case 'f': /* forward */
1323 widget = fbtk_create_button(toolbar,
1324 (xdir == 1)?xpos :
1325 xpos - right_arrow.width,
1326 padding,
1327 right_arrow.width,
1328 -padding,
1329 frame_col,
1330 &right_arrow,
1331 fb_rightarrow_click,
1332 gw);
1333 gw->forward = widget;
1334 break;
1335
1336 case 'c': /* close the current window */
1337 widget = fbtk_create_button(toolbar,
1338 (xdir == 1)?xpos :
1339 xpos - stop_image_g.width,
1340 padding,
1341 stop_image_g.width,
1342 -padding,
1343 frame_col,
1344 &stop_image_g,
1345 fb_close_click,
1346 gw->bw);
1347 gw->close = widget;
1348 break;
1349
1350 case 's': /* stop */
1351 widget = fbtk_create_button(toolbar,
1352 (xdir == 1)?xpos :
1353 xpos - stop_image.width,
1354 padding,
1355 stop_image.width,
1356 -padding,
1357 frame_col,
1358 &stop_image,
1359 fb_stop_click,
1360 gw->bw);
1361 gw->stop = widget;
1362 break;
1363
1364 case 'r': /* reload */
1365 widget = fbtk_create_button(toolbar,
1366 (xdir == 1)?xpos :
1367 xpos - reload.width,
1368 padding,
1369 reload.width,
1370 -padding,
1371 frame_col,
1372 &reload,
1373 fb_reload_click,
1374 gw->bw);
1375 gw->reload = widget;
1376 break;
1377
1378 case 't': /* throbber/activity indicator */
1379 widget = fbtk_create_bitmap(toolbar,
1380 (xdir == 1)?xpos :
1381 xpos - throbber0.width,
1382 padding,
1383 throbber0.width,
1384 -padding,
1385 frame_col,
1386 &throbber0);
1387 gw->throbber = widget;
1388 break;
1389
1390
1391 case 'u': /* url bar*/
1392 if (xdir == -1) {
1393 /* met the u going backwards add url
1394 * now we know available extent
1395 */
1396
1397 widget = fbtk_create_writable_text(toolbar,
1398 xlhs,
1399 padding,
1400 xpos - xlhs,
1401 -padding,
1402 FB_COLOUR_WHITE0xFFFFFFFF,
1403 FB_COLOUR_BLACK0xFF000000,
1404 true1,
1405 fb_url_enter,
1406 gw->bw);
1407
1408 fbtk_set_handler(widget,
1409 FBTK_CBT_POINTERENTER,
1410 fb_url_move, gw->bw);
1411
1412 gw->url = widget; /* keep reference */
1413
1414 /* toolbar is complete */
1415 xdir = 0;
1416 break;
1417 }
1418 /* met url going forwards, note position and
1419 * reverse direction
1420 */
1421 itmtype = toolbar_layout + strlen(toolbar_layout);
1422 xdir = -1;
1423 xlhs = xpos;
1424 xpos = (2 * fbtk_get_width(toolbar));
1425 widget = toolbar;
1426 break;
1427
1428 default:
1429 widget = NULL((void*)0);
1430 xdir = 0;
1431 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1433
, }; nslog__log(&_nslog_ctx, "Unknown element %c in toolbar layout"
, *itmtype); } } while(0)
1432 "Unknown element %c in toolbar layout",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1433
, }; nslog__log(&_nslog_ctx, "Unknown element %c in toolbar layout"
, *itmtype); } } while(0)
1433 *itmtype)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1433
, }; nslog__log(&_nslog_ctx, "Unknown element %c in toolbar layout"
, *itmtype); } } while(0)
;
1434 break;
1435
1436 }
1437
1438 if (widget != NULL((void*)0)) {
1439 xpos += (xdir * (fbtk_get_width(widget) + padding));
1440 }
1441
1442 NSLOG(netsurf, INFO, "xpos is %d", xpos)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1442
, }; nslog__log(&_nslog_ctx, "xpos is %d", xpos); } } while
(0)
;
1443
1444 itmtype += xdir;
1445 }
1446
1447 fbtk_set_mapping(toolbar, true1);
1448
1449 return toolbar;
1450}
1451
1452
1453/** Resize a toolbar.
1454 *
1455 * @param gw Parent window
1456 * @param toolbar_height The height in pixels of the toolbar
1457 * @param padding The padding in pixels round each element of the toolbar
1458 * @param toolbar_layout A string defining which buttons and controls
1459 * should be added to the toolbar. May be empty
1460 * string to disable the bar.
1461 */
1462static void
1463resize_toolbar(struct gui_window *gw,
1464 int toolbar_height,
1465 int padding,
1466 const char *toolbar_layout)
1467{
1468 fbtk_widget_t *widget;
1469
1470 int xpos; /* The position of the next widget. */
1471 int xlhs = 0; /* extent of the left hand side widgets */
1472 int xdir = 1; /* the direction of movement + or - 1 */
1473 const char *itmtype; /* type of the next item */
1474 int x = 0, y = 0, w = 0, h = 0;
1475
1476 if (gw->toolbar == NULL((void*)0)) {
1477 return;
1478 }
1479
1480 if (toolbar_layout == NULL((void*)0)) {
1481 toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT"blfsrutc";
1482 }
1483
1484 itmtype = toolbar_layout;
1485
1486 if (*itmtype == 0) {
1487 return;
1488 }
1489
1490 fbtk_set_pos_and_size(gw->toolbar, 0, 0, 0, toolbar_height);
1491
1492 xpos = padding;
1493
1494 /* loop proceeds creating widget on the left hand side until
1495 * it runs out of layout or encounters a url bar declaration
1496 * wherupon it works backwards from the end of the layout
1497 * untill the space left is for the url bar
1498 */
1499 while (itmtype >= toolbar_layout && xdir != 0) {
1500
1501 switch (*itmtype) {
1502 case 'b': /* back */
1503 widget = gw->back;
1504 x = (xdir == 1) ? xpos : xpos - left_arrow.width;
1505 y = padding;
1506 w = left_arrow.width;
1507 h = -padding;
1508 break;
1509
1510 case 'l': /* local history */
1511 widget = gw->history;
1512 x = (xdir == 1) ? xpos : xpos - history_image.width;
1513 y = padding;
1514 w = history_image.width;
1515 h = -padding;
1516 break;
1517
1518 case 'f': /* forward */
1519 widget = gw->forward;
1520 x = (xdir == 1) ? xpos : xpos - right_arrow.width;
1521 y = padding;
1522 w = right_arrow.width;
1523 h = -padding;
1524 break;
1525
1526 case 'c': /* close the current window */
1527 widget = gw->close;
1528 x = (xdir == 1) ? xpos : xpos - stop_image_g.width;
1529 y = padding;
1530 w = stop_image_g.width;
1531 h = -padding;
1532 break;
1533
1534 case 's': /* stop */
1535 widget = gw->stop;
1536 x = (xdir == 1) ? xpos : xpos - stop_image.width;
1537 y = padding;
1538 w = stop_image.width;
1539 h = -padding;
1540 break;
1541
1542 case 'r': /* reload */
1543 widget = gw->reload;
1544 x = (xdir == 1) ? xpos : xpos - reload.width;
1545 y = padding;
1546 w = reload.width;
1547 h = -padding;
1548 break;
1549
1550 case 't': /* throbber/activity indicator */
1551 widget = gw->throbber;
1552 x = (xdir == 1) ? xpos : xpos - throbber0.width;
1553 y = padding;
1554 w = throbber0.width;
1555 h = -padding;
1556 break;
1557
1558
1559 case 'u': /* url bar*/
1560 if (xdir == -1) {
1561 /* met the u going backwards add url
1562 * now we know available extent
1563 */
1564 widget = gw->url;
1565 x = xlhs;
1566 y = padding;
1567 w = xpos - xlhs;
1568 h = -padding;
1569
1570 /* toolbar is complete */
1571 xdir = 0;
1572 break;
1573 }
1574 /* met url going forwards, note position and
1575 * reverse direction
1576 */
1577 itmtype = toolbar_layout + strlen(toolbar_layout);
1578 xdir = -1;
1579 xlhs = xpos;
1580 w = fbtk_get_width(gw->toolbar);
1581 xpos = 2 * w;
1582 widget = gw->toolbar;
1583 break;
1584
1585 default:
1586 widget = NULL((void*)0);
1587 break;
1588
1589 }
1590
1591 if (widget != NULL((void*)0)) {
1592 if (widget != gw->toolbar)
1593 fbtk_set_pos_and_size(widget, x, y, w, h);
1594 xpos += xdir * (w + padding);
1595 }
1596
1597 itmtype += xdir;
1598 }
1599}
1600
1601/** Routine called when "stripped of focus" event occours for browser widget.
1602 *
1603 * @param widget The widget reciving "stripped of focus" event.
1604 * @param cbi The callback parameters.
1605 * @return The callback result.
1606 */
1607static int
1608fb_browser_window_strip_focus(fbtk_widget_t *widget, fbtk_callback_info *cbi)
1609{
1610 fbtk_set_caret(widget, false0, 0, 0, 0, NULL((void*)0));
1611
1612 return 0;
1613}
1614
1615static void
1616create_browser_widget(struct gui_window *gw, int toolbar_height, int furniture_width)
1617{
1618 struct browser_widget_s *browser_widget;
1619 browser_widget = calloc(1, sizeof(struct browser_widget_s));
1620
1621 gw->browser = fbtk_create_user(gw->window,
1622 0,
1623 toolbar_height,
1624 -furniture_width,
1625 -furniture_width,
1626 browser_widget);
1627
1628 fbtk_set_handler(gw->browser, FBTK_CBT_REDRAW, fb_browser_window_redraw, gw);
1629 fbtk_set_handler(gw->browser, FBTK_CBT_DESTROY, fb_browser_window_destroy, gw);
1630 fbtk_set_handler(gw->browser, FBTK_CBT_INPUT, fb_browser_window_input, gw);
1631 fbtk_set_handler(gw->browser, FBTK_CBT_CLICK, fb_browser_window_click, gw);
1632 fbtk_set_handler(gw->browser, FBTK_CBT_STRIP_FOCUS, fb_browser_window_strip_focus, gw);
1633 fbtk_set_handler(gw->browser, FBTK_CBT_POINTERMOVE, fb_browser_window_move, gw);
1634}
1635
1636static void
1637resize_browser_widget(struct gui_window *gw, int x, int y,
1638 int width, int height)
1639{
1640 fbtk_set_pos_and_size(gw->browser, x, y, width, height);
1641 browser_window_schedule_reformat(gw->bw);
1642}
1643
1644static void
1645create_normal_browser_window(struct gui_window *gw, int furniture_width)
1
[debug] analyzing from create_normal_browser_window
1646{
1647 fbtk_widget_t *widget;
1648 fbtk_widget_t *toolbar;
1649 int statusbar_width = 0;
1650 int toolbar_height = nsoption_int(fb_toolbar_size)(nsoptions[NSOPTION_fb_toolbar_size].value.i);
1651
1652 NSLOG(netsurf, INFO, "Normal window")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1652
, }; nslog__log(&_nslog_ctx, "Normal window"); } } while(
0)
;
1653
1654 gw->window = fbtk_create_window(fbtk, 0, 0, 0, 0, 0);
1655
1656 statusbar_width = nsoption_int(toolbar_status_size)(nsoptions[NSOPTION_toolbar_status_size].value.i) *
1657 fbtk_get_width(gw->window) / 10000;
1658
1659 /* toolbar */
1660 toolbar = create_toolbar(gw,
1661 toolbar_height,
1662 2,
1663 FB_FRAME_COLOUR0xFFDDDDDD,
1664 nsoption_charp(fb_toolbar_layout)(nsoptions[NSOPTION_fb_toolbar_layout].value.s));
1665 gw->toolbar = toolbar;
1666
1667 /* set the actually created toolbar height */
1668 if (toolbar != NULL((void*)0)) {
1669 toolbar_height = fbtk_get_height(toolbar);
1670 } else {
1671 toolbar_height = 0;
1672 }
1673
1674 /* status bar */
1675 gw->status = fbtk_create_text(gw->window,
1676 0,
1677 fbtk_get_height(gw->window) - furniture_width,
1678 statusbar_width, furniture_width,
1679 FB_FRAME_COLOUR0xFFDDDDDD, FB_COLOUR_BLACK0xFF000000,
1680 false0);
1681 fbtk_set_handler(gw->status, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL((void*)0));
1682
1683 NSLOG(netsurf, INFO, "status bar %p at %d,%d", gw->status,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1684
, }; nslog__log(&_nslog_ctx, "status bar %p at %d,%d", gw
->status, fbtk_get_absx(gw->status), fbtk_get_absy(gw->
status)); } } while(0)
1684 fbtk_get_absx(gw->status), fbtk_get_absy(gw->status))do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1684
, }; nslog__log(&_nslog_ctx, "status bar %p at %d,%d", gw
->status, fbtk_get_absx(gw->status), fbtk_get_absy(gw->
status)); } } while(0)
;
1685
1686 /* create horizontal scrollbar */
1687 gw->hscroll = fbtk_create_hscroll(gw->window,
1688 statusbar_width,
1689 fbtk_get_height(gw->window) - furniture_width,
1690 fbtk_get_width(gw->window) - statusbar_width - furniture_width,
1691 furniture_width,
1692 FB_SCROLL_COLOUR0xFFAAAAAA,
1693 FB_FRAME_COLOUR0xFFDDDDDD,
1694 fb_scroll_callback,
1695 gw);
1696
1697 /* fill bottom right area */
1698
1699 if (nsoption_bool(fb_osk)(nsoptions[NSOPTION_fb_osk].value.b) == true1) {
1700 widget = fbtk_create_text_button(gw->window,
2
Value stored to 'widget' is never read
1701 fbtk_get_width(gw->window) - furniture_width,
1702 fbtk_get_height(gw->window) - furniture_width,
1703 furniture_width,
1704 furniture_width,
1705 FB_FRAME_COLOUR0xFFDDDDDD, FB_COLOUR_BLACK0xFF000000,
1706 fb_osk_click,
1707 NULL((void*)0));
1708 widget = fbtk_create_button(gw->window,
1709 fbtk_get_width(gw->window) - furniture_width,
1710 fbtk_get_height(gw->window) - furniture_width,
1711 furniture_width,
1712 furniture_width,
1713 FB_FRAME_COLOUR0xFFDDDDDD,
1714 &osk_image,
1715 fb_osk_click,
1716 NULL((void*)0));
1717 } else {
1718 widget = fbtk_create_fill(gw->window,
1719 fbtk_get_width(gw->window) - furniture_width,
1720 fbtk_get_height(gw->window) - furniture_width,
1721 furniture_width,
1722 furniture_width,
1723 FB_FRAME_COLOUR0xFFDDDDDD);
1724
1725 fbtk_set_handler(widget, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL((void*)0));
1726 }
1727
1728 gw->bottom_right = widget;
1729
1730 /* create vertical scrollbar */
1731 gw->vscroll = fbtk_create_vscroll(gw->window,
1732 fbtk_get_width(gw->window) - furniture_width,
1733 toolbar_height,
1734 furniture_width,
1735 fbtk_get_height(gw->window) - toolbar_height - furniture_width,
1736 FB_SCROLL_COLOUR0xFFAAAAAA,
1737 FB_FRAME_COLOUR0xFFDDDDDD,
1738 fb_scroll_callback,
1739 gw);
1740
1741 /* browser widget */
1742 create_browser_widget(gw, toolbar_height, nsoption_int(fb_furniture_size)(nsoptions[NSOPTION_fb_furniture_size].value.i));
1743
1744 /* Give browser_window's user widget input focus */
1745 fbtk_set_focus(gw->browser);
1746}
1747
1748static void
1749resize_normal_browser_window(struct gui_window *gw, int furniture_width)
1750{
1751 bool_Bool resized;
1752 int width, height;
1753 int statusbar_width;
1754 int toolbar_height = fbtk_get_height(gw->toolbar);
1755
1756 /* Resize the main window widget */
1757 resized = fbtk_set_pos_and_size(gw->window, 0, 0, 0, 0);
1758 if (!resized)
1759 return;
1760
1761 width = fbtk_get_width(gw->window);
1762 height = fbtk_get_height(gw->window);
1763 statusbar_width = nsoption_int(toolbar_status_size)(nsoptions[NSOPTION_toolbar_status_size].value.i) * width / 10000;
1764
1765 resize_toolbar(gw, toolbar_height, 2,
1766 nsoption_charp(fb_toolbar_layout)(nsoptions[NSOPTION_fb_toolbar_layout].value.s));
1767 fbtk_set_pos_and_size(gw->status,
1768 0, height - furniture_width,
1769 statusbar_width, furniture_width);
1770 fbtk_reposition_hscroll(gw->hscroll,
1771 statusbar_width, height - furniture_width,
1772 width - statusbar_width - furniture_width,
1773 furniture_width);
1774 fbtk_set_pos_and_size(gw->bottom_right,
1775 width - furniture_width, height - furniture_width,
1776 furniture_width, furniture_width);
1777 fbtk_reposition_vscroll(gw->vscroll,
1778 width - furniture_width,
1779 toolbar_height, furniture_width,
1780 height - toolbar_height - furniture_width);
1781 resize_browser_widget(gw,
1782 0, toolbar_height,
1783 width - furniture_width,
1784 height - furniture_width - toolbar_height);
1785}
1786
1787static void gui_window_add_to_window_list(struct gui_window *gw)
1788{
1789 gw->next = NULL((void*)0);
1790 gw->prev = NULL((void*)0);
1791
1792 if (window_list == NULL((void*)0)) {
1793 window_list = gw;
1794 } else {
1795 window_list->prev = gw;
1796 gw->next = window_list;
1797 window_list = gw;
1798 }
1799}
1800
1801static void gui_window_remove_from_window_list(struct gui_window *gw)
1802{
1803 struct gui_window *list;
1804
1805 for (list = window_list; list != NULL((void*)0); list = list->next) {
1806 if (list != gw)
1807 continue;
1808
1809 if (list == window_list) {
1810 window_list = list->next;
1811 if (window_list != NULL((void*)0))
1812 window_list->prev = NULL((void*)0);
1813 } else {
1814 list->prev->next = list->next;
1815 if (list->next != NULL((void*)0)) {
1816 list->next->prev = list->prev;
1817 }
1818 }
1819 break;
1820 }
1821}
1822
1823
1824static struct gui_window *
1825gui_window_create(struct browser_window *bw,
1826 struct gui_window *existing,
1827 gui_window_create_flags flags)
1828{
1829 struct gui_window *gw;
1830
1831 gw = calloc(1, sizeof(struct gui_window));
1832
1833 if (gw == NULL((void*)0))
1834 return NULL((void*)0);
1835
1836 /* associate the gui window with the underlying browser window
1837 */
1838 gw->bw = bw;
1839
1840 create_normal_browser_window(gw, nsoption_int(fb_furniture_size)(nsoptions[NSOPTION_fb_furniture_size].value.i));
1841
1842 /* map and request redraw of gui window */
1843 fbtk_set_mapping(gw->window, true1);
1844
1845 /* Add it to the window list */
1846 gui_window_add_to_window_list(gw);
1847
1848 return gw;
1849}
1850
1851static void
1852gui_window_destroy(struct gui_window *gw)
1853{
1854 gui_window_remove_from_window_list(gw);
1855
1856 fbtk_destroy_widget(gw->window);
1857
1858 free(gw);
1859}
1860
1861
1862/**
1863 * Invalidates an area of a framebuffer browser window
1864 *
1865 * \param g The netsurf window being invalidated.
1866 * \param rect area to redraw or NULL for the entire window area
1867 * \return NSERROR_OK on success or appropriate error code
1868 */
1869static nserror
1870fb_window_invalidate_area(struct gui_window *g, const struct rect *rect)
1871{
1872 struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
1873
1874 if (rect != NULL((void*)0)) {
1875 fb_queue_redraw(g->browser,
1876 rect->x0 - bwidget->scrollx,
1877 rect->y0 - bwidget->scrolly,
1878 rect->x1 - bwidget->scrollx,
1879 rect->y1 - bwidget->scrolly);
1880 } else {
1881 fb_queue_redraw(g->browser,
1882 0,
1883 0,
1884 fbtk_get_width(g->browser),
1885 fbtk_get_height(g->browser));
1886 }
1887 return NSERROR_OK;
1888}
1889
1890static bool_Bool
1891gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
1892{
1893 struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
1894
1895 *sx = bwidget->scrollx;
1896 *sy = bwidget->scrolly;
1897
1898 return true1;
1899}
1900
1901/**
1902 * Set the scroll position of a framebuffer browser window.
1903 *
1904 * Scrolls the viewport to ensure the specified rectangle of the
1905 * content is shown. The framebuffer implementation scrolls the contents so
1906 * the specified point in the content is at the top of the viewport.
1907 *
1908 * \param gw gui_window to scroll
1909 * \param rect The rectangle to ensure is shown.
1910 * \return NSERROR_OK on success or apropriate error code.
1911 */
1912static nserror
1913gui_window_set_scroll(struct gui_window *gw, const struct rect *rect)
1914{
1915 struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
1916
1917 assert(bwidget)((bwidget) ? (void) (0) : __assert_fail ("bwidget", "frontends/framebuffer/gui.c"
, 1917, __extension__ __PRETTY_FUNCTION__))
;
1918
1919 widget_scroll_x(gw, rect->x0, true1);
1920 widget_scroll_y(gw, rect->y0, true1);
1921
1922 return NSERROR_OK;
1923}
1924
1925
1926/**
1927 * Find the current dimensions of a framebuffer browser window content area.
1928 *
1929 * \param gw The gui window to measure content area of.
1930 * \param width receives width of window
1931 * \param height receives height of window
1932 * \return NSERROR_OK on sucess and width and height updated.
1933 */
1934static nserror
1935gui_window_get_dimensions(struct gui_window *gw, int *width, int *height)
1936{
1937 *width = fbtk_get_width(gw->browser);
1938 *height = fbtk_get_height(gw->browser);
1939
1940 return NSERROR_OK;
1941}
1942
1943static void
1944gui_window_update_extent(struct gui_window *gw)
1945{
1946 int w, h;
1947 browser_window_get_extents(gw->bw, true1, &w, &h);
1948
1949 fbtk_set_scroll_parameters(gw->hscroll, 0, w,
1950 fbtk_get_width(gw->browser), 100);
1951
1952 fbtk_set_scroll_parameters(gw->vscroll, 0, h,
1953 fbtk_get_height(gw->browser), 100);
1954}
1955
1956static void
1957gui_window_set_status(struct gui_window *g, const char *text)
1958{
1959 fbtk_set_text(g->status, text);
1960}
1961
1962static void
1963gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
1964{
1965 switch (shape) {
1966 case GUI_POINTER_POINT:
1967 framebuffer_set_cursor(&hand_image);
1968 break;
1969
1970 case GUI_POINTER_CARET:
1971 framebuffer_set_cursor(&caret_image);
1972 break;
1973
1974 case GUI_POINTER_MENU:
1975 framebuffer_set_cursor(&menu_image);
1976 break;
1977
1978 case GUI_POINTER_PROGRESS:
1979 framebuffer_set_cursor(&progress_image);
1980 break;
1981
1982 case GUI_POINTER_MOVE:
1983 framebuffer_set_cursor(&move_image);
1984 break;
1985
1986 default:
1987 framebuffer_set_cursor(&pointer_image);
1988 break;
1989 }
1990}
1991
1992static nserror
1993gui_window_set_url(struct gui_window *g, nsurl *url)
1994{
1995 fbtk_set_text(g->url, nsurl_access(url));
1996 return NSERROR_OK;
1997}
1998
1999static void
2000throbber_advance(void *pw)
2001{
2002 struct gui_window *g = pw;
2003 struct fbtk_bitmap *image;
2004
2005 switch (g->throbber_index) {
2006 case 0:
2007 image = &throbber1;
2008 g->throbber_index = 1;
2009 break;
2010
2011 case 1:
2012 image = &throbber2;
2013 g->throbber_index = 2;
2014 break;
2015
2016 case 2:
2017 image = &throbber3;
2018 g->throbber_index = 3;
2019 break;
2020
2021 case 3:
2022 image = &throbber4;
2023 g->throbber_index = 4;
2024 break;
2025
2026 case 4:
2027 image = &throbber5;
2028 g->throbber_index = 5;
2029 break;
2030
2031 case 5:
2032 image = &throbber6;
2033 g->throbber_index = 6;
2034 break;
2035
2036 case 6:
2037 image = &throbber7;
2038 g->throbber_index = 7;
2039 break;
2040
2041 case 7:
2042 image = &throbber8;
2043 g->throbber_index = 0;
2044 break;
2045
2046 default:
2047 return;
2048 }
2049
2050 if (g->throbber_index >= 0) {
2051 fbtk_set_bitmap(g->throbber, image);
2052 framebuffer_schedule(100, throbber_advance, g);
2053 }
2054}
2055
2056static void
2057gui_window_start_throbber(struct gui_window *g)
2058{
2059 g->throbber_index = 0;
2060 framebuffer_schedule(100, throbber_advance, g);
2061}
2062
2063static void
2064gui_window_stop_throbber(struct gui_window *gw)
2065{
2066 gw->throbber_index = -1;
2067 fbtk_set_bitmap(gw->throbber, &throbber0);
2068
2069 fb_update_back_forward(gw);
2070
2071}
2072
2073static void
2074gui_window_remove_caret_cb(fbtk_widget_t *widget)
2075{
2076 struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
2077 int c_x, c_y, c_h;
2078
2079 if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
2080 /* browser window already had caret:
2081 * redraw its area to remove it first */
2082 fb_queue_redraw(widget,
2083 c_x - bwidget->scrollx,
2084 c_y - bwidget->scrolly,
2085 c_x + 1 - bwidget->scrollx,
2086 c_y + c_h - bwidget->scrolly);
2087 }
2088}
2089
2090static void
2091gui_window_place_caret(struct gui_window *g, int x, int y, int height,
2092 const struct rect *clip)
2093{
2094 struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
2095
2096 /* set new pos */
2097 fbtk_set_caret(g->browser, true1, x, y, height,
2098 gui_window_remove_caret_cb);
2099
2100 /* redraw new caret pos */
2101 fb_queue_redraw(g->browser,
2102 x - bwidget->scrollx,
2103 y - bwidget->scrolly,
2104 x + 1 - bwidget->scrollx,
2105 y + height - bwidget->scrolly);
2106}
2107
2108static void
2109gui_window_remove_caret(struct gui_window *g)
2110{
2111 int c_x, c_y, c_h;
2112
2113 if (fbtk_get_caret(g->browser, &c_x, &c_y, &c_h)) {
2114 /* browser window owns the caret, so can remove it */
2115 fbtk_set_caret(g->browser, false0, 0, 0, 0, NULL((void*)0));
2116 }
2117}
2118
2119/**
2120 * process miscellaneous window events
2121 *
2122 * \param gw The window receiving the event.
2123 * \param event The event code.
2124 * \return NSERROR_OK when processed ok
2125 */
2126static nserror
2127gui_window_event(struct gui_window *gw, enum gui_window_event event)
2128{
2129 switch (event) {
2130 case GW_EVENT_UPDATE_EXTENT:
2131 gui_window_update_extent(gw);
2132 break;
2133
2134 case GW_EVENT_REMOVE_CARET:
2135 gui_window_remove_caret(gw);
2136 break;
2137
2138 case GW_EVENT_START_THROBBER:
2139 gui_window_start_throbber(gw);
2140 break;
2141
2142 case GW_EVENT_STOP_THROBBER:
2143 gui_window_stop_throbber(gw);
2144 break;
2145
2146 default:
2147 break;
2148 }
2149 return NSERROR_OK;
2150}
2151
2152static struct gui_window_table framebuffer_window_table = {
2153 .create = gui_window_create,
2154 .destroy = gui_window_destroy,
2155 .invalidate = fb_window_invalidate_area,
2156 .get_scroll = gui_window_get_scroll,
2157 .set_scroll = gui_window_set_scroll,
2158 .get_dimensions = gui_window_get_dimensions,
2159 .event = gui_window_event,
2160
2161 .set_url = gui_window_set_url,
2162 .set_status = gui_window_set_status,
2163 .set_pointer = gui_window_set_pointer,
2164 .place_caret = gui_window_place_caret,
2165};
2166
2167
2168static struct gui_misc_table framebuffer_misc_table = {
2169 .schedule = framebuffer_schedule,
2170
2171 .quit = gui_quit,
2172};
2173
2174/**
2175 * Entry point from OS.
2176 *
2177 * /param argc The number of arguments in the string vector.
2178 * /param argv The argument string vector.
2179 * /return The return code to the OS
2180 */
2181int
2182main(int argc, char** argv)
2183{
2184 struct browser_window *bw;
2185 char *options;
2186 char *messages;
2187 nsurl *url;
2188 nserror ret;
2189 nsfb_t *nsfb;
2190 struct netsurf_table framebuffer_table = {
2191 .misc = &framebuffer_misc_table,
2192 .window = &framebuffer_window_table,
2193 .corewindow = framebuffer_core_window_table,
2194 .clipboard = framebuffer_clipboard_table,
2195 .fetch = framebuffer_fetch_table,
2196 .utf8 = framebuffer_utf8_table,
2197 .bitmap = framebuffer_bitmap_table,
2198 .layout = framebuffer_layout_table,
2199 };
2200
2201 ret = netsurf_register(&framebuffer_table);
2202 if (ret != NSERROR_OK) {
2203 die("NetSurf operation table failed registration");
2204 }
2205
2206 respaths = fb_init_resource_path(NETSURF_FB_RESPATH"${HOME}/.netsurf/:${NETSURFRES}:/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf:./frontends/framebuffer/res"":"NETSURF_FB_FONTPATH"/usr/share/fonts/truetype/dejavu:/usr/share/fonts/truetype/msttcorefonts");
2207
2208 /* initialise logging. Not fatal if it fails but not much we
2209 * can do about it either.
2210 */
2211 nslog_init(nslog_stream_configure, &argc, argv);
2212
2213 /* user options setup */
2214 ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
2215 if (ret != NSERROR_OK) {
2216 die("Options failed to initialise");
2217 }
2218 options = filepath_find(respaths, "Choices");
2219 nsoption_read(options, nsoptions);
2220 free(options);
2221 nsoption_commandline(&argc, argv, nsoptions);
2222
2223 /* message init */
2224 messages = filepath_find(respaths, "Messages");
2225 ret = messages_add_from_file(messages);
2226 free(messages);
2227 if (ret != NSERROR_OK) {
2228 fprintf(stderrstderr, "Message translations failed to load\n");
2229 }
2230
2231 /* common initialisation */
2232 ret = netsurf_init(NULL((void*)0));
2233 if (ret != NSERROR_OK) {
2234 die("NetSurf failed to initialise");
2235 }
2236
2237 /* Override, since we have no support for non-core SELECT menu */
2238 nsoption_set_bool(core_select_menu, true)nsoptions[NSOPTION_core_select_menu].value.b = 1;
2239
2240 if (process_cmdline(argc,argv) != true1)
2241 die("unable to process command line.\n");
2242
2243 nsfb = framebuffer_initialise(fename, fewidth, feheight, febpp);
2244 if (nsfb == NULL((void*)0))
2245 die("Unable to initialise framebuffer");
2246
2247 framebuffer_set_cursor(&pointer_image);
2248
2249 if (fb_font_init() == false0)
2250 die("Unable to initialise the font system");
2251
2252 fbtk = fbtk_init(nsfb);
2253
2254 fbtk_enable_oskb(fbtk);
2255
2256 urldb_load_cookies(nsoption_charp(cookie_file)(nsoptions[NSOPTION_cookie_file].value.s));
2257
2258 /* create an initial browser window */
2259
2260 NSLOG(netsurf, INFO, "calling browser_window_create")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 2260
, }; nslog__log(&_nslog_ctx, "calling browser_window_create"
); } } while(0)
;
2261
2262 ret = nsurl_create(feurl, &url);
2263 if (ret == NSERROR_OK) {
2264 ret = browser_window_create(BW_CREATE_HISTORY,
2265 url,
2266 NULL((void*)0),
2267 NULL((void*)0),
2268 &bw);
2269 nsurl_unref(url);
2270 }
2271 if (ret != NSERROR_OK) {
2272 fb_warn_user("Errorcode:", messages_get_errorcode(ret));
2273 } else {
2274 framebuffer_run();
2275
2276 browser_window_destroy(bw);
2277 }
2278
2279 netsurf_exit();
2280
2281 if (fb_font_finalise() == false0)
2282 NSLOG(netsurf, INFO, "Font finalisation failed.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/gui.c", sizeof("frontends/framebuffer/gui.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 2282
, }; nslog__log(&_nslog_ctx, "Font finalisation failed.")
; } } while(0)
;
2283
2284 /* finalise options */
2285 nsoption_finalise(nsoptions, nsoptions_default);
2286
2287 /* finalise logging */
2288 nslog_finalise();
2289
2290 return 0;
2291}
2292
2293void gui_resize(fbtk_widget_t *root, int width, int height)
2294{
2295 struct gui_window *gw;
2296 nsfb_t *nsfb = fbtk_get_nsfb(root);
2297
2298 /* Enforce a minimum */
2299 if (width < 300)
2300 width = 300;
2301 if (height < 200)
2302 height = 200;
2303
2304 if (framebuffer_resize(nsfb, width, height, febpp) == false0) {
2305 return;
2306 }
2307
2308 fbtk_set_pos_and_size(root, 0, 0, width, height);
2309
2310 fewidth = width;
2311 feheight = height;
2312
2313 for (gw = window_list; gw != NULL((void*)0); gw = gw->next) {
2314 resize_normal_browser_window(gw,
2315 nsoption_int(fb_furniture_size)(nsoptions[NSOPTION_fb_furniture_size].value.i));
2316 }
2317
2318 fbtk_request_redraw(root);
2319}
2320
2321
2322/*
2323 * Local Variables:
2324 * c-basic-offset:8
2325 * End:
2326 */