NetSurf
gui.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2015 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
3 * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
4 * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
5 *
6 * This file is part of NetSurf, http://www.netsurf-browser.org/
7 *
8 * NetSurf is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * NetSurf is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define __STDBOOL_H__ 1
22#include <assert.h>
23#include <ctype.h>
24#include <stdbool.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <limits.h>
30#include <sys/select.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33
34#include <Alert.h>
35#include <Application.h>
36#include <BeBuild.h>
37#include <FindDirectory.h>
38#include <Mime.h>
39#include <Path.h>
40#include <PathFinder.h>
41#include <Resources.h>
42#include <Roster.h>
43#include <Screen.h>
44#include <String.h>
45#ifdef __HAIKU__
46#include <LocaleRoster.h>
47#endif
48
49extern "C" {
50
51#include "utils/nsoption.h"
52#include "utils/filename.h"
53#include "utils/log.h"
54#include "utils/messages.h"
55#include "utils/url.h"
56#include "utils/corestrings.h"
57#include "utils/utf8.h"
58#include "utils/utils.h"
59#include "utils/nsurl.h"
60#include "netsurf/misc.h"
61#include "netsurf/clipboard.h"
62#include "netsurf/search.h"
63#include "netsurf/fetch.h"
64#include "netsurf/netsurf.h"
65#include "netsurf/content.h"
67#include "netsurf/cookie_db.h"
68#include "netsurf/url_db.h"
69#include "content/fetch.h"
70
71}
72
73#include "beos/gui.h"
74#include "beos/gui_options.h"
75//#include "beos/completion.h"
76#include "beos/window.h"
77#include "beos/throbber.h"
78#include "beos/filetype.h"
79#include "beos/download.h"
80#include "beos/schedule.h"
81#include "beos/fetch_rsrc.h"
82#include "beos/scaffolding.h"
83#include "beos/bitmap.h"
84#include "beos/font.h"
85
86//TODO: use resources
87// enable using resources instead of files
88#define USE_RESOURCES 1
89
90bool nsbeos_done = false;
91
92bool replicated = false; /**< if we are running as a replicant */
93
96
98
99BWindow *wndAbout;
100BWindow *wndWarning;
101//GladeXML *gladeWindows;
102BWindow *wndTooltip;
103//beosLabel *labelTooltip;
104BFilePanel *wndOpenFile;
105
106static thread_id sBAppThreadID;
107
108static BMessage *gFirstRefsReceived = NULL;
109
110static int sEventPipe[2];
111
112// #pragma mark - class NSBrowserFrameView
113
114
115/* exported function defined in beos/gui.h */
116nserror beos_warn_user(const char *warning, const char *detail)
117{
118 NSLOG(netsurf, INFO, "warn_user: %s (%s)", warning, detail);
119 BAlert *alert;
120 BString text(warning);
121 if (detail)
122 text << ":\n" << detail;
123
124 alert = new BAlert("NetSurf Warning", text.String(), "Debug", "Ok",
125 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
126 if (alert->Go() < 1) {
127 debugger("warn_user");
128 }
129
130 return NSERROR_OK;
131}
132
134 : BApplication("application/x-vnd.NetSurf")
135{
136}
137
138
140{
141}
142
143
144void
146{
147 switch (message->what) {
148 case B_REFS_RECEIVED:
150 // messages for top-level
151 // we'll just send them to the first window
152 case 'back':
153 case 'forw':
154 case 'stop':
155 case 'relo':
156 case 'home':
157 case 'urlc':
158 case 'urle':
159 case 'sear':
160 case 'menu':
161 // NetPositive messages
162 case B_NETPOSITIVE_OPEN_URL:
163 case B_NETPOSITIVE_BACK:
164 case B_NETPOSITIVE_FORWARD:
165 case B_NETPOSITIVE_HOME:
166 case B_NETPOSITIVE_RELOAD:
167 case B_NETPOSITIVE_STOP:
168 case B_NETPOSITIVE_DOWN:
169 case B_NETPOSITIVE_UP:
170 //DetachCurrentMessage();
171 //nsbeos_pipe_message(message, this, fGuiWindow);
172 break;
173 default:
174 BApplication::MessageReceived(message);
175 }
176}
177
178
179void
181{
183 if (!win) {
184 return;
185 }
186 win->Unlock();
187 BMessage *message = DetachCurrentMessage();
188 nsbeos_pipe_message_top(message, win, win->Scaffolding());
189}
190
191
192void
194{
195 DetachCurrentMessage();
197 if (!win) {
198 gFirstRefsReceived = message;
199 return;
200 }
201 win->Unlock();
202 nsbeos_pipe_message_top(message, win, win->Scaffolding());
203}
204
205
206void
208{
209 nsbeos_pipe_message(new BMessage(B_ABOUT_REQUESTED), NULL, NULL);
210}
211
212
213bool
215{
216 // let it notice it
217 nsbeos_pipe_message(new BMessage(B_QUIT_REQUESTED), NULL, NULL);
218 // we'll let the main thread Quit() ourselves when it's done.
219 return false;
220}
221
222
223// #pragma mark - implementation
224
225
226
227/* realpath fallback on R5 */
228#if !defined(__HAIKU__) && !defined(B_BEOS_VERSION_DANO)
229extern "C" char *realpath(const char *f, char *buf);
230char *realpath(const char *f, char *buf)
231{
232 BPath path(f, NULL, true);
233 if (path.InitCheck() < 0) {
234 strncpy(buf, f, MAXPATHLEN);
235 return NULL;
236 }
237 //printf("RP: '%s'\n", path.Path());
238 strncpy(buf, path.Path(), MAXPATHLEN);
239 return buf;
240}
241#endif
242
243/* finds the NetSurf binary image ID and path
244 *
245 */
247{
248 image_info info;
249 int32 cookie = 0;
250 while (get_next_image_info(0, &cookie, &info) == B_OK) {
251//fprintf(stderr, "%p <> %p, %p\n", (char *)&find_app_resources, (char *)info.text, (char *)info.text + info.text_size);
252 if (((char *)&nsbeos_find_app_path >= (char *)info.text)
253 && ((char *)&nsbeos_find_app_path < (char *)info.text + info.text_size)) {
254//fprintf(stderr, "match\n");
255 if (path) {
256 memset(path, 0, B_PATH_NAME_LENGTH);
257 strncpy(path, info.name, B_PATH_NAME_LENGTH-1);
258 }
259 return info.id;
260 }
261 }
262 return B_ERROR;
263}
264
265/**
266 * Locate a shared resource file by searching known places in order.
267 *
268 * Search order is: ~/config/settings/NetSurf/, ~/.netsurf/, $NETSURFRES/
269 * (where NETSURFRES is an environment variable), and finally the path
270 * specified by the macro at the top of this file.
271 *
272 * \param buf buffer to write to. must be at least PATH_MAX chars
273 * \param filename file to look for
274 * \param def default to return if file not found
275 * \return path to resource.
276 */
277char *find_resource(char *buf, const char *filename, const char *def)
278{
279 const char *cdir = NULL;
280 status_t err;
281 BPath path;
282 char t[PATH_MAX];
283
284 err = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
285 path.Append("NetSurf");
286 if (err >= B_OK)
287 cdir = path.Path();
288 if (cdir != NULL) {
289 strcpy(t, cdir);
290 strcat(t, "/");
291 strcat(t, filename);
292 realpath(t, buf);
293 if (access(buf, R_OK) == 0)
294 return buf;
295 }
296
297 cdir = getenv("HOME");
298 if (cdir != NULL) {
299 strcpy(t, cdir);
300 strcat(t, "/.netsurf/");
301 strcat(t, filename);
302 realpath(t, buf);
303 if (access(buf, R_OK) == 0)
304 return buf;
305 }
306
307 cdir = getenv("NETSURFRES");
308
309 if (cdir != NULL) {
310 realpath(cdir, buf);
311 strcat(buf, "/");
312 strcat(buf, filename);
313 if (access(buf, R_OK) == 0)
314 return buf;
315 }
316
317
318 BPathFinder f((void*)find_resource);
319
320 BPath p;
321 if (f.FindPath(B_FIND_PATH_APPS_DIRECTORY, "netsurf/res", p) == B_OK) {
322 strcpy(t, p.Path());
323 strcat(t, filename);
324 realpath(t, buf);
325 if (access(buf, R_OK) == 0)
326 return buf;
327 }
328
329 if (def[0] == '%') {
330 snprintf(t, PATH_MAX, "%s%s", path.Path(), def + 1);
331 if (realpath(t, buf) == NULL) {
332 strcpy(buf, t);
333 }
334 } else if (def[0] == '~') {
335 snprintf(t, PATH_MAX, "%s%s", getenv("HOME"), def + 1);
336 if (realpath(t, buf) == NULL) {
337 strcpy(buf, t);
338 }
339 } else {
340 if (realpath(def, buf) == NULL) {
341 strcpy(buf, def);
342 }
343 }
344
345 return buf;
346}
347
348/**
349 * Check that ~/.netsurf/ exists, and if it doesn't, create it.
350 */
351static void check_homedir(void)
352{
353 status_t err;
354
355 BPath path;
356 err = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
357
358 if (err < B_OK) {
359 /* we really can't continue without a home directory. */
360 NSLOG(netsurf, INFO,
361 "Can't find user settings directory - nowhere to store state!");
362 die("NetSurf needs to find the user settings directory in order to run.\n");
363 }
364
365 path.Append("NetSurf");
366 err = create_directory(path.Path(), 0644);
367 if (err < B_OK) {
368 NSLOG(netsurf, INFO, "Unable to create %s", path.Path());
369 die("NetSurf could not create its settings directory.\n");
370 }
371}
372
373static int32 bapp_thread(void *arg)
374{
375 be_app->Lock();
376 be_app->Run();
377 return 0;
378}
379
380static nsurl *gui_get_resource_url(const char *path)
381{
382 nsurl *url = NULL;
383 BString u("rsrc:///");
384
385 /* default.css -> beosdefault.css */
386 if (strcmp(path, "default.css") == 0)
387 path = "beosdefault.css";
388
389 /* favicon.ico -> favicon.png */
390 if (strcmp(path, "favicon.ico") == 0)
391 path = "favicon.png";
392
393 u << path;
394 NSLOG(netsurf, INFO, "(%s) -> '%s'\n", path, u.String());
395 nsurl_create(u.String(), &url);
396 return url;
397}
398
399
400
401#if !defined(__HAIKU__) && !defined(B_BEOS_VERSION_DANO)
402/* more ui_colors, R5 only had a few defined... */
403#define B_PANEL_TEXT_COLOR ((color_which)10)
404#define B_DOCUMENT_BACKGROUND_COLOR ((color_which)11)
405#define B_DOCUMENT_TEXT_COLOR ((color_which)12)
406#define B_CONTROL_BACKGROUND_COLOR ((color_which)13)
407#define B_CONTROL_TEXT_COLOR ((color_which)14)
408#define B_CONTROL_BORDER_COLOR ((color_which)15)
409#define B_CONTROL_HIGHLIGHT_COLOR ((color_which)16)
410#define B_NAVIGATION_BASE_COLOR ((color_which)4)
411#define B_NAVIGATION_PULSE_COLOR ((color_which)17)
412#define B_SHINE_COLOR ((color_which)18)
413#define B_SHADOW_COLOR ((color_which)19)
414#define B_MENU_SELECTED_BORDER_COLOR ((color_which)9)
415#define B_TOOL_TIP_BACKGROUND_COLOR ((color_which)20)
416#define B_TOOL_TIP_TEXT_COLOR ((color_which)21)
417#define B_SUCCESS_COLOR ((color_which)100)
418#define B_FAILURE_COLOR ((color_which)101)
419#define B_MENU_SELECTED_BACKGROUND_COLOR B_MENU_SELECTION_BACKGROUND_COLOR
420#define B_RANDOM_COLOR ((color_which)0x80000000)
421#define B_MICHELANGELO_FAVORITE_COLOR ((color_which)0x80000001)
422#define B_DSANDLER_FAVORITE_SKY_COLOR ((color_which)0x80000002)
423#define B_DSANDLER_FAVORITE_INK_COLOR ((color_which)0x80000003)
424#define B_DSANDLER_FAVORITE_SHOES_COLOR ((color_which)0x80000004)
425#define B_DAVE_BROWN_FAVORITE_COLOR ((color_which)0x80000005)
426#endif
427#if defined(B_BEOS_VERSION_DANO)
428#define B_TOOL_TIP_BACKGROUND_COLOR B_TOOLTIP_BACKGROUND_COLOR
429#define B_TOOL_TIP_TEXT_COLOR B_TOOLTIP_TEXT_COLOR
430#define
431#endif
432#define NOCOL ((color_which)0)
433
434/**
435 * set option from pen
436 */
437static nserror
439 color_which ui,
440 enum nsoption_e option,
441 colour def_colour)
442{
443 if (ui != NOCOL) {
444 rgb_color c;
445 if (ui == B_DESKTOP_COLOR) {
446 BScreen s;
447 c = s.DesktopColor();
448 } else {
449 c = ui_color(ui);
450 }
451
452 def_colour = ((((uint32_t)c.blue << 16) & 0xff0000) |
453 ((c.green << 8) & 0x00ff00) |
454 ((c.red) & 0x0000ff));
455 }
456
457 opts[option].value.c = def_colour;
458
459 return NSERROR_OK;
460}
461
462/**
463 * Set option defaults for beos frontend
464 *
465 * @param defaults The option table to update.
466 * @return error status.
467 */
469{
470 /* set system colours for beos ui */
471 struct {
472 color_which ui;
473 colour dflt;
474 enum nsoption_e option;
475 } entries[] = {
476 {
478 0x00000000,
479 NSOPTION_sys_colour_AccentColor
480 }, {
482 0x00000000,
483 NSOPTION_sys_colour_AccentColorText
484 }, {
486 0x00000000,
487 NSOPTION_sys_colour_ActiveText
488 }, {
490 0x00000000,
491 NSOPTION_sys_colour_ButtonBorder
492 }, {
494 0x00aaaaaa,
495 NSOPTION_sys_colour_ButtonFace
496 }, {
498 0x00000000,
499 NSOPTION_sys_colour_ButtonText
500 }, {
502 0x00aaaaaa,
503 NSOPTION_sys_colour_Canvas
504 }, {
506 0x00000000,
507 NSOPTION_sys_colour_CanvasText
508 }, {
510 0x00000000,
511 NSOPTION_sys_colour_Field
512 }, {
514 0x00000000,
515 NSOPTION_sys_colour_FieldText
516 }, {
517 NOCOL,
518 0x00777777,
519 NSOPTION_sys_colour_GrayText
520 }, {
521 NOCOL,
522 0x00ee0000,
523 NSOPTION_sys_colour_Highlight
524 }, {
525 NOCOL,
526 0x00000000,
527 NSOPTION_sys_colour_HighlightText
528 }, {
529 B_LINK_TEXT_COLOR,
530 0x00000000,
531 NSOPTION_sys_colour_LinkText
532 }, {
533 B_CONTROL_MARK_COLOR,
534 0x00000000,
535 NSOPTION_sys_colour_Mark
536 }, {
538 0x00000000,
539 NSOPTION_sys_colour_MarkText
540 }, {
542 0x00000000,
543 NSOPTION_sys_colour_SelectedItem
544 }, {
546 0x00000000,
547 NSOPTION_sys_colour_SelectedItemText
548 }, {
549 B_LINK_VISITED_COLOR,
550 0x00000000,
551 NSOPTION_sys_colour_VisitedText
552 }, {
553 NOCOL,
554 0x00000000,
556 },
557 };
558
559 int idx;
560
561 for (idx=0; entries[idx].option != NSOPTION_LISTEND; idx++) {
563 entries[idx].ui,
564 entries[idx].option,
565 entries[idx].dflt);
566 }
567
568 return NSERROR_OK;
569}
570
572{
574}
575
576/**
577 * Ensures output logging stream is correctly configured
578 */
579static bool nslog_stream_configure(FILE *fptr)
580{
581 /* set log stream to be non-buffering */
582 setbuf(fptr, NULL);
583
584 return true;
585}
586
587static BPath get_messages_path()
588{
589 BPathFinder f((void*)get_messages_path);
590
591 BPath p;
592 f.FindPath(B_FIND_PATH_APPS_DIRECTORY, "netsurf/res", p);
593 BString lang;
594#ifdef __HAIKU__
595 BMessage preferredLangs;
596 if (BLocaleRoster::Default()->GetPreferredLanguages(&preferredLangs) == B_OK) {
597 preferredLangs.FindString("language", 0, &lang);
598 lang.Truncate(2);
599 }
600#endif
601 if (lang.Length() < 1) {
602 lang.SetTo(getenv("LC_MESSAGES"));
603 lang.Truncate(2);
604 }
605 BDirectory d(p.Path());
606 if (!d.Contains(lang.String(), B_DIRECTORY_NODE))
607 lang = "en";
608 p.Append(lang.String());
609 p.Append("Messages");
610 return p;
611}
612
613
614static void gui_init(int argc, char** argv)
615{
616 const char *addr;
617 nsurl *url;
618 nserror error;
619 char buf[PATH_MAX];
620
621 if (pipe(sEventPipe) < 0)
622 return;
623 if (!replicated) {
624 sBAppThreadID = spawn_thread(bapp_thread, "BApplication(NetSurf)", B_NORMAL_PRIORITY, (void *)find_thread(NULL));
625 if (sBAppThreadID < B_OK)
626 return; /* #### handle errors */
627 if (resume_thread(sBAppThreadID) < B_OK)
628 return;
629 }
630
632
634
636
637 // make sure the cache dir exists
638 create_directory(TEMP_FILENAME_PREFIX, 0700);
639
640 //nsbeos_completion_init();
641
642
643 /* This is an ugly hack to just get the new-style throbber going.
644 * It, along with the PNG throbber loader, need making more generic.
645 */
646 {
647#define STROF(n) #n
648#define FIND_THROB(n) filenames[(n)] = \
649 "throbber/throbber" STROF(n) ".png";
650 const char *filenames[9];
651 FIND_THROB(0);
652 FIND_THROB(1);
653 FIND_THROB(2);
654 FIND_THROB(3);
655 FIND_THROB(4);
656 FIND_THROB(5);
657 FIND_THROB(6);
658 FIND_THROB(7);
659 FIND_THROB(8);
661 filenames[0], filenames[1], filenames[2], filenames[3],
662 filenames[4], filenames[5], filenames[6], filenames[7],
663 filenames[8]);
664#undef FIND_THROB
665#undef STROF
666 }
667
668 if (nsbeos_throbber == NULL)
669 die("Unable to load throbber image.\n");
670
671 find_resource(buf, "Choices", "%/Choices");
672 NSLOG(netsurf, INFO, "Using '%s' as Preferences file", buf);
673 options_file_location = strdup(buf);
674 nsoption_read(buf, NULL);
675
676
677 /* check what the font settings are, setting them to a default font
678 * if they're not set - stops Pango whinging
679 */
680#define SETFONTDEFAULT(OPTION,y) if (nsoption_charp(OPTION) == NULL) nsoption_set_charp(OPTION, strdup((y)))
681
682 //XXX: use be_plain_font & friends, when we can check if font is serif or not.
683/*
684 font_family family;
685 font_style style;
686 be_plain_font->GetFamilyAndStyle(&family, &style);
687 SETFONTDEFAULT(font_sans, family);
688 SETFONTDEFAULT(font_serif, family);
689 SETFONTDEFAULT(font_mono, family);
690 SETFONTDEFAULT(font_cursive, family);
691 SETFONTDEFAULT(font_fantasy, family);
692*/
693#ifdef __HAIKU__
694 SETFONTDEFAULT(font_sans, "DejaVu Sans");
695 SETFONTDEFAULT(font_serif, "DejaVu Serif");
696 SETFONTDEFAULT(font_mono, "DejaVu Mono");
697 SETFONTDEFAULT(font_cursive, "DejaVu Sans");
698 SETFONTDEFAULT(font_fantasy, "DejaVu Sans");
699#else
700 SETFONTDEFAULT(font_sans, "Bitstream Vera Sans");
701 SETFONTDEFAULT(font_serif, "Bitstream Vera Serif");
702 SETFONTDEFAULT(font_mono, "Bitstream Vera Sans Mono");
703 SETFONTDEFAULT(font_cursive, "Bitstream Vera Serif");
704 SETFONTDEFAULT(font_fantasy, "Bitstream Vera Serif");
705#endif
706
708
709 /* We don't yet have an implementation of "select" form elements (they should use a popup menu)
710 * So we use the cross-platform code instead. */
711 nsoption_set_bool(core_select_menu, true);
712
713 if (nsoption_charp(cookie_file) == NULL) {
714 find_resource(buf, "Cookies", "%/Cookies");
715 NSLOG(netsurf, INFO, "Using '%s' as Cookies file", buf);
716 nsoption_set_charp(cookie_file, strdup(buf));
717 }
718 if (nsoption_charp(cookie_jar) == NULL) {
719 find_resource(buf, "Cookies", "%/Cookies");
720 NSLOG(netsurf, INFO, "Using '%s' as Cookie Jar file", buf);
721 nsoption_set_charp(cookie_jar, strdup(buf));
722 }
723 if ((nsoption_charp(cookie_file) == NULL) ||
724 (nsoption_charp(cookie_jar) == NULL))
725 die("Failed initialising cookie options");
726
727 if (nsoption_charp(url_file) == NULL) {
728 find_resource(buf, "URLs", "%/URLs");
729 NSLOG(netsurf, INFO, "Using '%s' as URL file", buf);
730 nsoption_set_charp(url_file, strdup(buf));
731 }
732
733 if (nsoption_charp(ca_path) == NULL) {
734 find_resource(buf, "certs", "/etc/ssl/certs");
735 NSLOG(netsurf, INFO, "Using '%s' as certificate path", buf);
736 nsoption_set_charp(ca_path, strdup(buf));
737 }
738
739 //find_resource(buf, "mime.types", "/etc/mime.types");
741
742 urldb_load(nsoption_charp(url_file));
744
745 //nsbeos_download_initialise();
746
747 if (!replicated)
748 be_app->Unlock();
749
750 if (argc > 1) {
751 addr = argv[1];
752 } else if (nsoption_charp(homepage_url) != NULL) {
753 addr = nsoption_charp(homepage_url);
754 } else {
755 addr = NETSURF_HOMEPAGE;
756 }
757
758 /* create an initial browser window */
759 error = nsurl_create(addr, &url);
760 if (error == NSERROR_OK) {
761 error = browser_window_create(
763 url,
764 NULL,
765 NULL,
766 NULL);
767 nsurl_unref(url);
768 }
769 if (error != NSERROR_OK) {
771 }
772
773 if (gFirstRefsReceived) {
774 // resend the refs we got before having a window to send them to
775 be_app_messenger.SendMessage(gFirstRefsReceived);
776 delete gFirstRefsReceived;
777 gFirstRefsReceived = NULL;
778 }
779
780}
781
782
783
784
785void nsbeos_pipe_message(BMessage *message, BView *_this, struct gui_window *gui)
786{
787 if (message == NULL) {
788 fprintf(stderr, "%s(NULL)!\n", __FUNCTION__);
789 return;
790 }
791 if (_this)
792 message->AddPointer("View", _this);
793 if (gui)
794 message->AddPointer("gui_window", gui);
795 write(sEventPipe[1], &message, sizeof(void *));
796}
797
798
799void nsbeos_pipe_message_top(BMessage *message, BWindow *_this, struct beos_scaffolding *scaffold)
800{
801 if (message == NULL) {
802 fprintf(stderr, "%s(NULL)!\n", __FUNCTION__);
803 return;
804 }
805 if (_this)
806 message->AddPointer("Window", _this);
807 if (scaffold)
808 message->AddPointer("scaffolding", scaffold);
809 write(sEventPipe[1], &message, sizeof(void *));
810}
811
812
814{
815 fd_set read_fd_set, write_fd_set, exc_fd_set;
816 int max_fd;
817 struct timeval timeout;
818 unsigned int fd_count = 0;
819 bigtime_t next_schedule = 0;
820
821 /* run the scheduler */
822 schedule_run();
823
824 /* get any active fetcher fd */
825 fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd);
826
827 // our own event pipe
828 FD_SET(sEventPipe[0], &read_fd_set);
829
830 // max of all the fds in the set, plus one for select()
831 max_fd = MAX(max_fd, sEventPipe[0]) + 1;
832
833 // compute schedule timeout
834 if (earliest_callback_timeout != B_INFINITE_TIMEOUT) {
835 next_schedule = earliest_callback_timeout - system_time();
836 } else {
837 next_schedule = earliest_callback_timeout;
838 }
839
840 // we're quite late already...
841 if (next_schedule < 0)
842 next_schedule = 0;
843
844 timeout.tv_sec = (long)(next_schedule / 1000000LL);
845 timeout.tv_usec = (long)(next_schedule % 1000000LL);
846
847 NSLOG(netsurf, DEEPDEBUG,
848 "gui_poll: select(%d, ..., %Ldus",
849 max_fd, next_schedule);
850 fd_count = select(max_fd, &read_fd_set, &write_fd_set, &exc_fd_set,
851 &timeout);
852 NSLOG(netsurf, DEEPDEBUG, "select: %d\n", fd_count);
853
854 if (fd_count > 0 && FD_ISSET(sEventPipe[0], &read_fd_set)) {
855 BMessage *message;
856 int len = read(sEventPipe[0], &message, sizeof(void *));
857 NSLOG(netsurf, DEEPDEBUG, "gui_poll: BMessage ? %d read", len);
858 if (len == sizeof(void *)) {
859 NSLOG(netsurf, DEEPDEBUG,
860 "gui_poll: BMessage.what %-4.4s\n",
861 (char *)&(message->what));
862 nsbeos_dispatch_event(message);
863 }
864 }
865}
866
867
868static void gui_quit(void)
869{
871 urldb_save(nsoption_charp(url_file));
872 //options_save_tree(hotlist,nsoption_charp(hotlist_file),messages_get("TreeHotlist"));
873
874 free(nsoption_charp(cookie_file));
875 free(nsoption_charp(cookie_jar));
878}
879
880static char *url_to_path(const char *url)
881{
882 char *url_path;
883 char *path = NULL;
884
885 if (url_unescape(url, 0, NULL, &url_path) == NSERROR_OK) {
886 /* return the absolute path including leading / */
887 path = strdup(url_path + (FILE_SCHEME_PREFIX_LEN - 1));
888 free(url_path);
889 }
890
891 return path;
892}
893
894/**
895 * Send the source of a content to a text editor.
896 */
897
899{
900 char *temp_name;
901 bool done = false;
902 BPath path;
903 status_t err;
904 size_t size;
905 const uint8_t *source;
906
907 source = content_get_source_data(content, &size);
908
909 if (!content || !source) {
910 beos_warn_user("MiscError", "No document source");
911 return;
912 }
913
914 /* try to load local files directly. */
916 if (temp_name) {
917 path.SetTo(temp_name);
918 BEntry entry;
919 if (entry.SetTo(path.Path()) >= B_OK
920 && entry.Exists() && entry.IsFile())
921 done = true;
922 }
923 if (!done) {
924 /* We cannot release the requested filename until after it
925 * has finished being used. As we can't easily find out when
926 * this is, we simply don't bother releasing it and simply
927 * allow it to be re-used next time NetSurf is started. The
928 * memory overhead from doing this is under 1 byte per
929 * filename. */
930 BString filename(filename_request());
931 if (filename.IsEmpty()) {
932 beos_warn_user("NoMemory", 0);
933 return;
934 }
935
936 lwc_string *mime = content_get_mime_type(content);
937
938 /* provide an extension, as Pe still doesn't sniff the MIME */
939 if (mime) {
940 BMimeType type(lwc_string_data(mime));
941 BMessage extensions;
942 if (type.GetFileExtensions(&extensions) == B_OK) {
943 BString ext;
944 if (extensions.FindString("extensions", &ext) == B_OK)
945 filename << "." << ext;
946 }
947 /* we unref(mime) later on, we just leak on error */
948 }
949
951 path.Append(filename.String());
952 BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE);
953 err = file.InitCheck();
954 if (err < B_OK) {
955 beos_warn_user("IOError", strerror(err));
956 return;
957 }
958 err = file.Write(source, size);
959 if (err < B_OK) {
960 beos_warn_user("IOError", strerror(err));
961 return;
962 }
963
964 if (mime) {
965 file.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0LL,
966 lwc_string_data(mime), lwc_string_length(mime) + 1);
967 lwc_string_unref(mime);
968 }
969
970 }
971
972 entry_ref ref;
973 if (get_ref_for_path(path.Path(), &ref) < B_OK)
974 return;
975
976 BMessage m(B_REFS_RECEIVED);
977 m.AddRef("refs", &ref);
978
979
980 // apps to try
981 const char *editorSigs[] = {
982 "text/x-source-code",
983 "application/x-vnd.beunited.pe",
984 "application/x-vnd.XEmacs",
985 "application/x-vnd.Haiku-StyledEdit",
986 "application/x-vnd.Be-STEE",
987 "application/x-vnd.yT-STEE",
988 NULL
989 };
990 int i;
991 for (i = 0; editorSigs[i]; i++) {
992 team_id team = -1;
993 {
994 BMessenger msgr(editorSigs[i], team);
995 if (msgr.SendMessage(&m) >= B_OK)
996 break;
997
998 }
999
1000 err = be_roster->Launch(editorSigs[i], (BMessage *)&m, &team);
1001 if (err >= B_OK || err == B_ALREADY_RUNNING)
1002 break;
1003 }
1004}
1005
1006/**
1007 * Broadcast an URL that we can't handle.
1008 */
1009
1010static nserror gui_launch_url(struct nsurl *url)
1011{
1012 status_t status;
1013 // try to open it as an URI
1014 BString mimeType = "application/x-vnd.Be.URL.";
1015 BString arg(nsurl_access(url));
1016
1017 mimeType.Append(arg, arg.FindFirst(":"));
1018
1019 // special case, text/x-email is used traditionally
1020 // use it instead
1021 if (arg.IFindFirst("mailto:") == 0)
1022 mimeType = "text/x-email";
1023
1024 // the protocol should be alphanum
1025 // we just check if it's registered
1026 // if not there is likely no supporting app anyway
1027 if (!BMimeType::IsValid(mimeType.String()))
1029 char *args[2] = { (char *)nsurl_access(url), NULL };
1030 status = be_roster->Launch(mimeType.String(), 1, args);
1031 if (status < B_OK)
1032 beos_warn_user("Cannot launch url", strerror(status));
1033 return NSERROR_OK;
1034}
1035
1036
1037
1038void die(const char * const error)
1039{
1040 fprintf(stderr, "%s", error);
1041 BAlert *alert;
1042 BString text("Cannot continue:\n");
1043 text << error;
1044
1045 alert = new BAlert("NetSurf Error", text.String(), "Debug", "Ok", NULL,
1046 B_WIDTH_AS_USUAL, B_STOP_ALERT);
1047 if (alert->Go() < 1)
1048 debugger("die");
1049
1050 exit(EXIT_FAILURE);
1051}
1052
1053
1057 NULL, // get_resource_data
1058 NULL, // release_resource_data
1059 NULL, // fetch_mimetype
1060 NULL, // socket open
1061 NULL, // socket close
1062};
1063
1066 gui_quit,
1068 NULL, //401login
1069 NULL, // pdf_password (if we have Haru support)
1070 NULL, // present_cookies
1071};
1072
1073
1074/** Normal entry point from OS */
1075int main(int argc, char** argv)
1076{
1077 nserror ret;
1078 BPath options;
1079 struct netsurf_table beos_table = {
1082 NULL, /* corewindow */
1086 NULL, /* use POSIX file */
1087 NULL, /* default utf8 */
1088 NULL, /* default search */
1089 NULL, /* default web search */
1090 NULL, /* default low level cache persistant storage */
1093 };
1094
1095 ret = netsurf_register(&beos_table);
1096 if (ret != NSERROR_OK) {
1097 die("NetSurf operation table failed registration");
1098 }
1099
1100 if (find_directory(B_USER_SETTINGS_DIRECTORY, &options, true) == B_OK) {
1101 options.Append("x-vnd.NetSurf");
1102 }
1103
1104 if (!replicated) {
1105 // create the Application object before trying to use messages
1106 // so we can open an alert in case of error.
1108 }
1109
1110 /* initialise logging. Not fatal if it fails but not much we
1111 * can do about it either.
1112 */
1113 nslog_init(nslog_stream_configure, &argc, argv);
1114
1115 /* user options setup */
1117 if (ret != NSERROR_OK) {
1118 die("Options failed to initialise");
1119 }
1120 nsoption_read(options.Path(), NULL);
1121 nsoption_commandline(&argc, argv, NULL);
1122
1123 /* common initialisation */
1124 BResources resources;
1125 resources.SetToImage((const void*)main);
1126 size_t size = 0;
1127
1128 BString lang;
1129#ifdef __HAIKU__
1130 BMessage preferredLangs;
1131 if (BLocaleRoster::Default()->GetPreferredLanguages(&preferredLangs) == B_OK) {
1132 preferredLangs.FindString("language", 0, &lang);
1133 }
1134#endif
1135 if (lang.Length() < 1)
1136 lang.SetTo(getenv("LC_MESSAGES"));
1137
1138 char path[12];
1139 sprintf(path,"%.2s/Messages", lang.String());
1140 NSLOG(netsurf, INFO, "Loading messages from resource %s\n", path);
1141
1142 const uint8_t* res = (const uint8_t*)resources.LoadResource('data', path, &size);
1143 if (size > 0 && res != NULL) {
1144 ret = messages_add_from_inline(res, size);
1145 } else {
1146 BPath messages = get_messages_path();
1147 ret = messages_add_from_file(messages.Path());
1148 }
1149
1150 ret = netsurf_init(NULL);
1151 if (ret != NSERROR_OK) {
1152 die("NetSurf failed to initialise");
1153 }
1154
1155 gui_init(argc, argv);
1156
1157 while (!nsbeos_done) {
1159 }
1160
1161 netsurf_exit();
1162
1163 /* finalise options */
1165
1166 /* finalise logging */
1168
1169 return 0;
1170}
1171
1172/** called when replicated from NSBaseView::Instantiate() */
1173int gui_init_replicant(int argc, char** argv)
1174{
1175 nserror ret;
1176 BPath options;
1177 struct netsurf_table beos_table = {
1180 NULL, /* corewindow */
1184 NULL, /* use POSIX file */
1185 NULL, /* default utf8 */
1186 NULL, /* default search */
1187 NULL, /* default web search */
1188 NULL, /* default low level cache persistant storage */
1191 };
1192
1193 ret = netsurf_register(&beos_table);
1194 if (ret != NSERROR_OK) {
1195 die("NetSurf operation table failed registration");
1196 }
1197
1198 if (find_directory(B_USER_SETTINGS_DIRECTORY, &options, true) == B_OK) {
1199 options.Append("x-vnd.NetSurf");
1200 }
1201
1202 /* initialise logging. Not fatal if it fails but not much we
1203 * can do about it either.
1204 */
1205 nslog_init(nslog_stream_configure, &argc, argv);
1206
1207 // FIXME: use options as readonly for replicants
1208 /* user options setup */
1210 if (ret != NSERROR_OK) {
1211 // FIXME: must not die when in replicant!
1212 die("Options failed to initialise");
1213 }
1214 nsoption_read(options.Path(), NULL);
1215 nsoption_commandline(&argc, argv, NULL);
1216
1217 /* common initialisation */
1218 BPath messages = get_messages_path();
1219 ret = messages_add_from_file(messages.Path());
1220
1221 ret = netsurf_init(NULL);
1222 if (ret != NSERROR_OK) {
1223 // FIXME: must not die when in replicant!
1224 die("NetSurf failed to initialise");
1225 }
1226
1227 gui_init(argc, argv);
1228
1229 return 0;
1230}
const char * fetch_filetype(const char *unix_path)
Determine the MIME type of a local file.
Definition: filetype.c:58
#define PATH_MAX
Definition: gui.h:31
int schedule_run(void)
Process events up to current time.
Definition: schedule.c:137
#define B_UI_SETTINGS_CHANGED
Definition: gui.h:28
struct gui_bitmap_table * beos_bitmap_table
Definition: bitmap.cpp:499
Browser window creation and manipulation interface.
nserror browser_window_create(enum browser_window_create_flags flags, struct nsurl *url, struct nsurl *referrer, struct browser_window *existing, struct browser_window **bw)
Create and open a new root browser window with the given page.
@ BW_CREATE_HISTORY
this will form a new history node (don't set for back/reload/etc)
virtual void AboutRequested()
Definition: gui.cpp:207
virtual void MessageReceived(BMessage *message)
Definition: gui.cpp:145
virtual void ArgvReceived(int32 argc, char **argv)
Definition: gui.cpp:180
virtual ~NSBrowserApplication()
Definition: gui.cpp:139
virtual bool QuitRequested()
Definition: gui.cpp:214
virtual void RefsReceived(BMessage *message)
Definition: gui.cpp:193
struct beos_scaffolding * Scaffolding() const
Definition: scaffolding.h:66
nserror fetch_fdset(fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, int *maxfd_out)
Get the set of file descriptors the fetchers are currently using.
Definition: fetch.c:385
Fetching of data from a URL (interface).
Unified cookie database public interface.
void urldb_save_cookies(const char *filename)
Save persistent cookies to file.
Definition: urldb.c:4444
void urldb_load_cookies(const char *filename)
Load a cookie file into the database.
Definition: urldb.c:4277
Useful interned string pointers (interface).
#define FILE_SCHEME_PREFIX_LEN
File url prefix length.
Definition: corestrings.h:33
char options[PATH_MAX]
Definition: gui.c:91
struct gui_download_table * beos_download_table
Definition: download.cpp:263
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NO_FETCH_HANDLER
No fetch handler for URL scheme.
Definition: errors.h:33
@ NSERROR_OK
No error.
Definition: errors.h:30
void fetch_rsrc_unregister(void)
Definition: fetch_rsrc.cpp:402
void fetch_rsrc_register(void)
Definition: fetch_rsrc.cpp:366
rsrc: URL method handler
const char * filename_request(void)
Request a new, unique, filename.
Definition: filename.c:68
#define TEMP_FILENAME_PREFIX
Definition: filename.h:27
void beos_fetch_filetype_fin(void)
Definition: filetype.cpp:88
const char * type
Definition: filetype.cpp:44
void beos_fetch_filetype_init(void)
Definition: filetype.cpp:58
struct gui_layout_table * beos_layout_table
Definition: font.cpp:376
Beos font layout handling interface.
struct gui_window * search_current_window
Definition: gui.cpp:97
char * realpath(const char *f, char *buf)
Definition: gui.cpp:230
void nsbeos_gui_view_source(struct hlcache_handle *content)
Send the source of a content to a text editor.
Definition: gui.cpp:898
#define B_CONTROL_BORDER_COLOR
Definition: gui.cpp:408
image_id nsbeos_find_app_path(char *path)
Definition: gui.cpp:246
static nsurl * gui_get_resource_url(const char *path)
Definition: gui.cpp:380
BWindow * wndWarning
Definition: gui.cpp:100
BWindow * wndAbout
Definition: gui.cpp:99
#define B_SHINE_COLOR
Definition: gui.cpp:412
bool nsbeos_done
Definition: gui.cpp:90
static void gui_init(int argc, char **argv)
Definition: gui.cpp:614
#define SETFONTDEFAULT(OPTION, y)
#define B_TOOL_TIP_BACKGROUND_COLOR
Definition: gui.cpp:415
static nserror gui_launch_url(struct nsurl *url)
Broadcast an URL that we can't handle.
Definition: gui.cpp:1010
int main(int argc, char **argv)
Normal entry point from OS.
Definition: gui.cpp:1075
void nsbeos_gui_poll(void)
Definition: gui.cpp:813
BWindow * wndTooltip
Definition: gui.cpp:102
static struct gui_fetch_table beos_fetch_table
Definition: gui.cpp:1054
static char * url_to_path(const char *url)
Definition: gui.cpp:880
#define B_DOCUMENT_TEXT_COLOR
Definition: gui.cpp:405
int gui_init_replicant(int argc, char **argv)
called when replicated from NSBaseView::Instantiate()
Definition: gui.cpp:1173
void nsbeos_pipe_message_top(BMessage *message, BWindow *_this, struct beos_scaffolding *scaffold)
Definition: gui.cpp:799
static bool nslog_stream_configure(FILE *fptr)
Ensures output logging stream is correctly configured.
Definition: gui.cpp:579
static nserror set_colour_from_ui(struct nsoption_s *opts, color_which ui, enum nsoption_e option, colour def_colour)
set option from pen
Definition: gui.cpp:438
static void check_homedir(void)
Check that ~/.netsurf/ exists, and if it doesn't, create it.
Definition: gui.cpp:351
static nserror set_option_defaults(struct nsoption_s *defaults)
Set option defaults for beos frontend.
Definition: gui.cpp:468
static void gui_quit(void)
Definition: gui.cpp:868
void nsbeos_pipe_message(BMessage *message, BView *_this, struct gui_window *gui)
Definition: gui.cpp:785
char * find_resource(char *buf, const char *filename, const char *def)
Locate a shared resource file by searching known places in order.
Definition: gui.cpp:277
BFilePanel * wndOpenFile
Definition: gui.cpp:104
#define B_TOOL_TIP_TEXT_COLOR
Definition: gui.cpp:416
#define B_CONTROL_BACKGROUND_COLOR
Definition: gui.cpp:406
bool replicated
if we are running as a replicant
Definition: gui.cpp:92
static struct gui_misc_table beos_misc_table
Definition: gui.cpp:1064
#define FIND_THROB(n)
static int32 bapp_thread(void *arg)
Definition: gui.cpp:373
void die(const char *const error)
Cause an abnormal program termination.
Definition: gui.cpp:1038
nserror beos_warn_user(const char *warning, const char *detail)
Display a warning for a serious problem (eg memory exhaustion).
Definition: gui.cpp:116
char * glade_file_location
Definition: gui.cpp:95
#define B_CONTROL_TEXT_COLOR
Definition: gui.cpp:407
#define NOCOL
Definition: gui.cpp:432
void nsbeos_update_system_ui_colors(void)
Definition: gui.cpp:571
static thread_id sBAppThreadID
Definition: gui.cpp:106
static BMessage * gFirstRefsReceived
Definition: gui.cpp:108
#define B_DOCUMENT_BACKGROUND_COLOR
Definition: gui.cpp:404
char * options_file_location
Definition: gui.cpp:94
#define B_CONTROL_HIGHLIGHT_COLOR
Definition: gui.cpp:409
static BPath get_messages_path()
Definition: gui.cpp:587
static int sEventPipe[2]
Definition: gui.cpp:110
void nsbeos_options_init(void)
Definition: gui_options.cpp:38
Interface to platform-specific clipboard operations.
Public content interface.
struct nsurl * hlcache_handle_get_url(const struct hlcache_handle *handle)
Retrieve the URL associated with a high level cache handle.
const uint8_t * content_get_source_data(struct hlcache_handle *h, size_t *size)
Retrieve source of content.
Definition: content.c:1201
lwc_string * content_get_mime_type(struct hlcache_handle *h)
Retrieve mime-type of content.
Definition: content.c:1065
Interface to platform-specific fetcher operations.
Interface to platform-specific miscellaneous browser operation table.
Interface to platform-specific search operations.
nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
Initialise the logging system.
Definition: log.c:190
void nslog_finalise(void)
Shut down the logging system.
Definition: log.c:299
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
nserror messages_add_from_inline(const uint8_t *data, size_t size)
Read keys and values from inline message data into the standard Messages hash.
Definition: messages.c:190
nserror messages_add_from_file(const char *path)
Read keys and values from messages file into the standard Messages hash.
Definition: messages.c:177
const char * messages_get_errorcode(nserror code)
lookup of a message by errorcode from the standard Messages hash.
Definition: messages.c:263
Localised message support (interface).
NetSurf core interface registration, construction and destruction.
void netsurf_exit(void)
Finalise NetSurf core.
Definition: netsurf.c:232
nserror netsurf_init(const char *store_path)
Initialise netsurf core.
Definition: netsurf.c:107
nserror netsurf_register(struct netsurf_table *table)
Register operation table.
Definition: gui_factory.c:777
NetSurf URL handling (interface).
nserror nsurl_create(const char *const url_s, nsurl **url)
Create a NetSurf URL object from a URL string.
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
int32_t int32
Definition: os3support.h:183
NSBrowserWindow * nsbeos_find_last_window(void)
nserror beos_schedule(int t, void(*callback)(void *p), void *p)
Definition: schedule.cpp:84
bigtime_t earliest_callback_timeout
earliest deadline.
Definition: schedule.cpp:48
Interface to utility string handling.
Content which corresponds to a single URL.
function table for fetcher operations.
Definition: fetch.h:33
Graphical user interface browser misc function table.
Definition: misc.h:39
first entry in window list
Definition: gui.c:298
char * url
Definition: gui.h:154
struct gui_window::@47 option
Options.
High-level cache handle.
Definition: hlcache.c:66
NetSurf operation function table.
Definition: gui_table.h:48
union nsoption_s::@149 value
colour c
Definition: nsoption.h:122
bool nsbeos_throbber_initialise_from_png(const int frames,...)
Creates the throbber using a PNG for each frame.
Definition: throbber.cpp:45
uint32_t colour
Colour type: XBGR.
Definition: types.h:35
nserror url_unescape(const char *str, size_t length, size_t *length_out, char **result_out)
Convert an escaped string to plain.
Definition: url.c:67
Interface to URL parsing and joining operations.
Unified URL information database public interface.
nserror urldb_save(const char *filename)
Export the current database to file.
Definition: urldb.c:3091
nserror urldb_load(const char *filename)
Import an URL database from file, replacing any existing database.
Definition: urldb.c:2874
struct nsoption_s * nsoptions_default
global default option table.
Definition: nsoption.c:46
static struct nsoption_s defaults[]
The table of compiled in default options.
Definition: nsoption.c:64
nserror nsoption_read(const char *path, struct nsoption_s *opts)
Read choices file and set them in the passed table.
Definition: nsoption.c:698
struct nsoption_s * nsoptions
global active option table.
Definition: nsoption.c:45
nserror nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts)
Process commandline and set options approriately.
Definition: nsoption.c:858
nserror nsoption_init(nsoption_set_default_t *set_defaults, struct nsoption_s **popts, struct nsoption_s **pdefs)
Initialise option system.
Definition: nsoption.c:610
nserror nsoption_finalise(struct nsoption_s *opts, struct nsoption_s *defs)
Finalise option system.
Definition: nsoption.c:665
Option reading and saving interface.
#define nsoption_charp(OPTION)
Get the value of a string option.
Definition: nsoption.h:335
nsoption_e
Definition: nsoption.h:133
@ NSOPTION_LISTEND
Definition: nsoption.h:154
#define nsoption_set_bool(OPTION, VALUE)
set a boolean option in the default table
Definition: nsoption.h:348
#define nsoption_set_charp(OPTION, VALUE)
set string option in default table
Definition: nsoption.h:376
UTF-8 manipulation functions (interface).
Interface to a number of general purpose functionality.
void nsbeos_dispatch_event(BMessage *message)
Process beos messages into browser operations.
Definition: window.cpp:407
struct gui_clipboard_table * beos_clipboard_table
Definition: window.cpp:1317
struct gui_window_table * beos_window_table
Definition: window.cpp:1408
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821
static nserror text(const struct redraw_context *ctx, const struct plot_font_style *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plot.c:978