summaryrefslogtreecommitdiff
path: root/frontends/beos
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2016-05-05 22:28:51 +0100
committerVincent Sanders <vince@kyllikki.org>2016-05-15 13:44:34 +0100
commitd21447d096a320a08b3efb2b8768fad0dcdcfd64 (patch)
tree1a83814b7c9e94b2f13c473261f23dd3a17dee64 /frontends/beos
parent2cbb337756d9af5bda4d594964d446439f602551 (diff)
downloadnetsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.gz
netsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.bz2
move frontends into sub directory
Diffstat (limited to 'frontends/beos')
-rw-r--r--frontends/beos/Makefile102
-rw-r--r--frontends/beos/Makefile.defaults30
-rw-r--r--frontends/beos/WindowStack.h45
-rw-r--r--frontends/beos/about.cpp57
-rw-r--r--frontends/beos/about.h24
-rw-r--r--frontends/beos/beos_res.rsrcbin0 -> 11584 bytes
-rw-r--r--frontends/beos/bitmap.cpp556
-rw-r--r--frontends/beos/bitmap.h33
-rw-r--r--frontends/beos/cookies.cpp417
-rw-r--r--frontends/beos/cookies.h24
-rw-r--r--frontends/beos/download.cpp264
-rw-r--r--frontends/beos/download.h19
-rw-r--r--frontends/beos/fetch_rsrc.cpp396
-rw-r--r--frontends/beos/fetch_rsrc.h35
-rw-r--r--frontends/beos/filetype.cpp138
-rw-r--r--frontends/beos/filetype.h21
-rw-r--r--frontends/beos/font.cpp374
-rw-r--r--frontends/beos/font.h37
-rw-r--r--frontends/beos/gui.cpp1109
-rw-r--r--frontends/beos/gui.h88
-rw-r--r--frontends/beos/gui_options.cpp50
-rw-r--r--frontends/beos/gui_options.h31
-rw-r--r--frontends/beos/login.cpp196
-rw-r--r--frontends/beos/options.h30
-rw-r--r--frontends/beos/plotters.cpp659
-rw-r--r--frontends/beos/plotters.h48
-rw-r--r--frontends/beos/res.h18
-rw-r--r--frontends/beos/res.rdef242
l---------frontends/beos/res/SearchEngines1
l---------frontends/beos/res/adblock.css1
-rw-r--r--frontends/beos/res/beosdefault.css22
l---------frontends/beos/res/ca-bundle.txt1
l---------frontends/beos/res/credits.html1
l---------frontends/beos/res/de/welcome.html1
l---------frontends/beos/res/default.css1
l---------frontends/beos/res/en/credits.html1
l---------frontends/beos/res/en/licence.html1
l---------frontends/beos/res/en/maps.html1
l---------frontends/beos/res/en/welcome.html1
l---------frontends/beos/res/favicon.png1
l---------frontends/beos/res/icons1
l---------frontends/beos/res/internal.css1
l---------frontends/beos/res/it/credits.html1
l---------frontends/beos/res/it/licence.html1
l---------frontends/beos/res/it/welcome.html1
l---------frontends/beos/res/ja/welcome.html1
l---------frontends/beos/res/licence.html1
-rw-r--r--frontends/beos/res/license332
l---------frontends/beos/res/maps.html1
l---------frontends/beos/res/netsurf.png1
l---------frontends/beos/res/quirks.css1
-rw-r--r--frontends/beos/res/throbber/throbber0.pngbin0 -> 521 bytes
-rw-r--r--frontends/beos/res/throbber/throbber1.pngbin0 -> 820 bytes
-rw-r--r--frontends/beos/res/throbber/throbber2.pngbin0 -> 812 bytes
-rw-r--r--frontends/beos/res/throbber/throbber3.pngbin0 -> 826 bytes
-rw-r--r--frontends/beos/res/throbber/throbber4.pngbin0 -> 818 bytes
-rw-r--r--frontends/beos/res/throbber/throbber5.pngbin0 -> 815 bytes
-rw-r--r--frontends/beos/res/throbber/throbber6.pngbin0 -> 839 bytes
-rw-r--r--frontends/beos/res/throbber/throbber7.pngbin0 -> 811 bytes
-rw-r--r--frontends/beos/res/throbber/throbber8.pngbin0 -> 833 bytes
l---------frontends/beos/res/welcome.html1
-rw-r--r--frontends/beos/scaffolding.cpp2332
-rw-r--r--frontends/beos/scaffolding.h210
-rw-r--r--frontends/beos/schedule.cpp142
-rw-r--r--frontends/beos/schedule.h29
-rw-r--r--frontends/beos/search.cpp76
-rw-r--r--frontends/beos/throbber.cpp118
-rw-r--r--frontends/beos/throbber.h36
-rw-r--r--frontends/beos/window.cpp1382
-rw-r--r--frontends/beos/window.h83
70 files changed, 9827 insertions, 0 deletions
diff --git a/frontends/beos/Makefile b/frontends/beos/Makefile
new file mode 100644
index 000000000..8a79fc5ec
--- /dev/null
+++ b/frontends/beos/Makefile
@@ -0,0 +1,102 @@
+# ----------------------------------------------------------------------------
+# BeOS target setup
+# ----------------------------------------------------------------------------
+
+# Linker flags
+LDFLAGS += -L/boot/home/config/lib
+LDFLAGS += -L/boot/common/lib
+LDFLAGS += -lbe -ltranslation -ltracker -lcolumnlistview -lnetwork
+ifeq ($(CC_MAJOR),2)
+ LDFLAGS += -lstdc++.r4
+else
+ LDFLAGS += -lstdc++ -lsupc++
+endif
+
+COMMON_WARNFLAGS += -Wno-multichar
+
+# compiler flags
+CFLAGS += -std=c99 -Dnsbeos -D_BSD_SOURCE -D_POSIX_C_SOURCE -Drestrict="" -g
+CXXFLAGS += -Dnsbeos -D_BSD_SOURCE -D_POSIX_C_SOURCE -Drestrict="" -g
+
+BEOS_BERES := beres
+BEOS_RC := rc
+BEOS_XRES := xres
+BEOS_SETVER := setversion
+BEOS_MIMESET := mimeset
+
+VERSION_FULL := $(shell sed -n '/_version.*=.*"/{s/.*"\(.*\)".*/\1/;p;}' desktop/version.c)
+VERSION_MAJ := $(shell sed -n '/_major/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
+VERSION_MIN := $(shell sed -n '/_minor/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
+
+# ----------------------------------------------------------------------------
+# Source file setup
+# ----------------------------------------------------------------------------
+
+# sources purely for the BeOS build
+S_FRONTEND := about.cpp bitmap.cpp cookies.cpp download.cpp \
+ fetch_rsrc.cpp filetype.cpp font.cpp gui.cpp login.cpp \
+ gui_options.cpp plotters.cpp scaffolding.cpp search.cpp \
+ schedule.cpp throbber.cpp window.cpp
+
+# This is the final source build list
+# Note this is deliberately *not* expanded here as common and image
+# are not yet available
+SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_FRONTEND)
+EXETARGET := NetSurf
+
+# The filter and target for split messages
+MESSAGES_FILTER=beos
+MESSAGES_TARGET=$(FRONTEND_RESOURCES_DIR)
+
+# ----------------------------------------------------------------------------
+# Resources
+# ----------------------------------------------------------------------------
+
+RDEF_BEOS := res.rdef
+RDEF_BEOS := $(addprefix $(FRONTEND_SOURCE_DIR)/,$(RDEF_BEOS))
+
+RDEF_IMP_BEOS := res_import.rdef
+RDEF_IMP_BEOS := $(addprefix $(OBJROOT)/,$(subst /,_,$(RDEF_IMP_BEOS)))
+
+RDEP_BEOS := \
+ adblock.css beosdefault.css default.css internal.css quirks.css \
+ netsurf.png favicon.png ca-bundle.txt \
+ credits.html licence.html welcome.html maps.html SearchEngines
+
+RDEP_BEOS := $(addprefix $(FRONTEND_RESOURCES_DIR)/,$(RDEP_BEOS)) \
+ $(wildcard $(FRONTEND_RESOURCES_DIR)/icons/*.png) \
+ $(wildcard $(FRONTEND_RESOURCES_DIR)/??/*) \
+ $(wildcard $(FRONTEND_RESOURCES_DIR)/throbber/throbber*.png)
+
+RSRC_BEOS = $(addprefix $(OBJROOT)/,$(subst /,_,$(patsubst %.rdef,%.rsrc,$(RDEF_BEOS))))
+RESOURCES = $(RSRC_BEOS)
+
+$(RDEF_IMP_BEOS): $(RDEP_BEOS)
+ $(VQ)echo " GEN: $@"
+ $(Q)n=5000; for f in $^; do echo "resource($$n,\"$${f#beos/res/}\") #'data' import \"$${f#beos/}\";"; n=$$(($$n+1)); done > $@
+
+$(RSRC_BEOS): $(RDEF_BEOS) $(RDEF_IMP_BEOS)
+ $(VQ)echo " RC: $<"
+ $(Q)$(BEOS_RC) -I beos -o $@ $^
+
+
+# ----------------------------------------------------------------------------
+# Install target
+# ----------------------------------------------------------------------------
+
+install-beos:
+ mkdir -p $(DESTDIR)$(NETSURF_BEOS_BIN)
+ mkdir -p $(DESTDIR)$(NETSURF_BEOS_RESOURCES)
+ @copyattr -d $(EXETARGET) $(DESTDIR)$(NETSURF_BEOS_BIN)NetSurf
+ @cp -vRL $(FRONTEND_RESOURCES_DIR)/adblock.css $(DESTDIR)$(NETSURF_BEOS_RESOURCES)
+ @cp -vRL $(FRONTEND_RESOURCES_DIR)/ca-bundle.txt $(DESTDIR)$(NETSURF_BEOS_RESOURCES)
+ @cp -vRL $(FRONTEND_RESOURCES_DIR)/default.css $(DESTDIR)$(NETSURF_BEOS_RESOURCES)
+ @cp -vRL $(FRONTEND_RESOURCES_DIR)/beosdefault.css $(DESTDIR)$(NETSURF_BEOS_RESOURCES)
+ @cp -vRL $(FRONTEND_RESOURCES_DIR)/license $(DESTDIR)$(NETSURF_BEOS_RESOURCES)
+ @cp -vRL $(FRONTEND_RESOURCES_DIR)/SearchEngines $(DESTDIR)$(NETSURF_BEOS_RESOURCES)
+
+# ----------------------------------------------------------------------------
+# Package target
+# ----------------------------------------------------------------------------
+
+package-beos:
diff --git a/frontends/beos/Makefile.defaults b/frontends/beos/Makefile.defaults
new file mode 100644
index 000000000..7616a41a3
--- /dev/null
+++ b/frontends/beos/Makefile.defaults
@@ -0,0 +1,30 @@
+# ----------------------------------------------------------------------------
+# BeOS-specific options
+# ----------------------------------------------------------------------------
+
+# Where to install the netsurf binary
+NETSURF_BEOS_BIN := /boot/apps/netsurf/
+
+# TODO:HAIKU -- not sure if ~/.netsurf applies in beos
+# Where to search for NetSurf's resources after looking in ~/.netsurf and
+# $NETSURFRES. It must have a trailing /
+NETSURF_BEOS_RESOURCES := /boot/apps/netsurf/res/
+
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_NSSVG := YES
+
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := AUTO
+
+# Enable NetSurf's use of libharu for PDF export.
+# Valid options: YES, NO
+NETSURF_USE_HARU_PDF := NO
+
+# Force using glibc internal iconv implementation instead of external libiconv
+# Valid options: YES, NO
+NETSURF_USE_LIBICONV_PLUG := NO
+
+# Optimisation levels
+CFLAGS += -pipe -O2
diff --git a/frontends/beos/WindowStack.h b/frontends/beos/WindowStack.h
new file mode 100644
index 000000000..947b14360
--- /dev/null
+++ b/frontends/beos/WindowStack.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef WINDOW_STACK_H
+#define WINDOW_STACK_H
+
+
+#include <Window.h>
+
+
+class BWindowStack {
+public:
+ BWindowStack(BWindow* window);
+ ~BWindowStack();
+
+ status_t AddWindow(const BWindow* window);
+ status_t AddWindow(const BMessenger& window);
+ status_t AddWindowAt(const BWindow* window,
+ int32 position);
+ status_t AddWindowAt(const BMessenger& window,
+ int32 position);
+
+ status_t RemoveWindow(const BWindow* window);
+ status_t RemoveWindow(const BMessenger& window);
+ status_t RemoveWindowAt(int32 position,
+ BMessenger* window = NULL);
+
+ int32 CountWindows();
+
+ status_t WindowAt(int32 position,
+ BMessenger& messenger);
+ bool HasWindow(const BWindow* window);
+ bool HasWindow(const BMessenger& window);
+
+private:
+ status_t _AttachMessenger(const BMessenger& window);
+ status_t _ReadMessenger(BMessenger& window);
+ status_t _StartMessage(int32 what);
+
+ BPrivate::PortLink* fLink;
+};
+
+
+#endif
diff --git a/frontends/beos/about.cpp b/frontends/beos/about.cpp
new file mode 100644
index 000000000..89eb81829
--- /dev/null
+++ b/frontends/beos/about.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+extern "C" {
+#include "desktop/version.h"
+#include "utils/log.h"
+#include "testament.h"
+#include "utils/useragent.h"
+#include "curl/curlver.h"
+#include "desktop/gui_clipboard.h"
+}
+#include "beos/about.h"
+#include "beos/scaffolding.h"
+#include "beos/window.h"
+
+#include <private/interface/AboutWindow.h>
+#include <Application.h>
+#include <Invoker.h>
+#include <String.h>
+
+
+/**
+ * Creates the about alert
+ */
+void nsbeos_about(struct gui_window *gui)
+{
+ BString text;
+ text << "Netsurf : " << user_agent_string() << "\n";
+ text << "Version : " << netsurf_version << "\n";
+ text << "Build ID : " << WT_REVID << "\n";
+ text << "Date : " << WT_COMPILEDATE << "\n";
+ text << "cURL : " << LIBCURL_VERSION << "\n";
+
+ BAboutWindow *alert = new BAboutWindow("About NetSurf", "application/x-vnd.NetSurf");
+ alert->AddExtraInfo(text);
+ alert->Show();
+ //TODO: i18n-ize
+}
diff --git a/frontends/beos/about.h b/frontends/beos/about.h
new file mode 100644
index 000000000..f80d33f01
--- /dev/null
+++ b/frontends/beos/about.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BEOS_ABOUT_H__
+#define __BEOS_ABOUT_H__
+
+void nsbeos_about(struct gui_window *gui);
+
+#endif /* __BEOS_ABOUT_H__ */
diff --git a/frontends/beos/beos_res.rsrc b/frontends/beos/beos_res.rsrc
new file mode 100644
index 000000000..d37e9e6ec
--- /dev/null
+++ b/frontends/beos/beos_res.rsrc
Binary files differ
diff --git a/frontends/beos/bitmap.cpp b/frontends/beos/bitmap.cpp
new file mode 100644
index 000000000..26b7a3957
--- /dev/null
+++ b/frontends/beos/bitmap.cpp
@@ -0,0 +1,556 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * BeOS implementation of generic bitmaps.
+ *
+ * This implements the interface given by image/bitmap.h using BBitmap.
+ */
+
+#define __STDBOOL_H__ 1
+#include <assert.h>
+#include <sys/param.h>
+#include <string.h>
+#include <Bitmap.h>
+#include <BitmapStream.h>
+#include <File.h>
+#include <GraphicsDefs.h>
+#include <TranslatorFormats.h>
+#include <TranslatorRoster.h>
+#include <View.h>
+#include <stdlib.h>
+
+extern "C" {
+#include "utils/log.h"
+#include "content/content.h"
+#include "content/urldb.h"
+#include "desktop/plotters.h"
+#include "desktop/browser.h"
+#include "image/bitmap.h"
+}
+
+#include "beos/bitmap.h"
+#include "beos/gui.h"
+#include "beos/scaffolding.h"
+#include "beos/plotters.h"
+
+
+struct bitmap {
+ BBitmap *primary;
+ BBitmap *shadow; // in NetSurf's ABGR order
+ BBitmap *pretile_x;
+ BBitmap *pretile_y;
+ BBitmap *pretile_xy;
+ bool opaque;
+};
+
+#define MIN_PRETILE_WIDTH 256
+#define MIN_PRETILE_HEIGHT 256
+
+#warning TODO: check rgba order
+#warning TODO: add correct locking (not strictly required)
+
+
+/**
+ * Convert to BeOS RGBA32_LITTLE (strictly BGRA) from NetSurf's favoured ABGR format.
+ *
+ * Copies the converted data elsewhere. Operation is rotate left 8 bits.
+ *
+ * \param src Source 32-bit pixels arranged in ABGR order.
+ * \param dst Output data in BGRA order.
+ * \param width Width of the bitmap
+ * \param height Height of the bitmap
+ * \param rowstride Number of bytes to skip after each row (this implementation
+ * requires this to be a multiple of 4.)
+ */
+static inline void nsbeos_rgba_to_bgra(void *src,
+ void *dst,
+ int width,
+ int height,
+ size_t rowstride)
+{
+ struct abgr { uint8 a, b, g, r; };
+ struct rgba { uint8 r, g, b ,a; };
+ struct bgra { uint8 b, g, r, a; };
+ struct rgba *from = (struct rgba *)src;
+ struct bgra *to = (struct bgra *)dst;
+
+ rowstride >>= 2;
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ to[x].b = from[x].b;
+ to[x].g = from[x].g;
+ to[x].r = from[x].r;
+ to[x].a = from[x].a;
+ /*
+ if (from[x].a == 0)
+ *(rgb_color *)&to[x] = B_TRANSPARENT_32_BIT;
+ */
+ }
+ from += rowstride;
+ to += rowstride;
+ }
+}
+
+
+/**
+ * Create a bitmap.
+ *
+ * \param width width of image in pixels
+ * \param height width of image in pixels
+ * \param state a flag word indicating the initial state
+ * \return an opaque struct bitmap, or NULL on memory exhaustion
+ */
+static void *bitmap_create(int width, int height, unsigned int state)
+{
+ struct bitmap *bmp = (struct bitmap *)malloc(sizeof(struct bitmap));
+ if (bmp == NULL)
+ return NULL;
+
+ int32 flags = 0;
+ if (state & BITMAP_CLEAR_MEMORY)
+ flags |= B_BITMAP_CLEAR_TO_WHITE;
+
+ BRect frame(0, 0, width - 1, height - 1);
+ //XXX: bytes per row ?
+ bmp->primary = new BBitmap(frame, flags, B_RGBA32);
+ bmp->shadow = new BBitmap(frame, flags, B_RGBA32);
+
+ bmp->pretile_x = bmp->pretile_y = bmp->pretile_xy = NULL;
+
+ bmp->opaque = (state & BITMAP_OPAQUE) != 0;
+
+ return bmp;
+}
+
+
+/**
+ * Sets whether a bitmap should be plotted opaque
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \param opaque whether the bitmap should be plotted opaque
+ */
+static void bitmap_set_opaque(void *vbitmap, bool opaque)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ bitmap->opaque = opaque;
+}
+
+
+/**
+ * Tests whether a bitmap has an opaque alpha channel
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return whether the bitmap is opaque
+ */
+static bool bitmap_test_opaque(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ /* todo: test if bitmap is opaque */
+ return false;
+}
+
+
+/**
+ * Gets whether a bitmap should be plotted opaque
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+static bool bitmap_get_opaque(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ return bitmap->opaque;
+}
+
+
+/**
+ * Return a pointer to the pixel data in a bitmap.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return pointer to the pixel buffer
+ *
+ * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end
+ * of rows. The width of a row in bytes is given by bitmap_get_rowstride().
+ */
+
+static unsigned char *bitmap_get_buffer(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ return (unsigned char *)(bitmap->shadow->Bits());
+}
+
+
+/**
+ * Find the width of a pixel row in bytes.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return width of a pixel row in the bitmap
+ */
+static size_t bitmap_get_rowstride(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ return (bitmap->primary->BytesPerRow());
+}
+
+
+/**
+ * Find the bytes per pixels of a bitmap.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return bytes per pixels of the bitmap
+ */
+static size_t bitmap_get_bpp(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ return 4;
+}
+
+
+/**
+ * Free pretiles of a bitmap.
+ *
+ * \param bitmap The bitmap to free the pretiles of.
+ */
+static void nsbeos_bitmap_free_pretiles(struct bitmap *bitmap)
+{
+#define FREE_TILE(XY) if (bitmap->pretile_##XY) delete (bitmap->pretile_##XY); bitmap->pretile_##XY = NULL
+ FREE_TILE(x);
+ FREE_TILE(y);
+ FREE_TILE(xy);
+#undef FREE_TILE
+}
+
+
+/**
+ * Free a bitmap.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+static void bitmap_destroy(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ nsbeos_bitmap_free_pretiles(bitmap);
+ delete bitmap->primary;
+ delete bitmap->shadow;
+ free(bitmap);
+}
+
+
+/**
+ * Save a bitmap in the platform's native format.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \param path pathname for file
+ * \param flags modify the behaviour of the save
+ * \return true on success, false on error and error reported
+ */
+static bool bitmap_save(void *vbitmap, const char *path, unsigned flags)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ BTranslatorRoster *roster = BTranslatorRoster::Default();
+ BBitmapStream stream(bitmap->primary);
+ BFile file(path, B_WRITE_ONLY | B_CREATE_FILE);
+ uint32 type = B_PNG_FORMAT;
+
+ if (file.InitCheck() < B_OK)
+ return false;
+
+ if (roster->Translate(&stream, NULL, NULL, &file, type) < B_OK)
+ return false;
+
+ return true;
+}
+
+
+/**
+ * The bitmap image has changed, so flush any persistant cache.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+void bitmap_modified(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ // convert the shadow (ABGR) to into the primary bitmap
+ nsbeos_rgba_to_bgra(bitmap->shadow->Bits(), bitmap->primary->Bits(),
+ bitmap->primary->Bounds().Width() + 1,
+ bitmap->primary->Bounds().Height() + 1,
+ bitmap->primary->BytesPerRow());
+ nsbeos_bitmap_free_pretiles(bitmap);
+}
+
+
+static int bitmap_get_width(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ return bitmap->primary->Bounds().Width() + 1;
+}
+
+
+static int bitmap_get_height(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ return bitmap->primary->Bounds().Height() + 1;
+}
+
+
+static BBitmap *
+nsbeos_bitmap_generate_pretile(BBitmap *primary, int repeat_x, int repeat_y)
+{
+ int width = primary->Bounds().Width() + 1;
+ int height = primary->Bounds().Height() + 1;
+ size_t primary_stride = primary->BytesPerRow();
+ BRect frame(0, 0, width * repeat_x - 1, height * repeat_y - 1);
+ BBitmap *result = new BBitmap(frame, 0, B_RGBA32);
+
+ char *target_buffer = (char *)result->Bits();
+ int x,y,row;
+ /* This algorithm won't work if the strides are not multiples */
+ assert((size_t)(result->BytesPerRow()) ==
+ (primary_stride * repeat_x));
+
+ if (repeat_x == 1 && repeat_y == 1) {
+ delete result;
+ // just return a copy
+ return new BBitmap(primary);
+ }
+
+ for (y = 0; y < repeat_y; ++y) {
+ char *primary_buffer = (char *)primary->Bits();
+ for (row = 0; row < height; ++row) {
+ for (x = 0; x < repeat_x; ++x) {
+ memcpy(target_buffer,
+ primary_buffer, primary_stride);
+ target_buffer += primary_stride;
+ }
+ primary_buffer += primary_stride;
+ }
+ }
+ return result;
+
+}
+
+
+/**
+ * The primary image associated with this bitmap object.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+BBitmap *
+nsbeos_bitmap_get_primary(struct bitmap* bitmap)
+{
+ return bitmap->primary;
+}
+
+
+/**
+ * The X-pretiled image associated with this bitmap object.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+BBitmap *
+nsbeos_bitmap_get_pretile_x(struct bitmap* bitmap)
+{
+ if (!bitmap->pretile_x) {
+ int width = bitmap->primary->Bounds().Width() + 1;
+ int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
+ LOG("Pretiling %p for X*%d", bitmap, xmult);
+ bitmap->pretile_x = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, 1);
+ }
+ return bitmap->pretile_x;
+
+}
+
+
+/**
+ * The Y-pretiled image associated with this bitmap object.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+BBitmap *
+nsbeos_bitmap_get_pretile_y(struct bitmap* bitmap)
+{
+ if (!bitmap->pretile_y) {
+ int height = bitmap->primary->Bounds().Height() + 1;
+ int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
+ LOG("Pretiling %p for Y*%d", bitmap, ymult);
+ bitmap->pretile_y = nsbeos_bitmap_generate_pretile(bitmap->primary, 1, ymult);
+ }
+ return bitmap->pretile_y;
+}
+
+
+/**
+ * The XY-pretiled image associated with this bitmap object.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+BBitmap *
+nsbeos_bitmap_get_pretile_xy(struct bitmap* bitmap)
+{
+ if (!bitmap->pretile_xy) {
+ int width = bitmap->primary->Bounds().Width() + 1;
+ int height = bitmap->primary->Bounds().Height() + 1;
+ int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
+ int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
+ LOG("Pretiling %p for X*%d Y*%d", bitmap, xmult, ymult);
+ bitmap->pretile_xy = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, ymult);
+ }
+ return bitmap->pretile_xy;
+}
+
+
+/**
+ * Create a thumbnail of a page.
+ *
+ * \param bitmap the bitmap to draw to
+ * \param content content structure to thumbnail
+ * \return true on success and bitmap updated else false
+ */
+static nserror bitmap_render(struct bitmap *bitmap, hlcache_handle *content)
+{
+ BBitmap *thumbnail;
+ BBitmap *small;
+ BBitmap *big;
+ BView *oldView;
+ BView *view;
+ BView *thumbView;
+ float width;
+ float height;
+ int big_width;
+ int big_height;
+ int depth;
+
+ struct redraw_context ctx;
+ ctx.interactive = false;
+ ctx.background_images = true;
+ ctx.plot = &nsbeos_plotters;
+
+ assert(content);
+ assert(bitmap);
+
+ thumbnail = nsbeos_bitmap_get_primary(bitmap);
+ width = thumbnail->Bounds().Width();
+ height = thumbnail->Bounds().Height();
+ depth = 32;
+
+ big_width = MIN(content_get_width(content), 1024);
+ big_height = (int)(((big_width * height) + (width / 2)) / width);
+
+ BRect contentRect(0, 0, big_width - 1, big_height - 1);
+ big = new BBitmap(contentRect, B_BITMAP_ACCEPTS_VIEWS, B_RGB32);
+
+ if (big->InitCheck() < B_OK) {
+ delete big;
+ return NSERROR_NOMEM;
+ }
+
+ small = new BBitmap(thumbnail->Bounds(),
+ B_BITMAP_ACCEPTS_VIEWS, B_RGB32);
+
+ if (small->InitCheck() < B_OK) {
+ delete small;
+ delete big;
+ return NSERROR_NOMEM;
+ }
+
+ //XXX: _lock ?
+ // backup the current gc
+ oldView = nsbeos_current_gc();
+
+ view = new BView(contentRect, "thumbnailer",
+ B_FOLLOW_NONE, B_WILL_DRAW);
+ big->AddChild(view);
+
+ thumbView = new BView(small->Bounds(), "thumbnail",
+ B_FOLLOW_NONE, B_WILL_DRAW);
+ small->AddChild(thumbView);
+
+ view->LockLooper();
+
+ /* impose our view on the content... */
+ nsbeos_current_gc_set(view);
+
+ /* render the content */
+ content_scaled_redraw(content, big_width, big_height, &ctx);
+
+ view->Sync();
+ view->UnlockLooper();
+
+ // restore the current gc
+ nsbeos_current_gc_set(oldView);
+
+
+ // now scale it down
+ //XXX: use Zeta's bilinear scaler ?
+ //#ifdef B_ZETA_VERSION
+ // err = ScaleBitmap(*shot, *scaledBmp);
+ //#else
+ thumbView->LockLooper();
+ thumbView->DrawBitmap(big, big->Bounds(), small->Bounds());
+ thumbView->Sync();
+ thumbView->UnlockLooper();
+
+ small->LockBits();
+ thumbnail->LockBits();
+
+ // copy it to the bitmap
+ memcpy(thumbnail->Bits(), small->Bits(), thumbnail->BitsLength());
+
+ thumbnail->UnlockBits();
+ small->UnlockBits();
+
+ bitmap_modified(bitmap);
+
+ // cleanup
+ small->RemoveChild(thumbView);
+ delete thumbView;
+ delete small;
+ big->RemoveChild(view);
+ delete view;
+ delete big;
+
+ return NSERROR_OK;
+}
+
+
+static struct gui_bitmap_table bitmap_table = {
+ /*.create =*/ bitmap_create,
+ /*.destroy =*/ bitmap_destroy,
+ /*.set_opaque =*/ bitmap_set_opaque,
+ /*.get_opaque =*/ bitmap_get_opaque,
+ /*.test_opaque =*/ bitmap_test_opaque,
+ /*.get_buffer =*/ bitmap_get_buffer,
+ /*.get_rowstride =*/ bitmap_get_rowstride,
+ /*.get_width =*/ bitmap_get_width,
+ /*.get_height =*/ bitmap_get_height,
+ /*.get_bpp =*/ bitmap_get_bpp,
+ /*.save =*/ bitmap_save,
+ /*.modified =*/ bitmap_modified,
+ /*.render =*/ bitmap_render,
+};
+
+struct gui_bitmap_table *beos_bitmap_table = &bitmap_table;
diff --git a/frontends/beos/bitmap.h b/frontends/beos/bitmap.h
new file mode 100644
index 000000000..bcf5f7b8d
--- /dev/null
+++ b/frontends/beos/bitmap.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NS_BEOS_BITMAP_H
+#define NS_BEOS_BITMAP_H
+
+#include <Bitmap.h>
+
+extern struct gui_bitmap_table *beos_bitmap_table;
+
+BBitmap *nsbeos_bitmap_get_primary(struct bitmap*);
+BBitmap *nsbeos_bitmap_get_pretile_x(struct bitmap*);
+BBitmap *nsbeos_bitmap_get_pretile_y(struct bitmap*);
+BBitmap *nsbeos_bitmap_get_pretile_xy(struct bitmap*);
+
+void bitmap_modified(void *vbitmap);
+
+#endif /* NS_BEOS_BITMAP_H */
diff --git a/frontends/beos/cookies.cpp b/frontends/beos/cookies.cpp
new file mode 100644
index 000000000..d1357fffa
--- /dev/null
+++ b/frontends/beos/cookies.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2015 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+extern "C" {
+#include "desktop/mouse.h"
+#include "utils/log.h"
+#include "desktop/cookie_manager.h"
+#include "desktop/plotters.h"
+#include "desktop/tree.h"
+#include "desktop/textinput.h"
+#include "content/urldb.h"
+}
+#include "beos/cookies.h"
+
+#include <Application.h>
+#include <InterfaceKit.h>
+#include <String.h>
+#include <Button.h>
+#include <Catalog.h>
+#include <private/interface/ColumnListView.h>
+#include <private/interface/ColumnTypes.h>
+#include <GroupLayoutBuilder.h>
+#include <NetworkCookieJar.h>
+#include <OutlineListView.h>
+#include <ScrollView.h>
+#include <StringView.h>
+
+#include <vector>
+
+static std::vector<struct cookie_data*> cookieJar;
+
+class CookieWindow : public BWindow {
+public:
+ CookieWindow(BRect frame);
+ virtual void MessageReceived(BMessage* message);
+ virtual void Show();
+ virtual bool QuitRequested();
+
+private:
+ void _BuildDomainList();
+ BStringItem* _AddDomain(BString domain, bool fake);
+ void _ShowCookiesForDomain(BString domain);
+ void _DeleteCookies();
+
+private:
+ BOutlineListView* fDomains;
+ BColumnListView* fCookies;
+ BStringView* fHeaderView;
+};
+
+enum {
+ COOKIE_IMPORT = 'cimp',
+ COOKIE_EXPORT = 'cexp',
+ COOKIE_DELETE = 'cdel',
+ COOKIE_REFRESH = 'rfsh',
+
+ DOMAIN_SELECTED = 'dmsl'
+};
+
+
+class CookieDateColumn: public BDateColumn
+{
+public:
+ CookieDateColumn(const char* title, float width)
+ :
+ BDateColumn(title, width, width / 2, width * 2)
+ {
+ }
+
+ void DrawField(BField* field, BRect rect, BView* parent) {
+ BDateField* dateField = (BDateField*)field;
+ if (dateField->UnixTime() == -1) {
+ DrawString("Session cookie", parent, rect);
+ } else {
+ BDateColumn::DrawField(field, rect, parent);
+ }
+ }
+};
+
+
+class CookieRow: public BRow
+{
+public:
+ CookieRow(BColumnListView* list, struct cookie_data& cookie)
+ :
+ BRow(),
+ fCookie(cookie)
+ {
+ list->AddRow(this);
+ SetField(new BStringField(cookie.name), 0);
+ SetField(new BStringField(cookie.path), 1);
+ time_t expiration = cookie.expires;
+ SetField(new BDateField(&expiration), 2);
+ SetField(new BStringField(cookie.value), 3);
+
+ BString flags;
+ if (cookie.secure)
+ flags = "https ";
+ if (cookie.http_only)
+ flags = "http ";
+
+ SetField(new BStringField(flags.String()), 4);
+ }
+
+public:
+ struct cookie_data fCookie;
+};
+
+
+class DomainItem: public BStringItem
+{
+public:
+ DomainItem(BString text, bool empty)
+ :
+ BStringItem(text),
+ fEmpty(empty)
+ {
+ }
+
+public:
+ bool fEmpty;
+};
+
+
+CookieWindow::CookieWindow(BRect frame)
+ :
+ BWindow(frame,"Cookie manager", B_TITLED_WINDOW,
+ B_NORMAL_WINDOW_FEEL,
+ B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS)
+{
+ BGroupLayout* root = new BGroupLayout(B_HORIZONTAL, 0.0);
+ SetLayout(root);
+
+ fDomains = new BOutlineListView("domain list");
+ root->AddView(new BScrollView("scroll", fDomains, 0, false, true), 1);
+
+ fHeaderView = new BStringView("label","The cookie jar is empty!");
+ fCookies = new BColumnListView("cookie list", B_WILL_DRAW, B_FANCY_BORDER,
+ false);
+
+ float em = fCookies->StringWidth("M");
+ float flagsLength = fCookies->StringWidth("Mhttps hostOnly" B_UTF8_ELLIPSIS);
+
+ fCookies->AddColumn(new BStringColumn("Name",
+ 20 * em, 10 * em, 50 * em, 0), 0);
+ fCookies->AddColumn(new BStringColumn("Path",
+ 10 * em, 10 * em, 50 * em, 0), 1);
+ fCookies->AddColumn(new CookieDateColumn("Expiration",
+ fCookies->StringWidth("88/88/8888 88:88:88 AM")), 2);
+ fCookies->AddColumn(new BStringColumn("Value",
+ 20 * em, 10 * em, 50 * em, 0), 3);
+ fCookies->AddColumn(new BStringColumn("Flags",
+ flagsLength, flagsLength, flagsLength, 0), 4);
+
+ root->AddItem(BGroupLayoutBuilder(B_VERTICAL, B_USE_DEFAULT_SPACING)
+ .SetInsets(5, 5, 5, 5)
+ .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
+ .Add(fHeaderView)
+ .AddGlue()
+ .End()
+ .Add(fCookies)
+ .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
+ .SetInsets(5, 5, 5, 5)
+ .AddGlue()
+ .Add(new BButton("delete", "Delete",
+ new BMessage(COOKIE_DELETE))), 3);
+
+ fDomains->SetSelectionMessage(new BMessage(DOMAIN_SELECTED));
+}
+
+
+void
+CookieWindow::MessageReceived(BMessage* message)
+{
+ switch(message->what) {
+ case DOMAIN_SELECTED:
+ {
+ int32 index = message->FindInt32("index");
+ BStringItem* item = (BStringItem*)fDomains->ItemAt(index);
+ if (item != NULL) {
+ BString domain = item->Text();
+ _ShowCookiesForDomain(domain);
+ }
+ return;
+ }
+
+ case COOKIE_REFRESH:
+ _BuildDomainList();
+ return;
+
+ case COOKIE_DELETE:
+ _DeleteCookies();
+ return;
+ }
+ BWindow::MessageReceived(message);
+}
+
+
+void
+CookieWindow::Show()
+{
+ BWindow::Show();
+ if (IsHidden())
+ return;
+
+ PostMessage(COOKIE_REFRESH);
+}
+
+
+bool
+CookieWindow::QuitRequested()
+{
+ if (!IsHidden())
+ Hide();
+ cookieJar.clear();
+ return false;
+}
+
+
+void
+CookieWindow::_BuildDomainList()
+{
+ // Empty the domain list (TODO should we do this when hiding instead?)
+ for (int i = fDomains->FullListCountItems() - 1; i >= 1; i--) {
+ delete fDomains->FullListItemAt(i);
+ }
+ fDomains->MakeEmpty();
+
+ // BOutlineListView does not handle parent = NULL in many methods, so let's
+ // make sure everything always has a parent.
+ DomainItem* rootItem = new DomainItem("", true);
+ fDomains->AddItem(rootItem);
+
+ // Populate the domain list - TODO USE STL VECTOR
+
+
+ for(std::vector<struct cookie_data*>::iterator it = cookieJar.begin(); it != cookieJar.end(); ++it) {
+ _AddDomain((*it)->domain, false);
+ }
+
+ int i = 1;
+ while (i < fDomains->FullListCountItems())
+ {
+ DomainItem* item = (DomainItem*)fDomains->FullListItemAt(i);
+ // Detach items from the fake root
+ item->SetOutlineLevel(item->OutlineLevel() - 1);
+ i++;
+ }
+ fDomains->RemoveItem(rootItem);
+ delete rootItem;
+
+ i = 0;
+ int firstNotEmpty = i;
+ // Collapse empty items to keep the list short
+ while (i < fDomains->FullListCountItems())
+ {
+ DomainItem* item = (DomainItem*)fDomains->FullListItemAt(i);
+ if (item->fEmpty == true) {
+ if (fDomains->CountItemsUnder(item, true) == 1) {
+ // The item has no cookies, and only a single child. We can
+ // remove it and move its child one level up in the tree.
+
+ int count = fDomains->CountItemsUnder(item, false);
+ int index = fDomains->FullListIndexOf(item) + 1;
+ for (int j = 0; j < count; j++) {
+ BListItem* child = fDomains->FullListItemAt(index + j);
+ child->SetOutlineLevel(child->OutlineLevel() - 1);
+ }
+
+ fDomains->RemoveItem(item);
+ delete item;
+
+ // The moved child is at the same index the removed item was.
+ // We continue the loop without incrementing i to process it.
+ continue;
+ } else {
+ // The item has no cookies, but has multiple children. Mark it
+ // as disabled so it is not selectable.
+ item->SetEnabled(false);
+ if (i == firstNotEmpty)
+ firstNotEmpty++;
+ }
+ }
+
+ i++;
+ }
+
+ fDomains->Select(firstNotEmpty);
+}
+
+
+BStringItem*
+CookieWindow::_AddDomain(BString domain, bool fake)
+{
+ BStringItem* parent = NULL;
+ int firstDot = domain.FindFirst('.');
+ if (firstDot >= 0) {
+ BString parentDomain(domain);
+ parentDomain.Remove(0, firstDot + 1);
+ parent = _AddDomain(parentDomain, true);
+ } else {
+ parent = (BStringItem*)fDomains->FullListItemAt(0);
+ }
+
+ BListItem* existing;
+ int i = 0;
+ // check that we aren't already there
+ while ((existing = fDomains->ItemUnderAt(parent, true, i++)) != NULL) {
+ DomainItem* stringItem = (DomainItem*)existing;
+ if (stringItem->Text() == domain) {
+ if (fake == false)
+ stringItem->fEmpty = false;
+ return stringItem;
+ }
+ }
+
+ // Insert the new item, keeping the list alphabetically sorted
+ BStringItem* domainItem = new DomainItem(domain, fake);
+ domainItem->SetOutlineLevel(parent->OutlineLevel() + 1);
+ BStringItem* sibling = NULL;
+ int siblingCount = fDomains->CountItemsUnder(parent, true);
+ for (i = 0; i < siblingCount; i++) {
+ sibling = (BStringItem*)fDomains->ItemUnderAt(parent, true, i);
+ if (strcmp(sibling->Text(), domainItem->Text()) > 0) {
+ fDomains->AddItem(domainItem, fDomains->FullListIndexOf(sibling));
+ return domainItem;
+ }
+ }
+
+ if (sibling) {
+ // There were siblings, but all smaller than what we try to insert.
+ // Insert after the last one (and its subitems)
+ fDomains->AddItem(domainItem, fDomains->FullListIndexOf(sibling)
+ + fDomains->CountItemsUnder(sibling, false) + 1);
+ } else {
+ // There were no siblings, insert right after the parent
+ fDomains->AddItem(domainItem, fDomains->FullListIndexOf(parent) + 1);
+ }
+
+ return domainItem;
+}
+
+
+void
+CookieWindow::_ShowCookiesForDomain(BString domain)
+{
+ BString label;
+ label.SetToFormat("Cookies for %s", domain.String());
+ fHeaderView->SetText(label);
+
+ // Empty the cookie list
+ fCookies->Clear();
+
+ // Populate the domain list
+
+ for(std::vector<struct cookie_data*>::iterator it = cookieJar.begin(); it != cookieJar.end(); ++it) {
+ if((*it)->domain == domain) {
+ new CookieRow(fCookies,**it);
+ }
+ }
+}
+
+static bool nsbeos_cookie_parser(const struct cookie_data* data)
+{
+ cookieJar.push_back((struct cookie_data*)data);
+ return true;
+}
+
+void
+CookieWindow::_DeleteCookies()
+{
+ // TODO shall we handle multiple selection here?
+ CookieRow* row = (CookieRow*)fCookies->CurrentSelection();
+ if (row == NULL) {
+ // TODO see if a domain is selected in the domain list, and delete all
+ // cookies for that domain
+ return;
+ }
+
+ fCookies->RemoveRow(row);
+
+ urldb_delete_cookie(row->fCookie.domain, row->fCookie.path, row->fCookie.name);
+ cookieJar.clear();
+ urldb_iterate_cookies(&nsbeos_cookie_parser);
+
+ delete row;
+}
+
+/**
+ * Creates the Cookie Manager
+ */
+void nsbeos_cookies_init(void)
+{
+ CookieWindow* cookWin=new CookieWindow(BRect(100,100,700,500));
+ cookWin->Show();
+ cookWin->Activate();
+ urldb_iterate_cookies(&nsbeos_cookie_parser);
+}
diff --git a/frontends/beos/cookies.h b/frontends/beos/cookies.h
new file mode 100644
index 000000000..977ccd232
--- /dev/null
+++ b/frontends/beos/cookies.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BEOS_COOKIES_H__
+#define __BEOS_COOKIES_H__
+
+void nsbeos_cookies_init();
+
+#endif /* __BEOS_ABOUT_H__ */
diff --git a/frontends/beos/download.cpp b/frontends/beos/download.cpp
new file mode 100644
index 000000000..ea0271e60
--- /dev/null
+++ b/frontends/beos/download.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2012 Adrien Destugues <pulkomandy@pulkomandy.tk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdbool.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+extern "C" {
+#include "desktop/download.h"
+#include "desktop/gui_download.h"
+#include "utils/utils.h"
+#include "utils/string.h"
+}
+#include "beos/download.h"
+
+#include <File.h>
+#include <FilePanel.h>
+#include <Locker.h>
+#include <Messenger.h>
+#include <StatusBar.h>
+#include <Window.h>
+
+class NSDownloadWindow: public BWindow
+{
+ public:
+ NSDownloadWindow(download_context* ctx);
+ ~NSDownloadWindow();
+
+ void MessageReceived(BMessage* message);
+
+ void Progress(int size);
+ void Failure(const char* error);
+ void Success();
+ private:
+ download_context* ctx;
+ BStatusBar* bar;
+ unsigned long progress;
+ bool success;
+};
+
+
+struct gui_download_window {
+ download_context* ctx;
+ NSDownloadWindow* window;
+
+ BLocker* storageLock;
+ BDataIO* storage;
+};
+
+
+NSDownloadWindow::NSDownloadWindow(download_context* ctx)
+ : BWindow(BRect(30, 30, 400, 200), "Downloads", B_TITLED_WINDOW,
+ B_NOT_RESIZABLE)
+ , ctx(ctx)
+ , progress(0)
+ , success(false)
+{
+ unsigned long dlsize = download_context_get_total_length(ctx);
+ char* buffer = human_friendly_bytesize(dlsize);
+
+ // Create the status bar
+ BRect rect = Bounds();
+ rect.InsetBy(3, 3);
+ bar = new BStatusBar(rect, "progress",
+ download_context_get_filename(ctx), buffer);
+ bar->SetMaxValue(dlsize);
+
+ // Create the backgroundview (just so that the area around the progress bar
+ // is B_PANEL_BACKGROUND_COLOR instead of white)
+ BView* back = new BView(Bounds(), "back", B_FOLLOW_ALL_SIDES, B_WILL_DRAW);
+ back->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+
+ // Add the views to the window
+ back->AddChild(bar);
+ AddChild(back);
+
+ // Resize the window to leave a margin around the progress bar
+ BRect size = bar->Bounds();
+ ResizeTo(size.Width() + 6, size.Height() + 6);
+ Show();
+}
+
+
+NSDownloadWindow::~NSDownloadWindow()
+{
+ download_context_abort(ctx);
+ download_context_destroy(ctx);
+}
+
+
+void
+NSDownloadWindow::MessageReceived(BMessage* message)
+{
+ switch(message->what)
+ {
+ case B_SAVE_REQUESTED:
+ {
+ entry_ref directory;
+ const char* name;
+ struct gui_download_window* dw;
+ BFilePanel* source;
+
+ message->FindRef("directory", &directory);
+ message->FindString("name", &name);
+ message->FindPointer("dw", (void**)&dw);
+
+ BDirectory dir(&directory);
+ BFile* storage = new BFile(&dir, name,
+ B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
+ dw->storageLock->Lock();
+
+ BMallocIO* tempstore = dynamic_cast<BMallocIO*>(dw->storage);
+
+ storage->Write(tempstore->Buffer(), tempstore->BufferLength());
+ delete dw->storage;
+
+ if (success)
+ delete storage; // File is already finished downloading !
+ else
+ dw->storage = storage;
+ dw->storageLock->Unlock();
+
+ message->FindPointer("source", (void**)&source);
+ delete source;
+
+ break;
+ }
+ default:
+ BWindow::MessageReceived(message);
+ }
+}
+
+
+void
+NSDownloadWindow::Progress(int size)
+{
+ progress += size;
+
+ char* buffer = human_friendly_bytesize(progress);
+ strcat(buffer, "/");
+
+ bar->LockLooper();
+ bar->Update(size, NULL, buffer);
+ bar->Invalidate();
+ bar->UnlockLooper();
+}
+
+
+void
+NSDownloadWindow::Success()
+{
+ bar->LockLooper();
+ bar->SetBarColor(ui_color(B_SUCCESS_COLOR));
+ bar->UnlockLooper();
+
+ success = true;
+}
+
+
+void
+NSDownloadWindow::Failure(const char* error)
+{
+ bar->LockLooper();
+ bar->Update(0, NULL, error);
+ bar->SetBarColor(ui_color(B_FAILURE_COLOR));
+ bar->UnlockLooper();
+}
+
+
+static struct gui_download_window *gui_download_window_create(download_context *ctx,
+ struct gui_window *parent)
+{
+ struct gui_download_window *download = (struct gui_download_window*)malloc(sizeof *download);
+ if (download == NULL)
+ return NULL;
+
+ download->storageLock = new BLocker("storage_lock");
+ download->storage = new BMallocIO();
+ download->ctx = ctx;
+
+ download->window = new NSDownloadWindow(ctx);
+
+ // Also ask the user where to save the file
+ BMessage* msg = new BMessage(B_SAVE_REQUESTED);
+
+ BFilePanel* panel = new BFilePanel(B_SAVE_PANEL,
+ new BMessenger(download->window), NULL, 0, false);
+
+ panel->SetSaveText(download_context_get_filename(ctx));
+
+ msg->AddPointer("source", panel);
+ msg->AddPointer("dw", download);
+ panel->SetMessage(msg);
+
+ panel->Show();
+
+ return download;
+}
+
+
+static nserror gui_download_window_data(struct gui_download_window *dw,
+ const char *data, unsigned int size)
+{
+ dw->window->Progress(size);
+
+ dw->storageLock->Lock();
+ dw->storage->Write(data, size);
+ dw->storageLock->Unlock();
+
+ return NSERROR_OK;
+}
+
+
+static void gui_download_window_error(struct gui_download_window *dw,
+ const char *error_msg)
+{
+ dw->window->Failure(error_msg);
+
+ delete dw->storageLock;
+ delete dw->storage;
+}
+
+
+static void gui_download_window_done(struct gui_download_window *dw)
+{
+ dw->window->Success();
+
+ dw->storageLock->Lock();
+
+ // Only delete if the storage is already a file. Else, we must wait for the
+ // user to select something in the BFilePanel!
+ BFile* file = dynamic_cast<BFile*>(dw->storage);
+ delete file;
+ if (file)
+ delete dw->storageLock;
+ else
+ dw->storageLock->Unlock();
+}
+
+static struct gui_download_table download_table = {
+ gui_download_window_create,
+ gui_download_window_data,
+ gui_download_window_error,
+ gui_download_window_done,
+};
+
+struct gui_download_table *beos_download_table = &download_table;
+
diff --git a/frontends/beos/download.h b/frontends/beos/download.h
new file mode 100644
index 000000000..0ce387efc
--- /dev/null
+++ b/frontends/beos/download.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2012 Adrien Destugues <pulkomandy@pulkomandy.tk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+extern struct gui_download_table *beos_download_table;
diff --git a/frontends/beos/fetch_rsrc.cpp b/frontends/beos/fetch_rsrc.cpp
new file mode 100644
index 000000000..b771f7b2d
--- /dev/null
+++ b/frontends/beos/fetch_rsrc.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* rsrc: URL handling. */
+
+#define __STDBOOL_H__ 1
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <curl/curl.h> /* for URL unescaping functions */
+extern "C" {
+#include "utils/config.h"
+#include "content/fetch.h"
+#include "content/fetchers.h"
+#include "content/urldb.h"
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/ring.h"
+#include "utils/base64.h"
+}
+#include "beos/fetch_rsrc.h"
+#include "beos/filetype.h"
+#include "beos/gui.h"
+
+#include <image.h>
+#include <Resources.h>
+#include <String.h>
+
+struct fetch_rsrc_context {
+ struct fetch *parent_fetch;
+ char *name;
+ char *url;
+ char *mimetype;
+ char *data;
+ size_t datalen;
+
+ bool aborted;
+ bool locked;
+
+ struct fetch_rsrc_context *r_next, *r_prev;
+};
+
+static struct fetch_rsrc_context *ring = NULL;
+
+BResources *gAppResources = NULL;
+
+static bool fetch_rsrc_initialise(lwc_string *scheme)
+{
+ LOG("fetch_rsrc_initialise called for %s", lwc_string_data(scheme));
+ return true;
+}
+
+static void fetch_rsrc_finalise(lwc_string *scheme)
+{
+ LOG("fetch_rsrc_finalise called for %s", lwc_string_data(scheme));
+}
+
+static bool fetch_rsrc_can_fetch(const nsurl *url)
+{
+ return true;
+}
+
+static void *fetch_rsrc_setup(struct fetch *parent_fetch, nsurl *url,
+ bool only_2xx, bool downgrade_tls, const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers)
+{
+ struct fetch_rsrc_context *ctx;
+ ctx = (struct fetch_rsrc_context *)calloc(1, sizeof(*ctx));
+
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->parent_fetch = parent_fetch;
+ /* TODO: keep as nsurl to avoid copy */
+ ctx->url = (char *)malloc(nsurl_length(url) + 1);
+
+ if (ctx->url == NULL) {
+ free(ctx);
+ return NULL;
+ }
+ memcpy(ctx->url, nsurl_access(url), nsurl_length(url) + 1);
+
+ RING_INSERT(ring, ctx);
+
+ return ctx;
+}
+
+static bool fetch_rsrc_start(void *ctx)
+{
+ return true;
+}
+
+static void fetch_rsrc_free(void *ctx)
+{
+ struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx;
+
+ free(c->name);
+ free(c->url);
+ free(c->data);
+ free(c->mimetype);
+ RING_REMOVE(ring, c);
+ free(ctx);
+}
+
+static void fetch_rsrc_abort(void *ctx)
+{
+ struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx;
+
+ /* To avoid the poll loop having to deal with the fetch context
+ * disappearing from under it, we simply flag the abort here.
+ * The poll loop itself will perform the appropriate cleanup.
+ */
+ c->aborted = true;
+}
+
+static void fetch_rsrc_send_callback(const fetch_msg *msg,
+ struct fetch_rsrc_context *c)
+{
+ c->locked = true;
+ fetch_send_callback(msg, c->parent_fetch);
+ c->locked = false;
+}
+
+static bool fetch_rsrc_process(struct fetch_rsrc_context *c)
+{
+ fetch_msg msg;
+ char *params;
+ char *at = NULL;
+ char *slash;
+ char *comma = NULL;
+ char *unescaped;
+ uint32 type = 'data'; // default for embeded files
+ int32 id = 0;
+
+ /* format of a rsrc: URL is:
+ * rsrc://[TYPE][@NUM]/name[,mime]
+ */
+
+ LOG("*** Processing %s", c->url);
+
+ if (strlen(c->url) < 7) {
+ /* 7 is the minimum possible length (rsrc://) */
+ msg.type = FETCH_ERROR;
+ msg.data.error = "Malformed rsrc: URL";
+ fetch_rsrc_send_callback(&msg, c);
+ return false;
+ }
+
+ /* skip the rsrc: part */
+ params = c->url + sizeof("rsrc://") - 1;
+
+ /* find the slash */
+ if ( (slash = strchr(params, '/')) == NULL) {
+ msg.type = FETCH_ERROR;
+ msg.data.error = "Malformed rsrc: URL";
+ fetch_rsrc_send_callback(&msg, c);
+ return false;
+ }
+
+ // doesn't exist in the filesystem but we should hit the internal types.
+ c->mimetype = strdup(fetch_filetype(slash));
+ c->name = strdup(slash + 1);
+
+ if (c->mimetype == NULL) {
+ msg.type = FETCH_ERROR;
+ msg.data.error =
+ "Unable to allocate memory for mimetype in rsrc: URL";
+ fetch_rsrc_send_callback(&msg, c);
+ return false;
+ }
+
+ if (params[0] != '/') {
+ uint8 c1, c2, c3, c4;
+ if (sscanf(params, "%c%c%c%c", &c1, &c2, &c3, &c4) > 3) {
+ type = c1 << 24 | c2 << 16 | c3 << 8 | c4;
+ LOG("fetch_rsrc: type:%4.4s\n", (char *)&type);
+ }
+ }
+
+ LOG("fetch_rsrc: 0x%08lx, %ld, '%s'\n", type, id, c->name);
+
+ bool found;
+ if (id)
+ found = gAppResources->HasResource(type, id);
+ else
+ found = gAppResources->HasResource(type, c->name);
+ if (!found) {
+ BString error("Cannot locate resource: ");
+ if (id)
+ error << id;
+ else
+ error << c->name;
+ msg.type = FETCH_ERROR;
+ msg.data.error = error.String();
+ fetch_rsrc_send_callback(&msg, c);
+ return false;
+ }
+
+ size_t len;
+ const void *data;
+ if (id)
+ data = gAppResources->LoadResource(type, id, &len);
+ else
+ data = gAppResources->LoadResource(type, c->name, &len);
+
+ if (!data) {
+ msg.type = FETCH_ERROR;
+ msg.data.error = "Cannot load rsrc: URL";
+ fetch_rsrc_send_callback(&msg, c);
+ return false;
+ }
+
+ c->datalen = len;
+ c->data = (char *)malloc(c->datalen);
+ if (c->data == NULL) {
+ msg.type = FETCH_ERROR;
+ msg.data.error = "Unable to allocate memory for rsrc: URL";
+ fetch_rsrc_send_callback(&msg, c);
+ return false;
+ }
+ memcpy(c->data, data, c->datalen);
+
+ return true;
+}
+
+static void fetch_rsrc_poll(lwc_string *scheme)
+{
+ fetch_msg msg;
+ struct fetch_rsrc_context *c, *next;
+
+ if (ring == NULL) return;
+
+ /* Iterate over ring, processing each pending fetch */
+ c = ring;
+ do {
+ /* Take a copy of the next pointer as we may destroy
+ * the ring item we're currently processing */
+ next = c->r_next;
+
+ /* Ignore fetches that have been flagged as locked.
+ * This allows safe re-entrant calls to this function.
+ * Re-entrancy can occur if, as a result of a callback,
+ * the interested party causes fetch_poll() to be called
+ * again.
+ */
+ if (c->locked == true) {
+ continue;
+ }
+
+ /* Only process non-aborted fetches */
+ if (!c->aborted && fetch_rsrc_process(c) == true) {
+ char header[64];
+
+ fetch_set_http_code(c->parent_fetch, 200);
+ LOG("setting rsrc: MIME type to %s, length to %zd", c->mimetype, c->datalen);
+ /* Any callback can result in the fetch being aborted.
+ * Therefore, we _must_ check for this after _every_
+ * call to fetch_rsrc_send_callback().
+ */
+ snprintf(header, sizeof header, "Content-Type: %s",
+ c->mimetype);
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf = (const uint8_t *) header;
+ msg.data.header_or_data.len = strlen(header);
+ fetch_rsrc_send_callback(&msg, c);
+
+ snprintf(header, sizeof header, "Content-Length: %zd",
+ c->datalen);
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf = (const uint8_t *) header;
+ msg.data.header_or_data.len = strlen(header);
+ fetch_rsrc_send_callback(&msg, c);
+
+ if (!c->aborted) {
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) c->data;
+ msg.data.header_or_data.len = c->datalen;
+ fetch_rsrc_send_callback(&msg, c);
+ }
+ if (!c->aborted) {
+ msg.type = FETCH_FINISHED;
+ fetch_rsrc_send_callback(&msg, c);
+ }
+ } else {
+ LOG("Processing of %s failed!", c->url);
+
+ /* Ensure that we're unlocked here. If we aren't,
+ * then fetch_rsrc_process() is broken.
+ */
+ assert(c->locked == false);
+ }
+
+ fetch_remove_from_queues(c->parent_fetch);
+ fetch_free(c->parent_fetch);
+
+ /* Advance to next ring entry, exiting if we've reached
+ * the start of the ring or the ring has become empty
+ */
+ } while ( (c = next) != ring && ring != NULL);
+}
+
+/* BAppFileInfo is supposed to find the app's resources for us,
+ * but this won't work if we ever want to be used as a replicant.
+ * This trick should work regardless,
+ */
+static int find_app_resources()
+{
+ char path[B_PATH_NAME_LENGTH];
+ if (nsbeos_find_app_path(path) < B_OK)
+ return B_ERROR;
+ //fprintf(stderr, "loading resources from '%s'\n", path);
+
+ BFile file(path, B_READ_ONLY);
+ if (file.InitCheck() < 0)
+ return file.InitCheck();
+ gAppResources = new BResources;
+ status_t err;
+ err = gAppResources->SetTo(&file);
+ if (err >= B_OK)
+ return B_OK;
+ delete gAppResources;
+ gAppResources = NULL;
+ return err;
+}
+
+BResources *get_app_resources()
+{
+ return gAppResources;
+}
+
+void fetch_rsrc_register(void)
+{
+ lwc_string *scheme;
+ int err;
+ nserror ret;
+
+ const struct fetcher_operation_table fetcher_ops_rsrc = {
+ fetch_rsrc_initialise,
+ fetch_rsrc_can_fetch,
+ fetch_rsrc_setup,
+ fetch_rsrc_start,
+ fetch_rsrc_abort,
+ fetch_rsrc_free,
+ fetch_rsrc_poll,
+ fetch_rsrc_finalise
+ };
+
+ err = find_app_resources();
+
+ if (err < B_OK) {
+ beos_warn_user("Resources", strerror(err));
+ return;
+ }
+
+ if (lwc_intern_string("rsrc", SLEN("rsrc"), &scheme) != lwc_error_ok) {
+ die("Failed to initialise the fetch module "
+ "(couldn't intern \"rsrc\").");
+ }
+
+ ret = fetcher_add(scheme, &fetcher_ops_rsrc);
+ if (ret != NSERROR_OK) {
+ die("unable to add rsrc fetcher.");
+ }
+}
+
+void fetch_rsrc_unregister(void)
+{
+ delete gAppResources;
+ gAppResources = NULL;
+}
diff --git a/frontends/beos/fetch_rsrc.h b/frontends/beos/fetch_rsrc.h
new file mode 100644
index 000000000..ce17670a4
--- /dev/null
+++ b/frontends/beos/fetch_rsrc.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * rsrc: URL method handler
+ */
+
+#ifndef NETSURF_BEOS_FETCH_DATA_H
+#define NETSURF_BEOS_FETCH_DATA_H
+
+void fetch_rsrc_register(void);
+void fetch_rsrc_unregister(void);
+
+class BResources;
+BResources *get_app_resources();
+
+#include "beos/res.h"
+
+#endif
diff --git a/frontends/beos/filetype.cpp b/frontends/beos/filetype.cpp
new file mode 100644
index 000000000..75a33240a
--- /dev/null
+++ b/frontends/beos/filetype.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <Mime.h>
+#include <NodeInfo.h>
+#include <String.h>
+
+extern "C" {
+#include "content/fetch.h"
+#include "utils/log.h"
+#include "utils/hashtable.h"
+#include "utils/utils.h"
+}
+
+#include "beos/filetype.h"
+#include "beos/gui.h"
+
+static struct {
+ const char *type;
+ const char *ext1;
+ const char *ext2;
+} default_types[] = {
+ { "text/plain", "txt", NULL },
+ { "text/html", "htm", "html" },
+ { "text/css", "css", NULL },
+ { "image/gif", "gif", NULL },
+ { "image/jpeg", "jpg", "jpeg" },
+ { "image/png", "png", NULL },
+ { "image/jng", "jng", NULL },
+ { NULL, NULL, NULL }
+};
+
+void beos_fetch_filetype_init(void)
+{
+ BMimeType m;
+ status_t err;
+ int i;
+
+ // make sure we have basic mime types in the database
+ for (i = 0; default_types[i].type; i++) {
+ if (m.SetTo(default_types[i].type) < B_OK)
+ continue;
+ if (m.IsInstalled())
+ continue;
+ err = m.Install();
+ if (err < B_OK) {
+ beos_warn_user("Mime", strerror(err));
+ continue;
+ }
+ // the mime db doesn't know about it yet
+ BMessage extensions('exts');
+ if (default_types[i].ext1)
+ extensions.AddString("extensions", default_types[i].ext1);
+ if (default_types[i].ext2)
+ extensions.AddString("extensions", default_types[i].ext2);
+ err = m.SetFileExtensions(&extensions);
+ if (err < B_OK) {
+ beos_warn_user("Mime", strerror(err));
+ }
+ }
+}
+
+void beos_fetch_filetype_fin(void)
+{
+}
+
+const char *fetch_filetype(const char *unix_path)
+{
+ struct stat statbuf;
+ status_t err;
+ int i;
+ // NOT THREADSAFE
+ static char type[B_MIME_TYPE_LENGTH];
+
+ // override reading the mime type for known types
+ // avoids getting CSS files as text/x-source-code
+ // even though it's the mime sniffer rules that should be fixed.
+ BString ext(unix_path);
+ ext.Remove(0, ext.FindLast('.') + 1);
+ for (i = 0; default_types[i].type; i++) {
+ if (ext == default_types[i].ext1)
+ return default_types[i].type;
+ if (ext == default_types[i].ext2)
+ return default_types[i].type;
+ }
+
+ BEntry entry(unix_path, true);
+ BNode node(&entry);
+ err = node.InitCheck();
+ if (err < B_OK)
+ return "text/plain";
+
+ if (node.IsDirectory())
+ return "application/x-netsurf-directory";
+
+ BNodeInfo info(&node);
+ err = info.InitCheck();
+ if (err < B_OK)
+ return "test/plain";
+
+ err = info.GetType(type);
+ if (err < B_OK) {
+ // not there yet, sniff and retry
+ err = update_mime_info(unix_path, false, true, false);
+ if (err < B_OK)
+ return "text/plain";
+ err = info.GetType(type);
+ if (err < B_OK)
+ return "text/plain";
+ }
+
+ return type;
+}
diff --git a/frontends/beos/filetype.h b/frontends/beos/filetype.h
new file mode 100644
index 000000000..72252dbd0
--- /dev/null
+++ b/frontends/beos/filetype.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+void beos_fetch_filetype_init(void);
+void beos_fetch_filetype_fin(void);
+const char *fetch_filetype(const char *unix_path);
diff --git a/frontends/beos/font.cpp b/frontends/beos/font.cpp
new file mode 100644
index 000000000..003af52b5
--- /dev/null
+++ b/frontends/beos/font.cpp
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Font handling (BeOS implementation).
+ * TODO: check for correctness, the code is taken from the GTK one.
+ * maybe use the current view instead of constructing a new BFont each time ?
+ */
+
+
+#define __STDBOOL_H__ 1
+#include <stdbool.h>
+#include <assert.h>
+#include <stdio.h>
+#include <Font.h>
+#include <String.h>
+#include <View.h>
+
+extern "C" {
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "utils/nsurl.h"
+#include "desktop/gui_layout.h"
+}
+
+#include "beos/gui.h"
+#include "beos/font.h"
+#include "beos/plotters.h"
+
+
+/**
+ * Convert a font style to a PangoFontDescription.
+ *
+ * \param font Beos font object.
+ * \param fstyle style for this text
+ */
+void nsbeos_style_to_font(BFont &font, const struct plot_font_style *fstyle)
+{
+ float size;
+ uint16 face = 0;
+ const char *family;
+
+ switch (fstyle->family) {
+ case PLOT_FONT_FAMILY_SERIF:
+ family = nsoption_charp(font_serif);
+ break;
+ case PLOT_FONT_FAMILY_MONOSPACE:
+ family = nsoption_charp(font_mono);
+ break;
+ case PLOT_FONT_FAMILY_CURSIVE:
+ family = nsoption_charp(font_cursive);
+ break;
+ case PLOT_FONT_FAMILY_FANTASY:
+ family = nsoption_charp(font_fantasy);
+ break;
+ case PLOT_FONT_FAMILY_SANS_SERIF:
+ default:
+ family = nsoption_charp(font_sans);
+ break;
+ }
+
+ if ((fstyle->flags & FONTF_ITALIC)) {
+ face = B_ITALIC_FACE;
+ } else if ((fstyle->flags & FONTF_OBLIQUE)) {
+ face = B_ITALIC_FACE;
+ // XXX: no OBLIQUE flag ??
+ // maybe find "Oblique" style
+ // or use SetShear() ?
+ }
+
+#ifndef __HAIKU__XXX
+ if (fstyle->weight >= 600) {
+ face |= B_BOLD_FACE;
+ }
+#else
+ if (fstyle->weight >= 600) {
+ if (fstyle->weight >= 800)
+ face |= B_HEAVY_FACE;
+ else
+ face |= B_BOLD_FACE;
+ } else if (fstyle->weight <= 300) {
+ face |= B_LIGHT_FACE;
+ }
+#endif
+/*
+ case CSS_FONT_WEIGHT_100: weight = 100; break;
+ case CSS_FONT_WEIGHT_200: weight = 200; break;
+ case CSS_FONT_WEIGHT_300: weight = 300; break;
+ case CSS_FONT_WEIGHT_400: weight = 400; break;
+ case CSS_FONT_WEIGHT_500: weight = 500; break;
+ case CSS_FONT_WEIGHT_600: weight = 600; break;
+ case CSS_FONT_WEIGHT_700: weight = 700; break;
+ case CSS_FONT_WEIGHT_800: weight = 800; break;
+ case CSS_FONT_WEIGHT_900: weight = 900; break;
+*/
+
+ if (!face)
+ face = B_REGULAR_FACE;
+
+//fprintf(stderr, "nsbeos_style_to_font: %d, %d, %d -> '%s' %04x\n", style->font_family, style->font_style, style->font_weight, family, face);
+
+ if (family) {
+ font_family beos_family;
+
+ strncpy(beos_family, family, B_FONT_FAMILY_LENGTH);
+ // Ensure it's terminated
+ beos_family[B_FONT_FAMILY_LENGTH] = '\0';
+
+ font.SetFamilyAndFace(beos_family, face);
+ } else {
+ //XXX not used
+ font = be_plain_font;
+ font.SetFace(face);
+ }
+
+//fprintf(stderr, "nsbeos_style_to_font: value %f unit %d\n", style->font_size.value.length.value, style->font_size.value.length.unit);
+ size = fstyle->size / FONT_SIZE_SCALE;
+
+//fprintf(stderr, "nsbeos_style_to_font: %f %d\n", size, style->font_size.value.length.unit);
+
+ font.SetSize(size);
+}
+
+
+/**
+ * Measure the width of a string.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param width updated to width of string[0..length)
+ * \return true on success, false on error and error reported
+ */
+static nserror beos_font_width(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int *width)
+{
+ //fprintf(stderr, "%s(, '%s', %d, )\n", __FUNCTION__, string, length);
+ BFont font;
+
+ if (length == 0) {
+ *width = 0;
+ return NSERROR_OK;
+ }
+
+ nsbeos_style_to_font(font, fstyle);
+ *width = (int)font.StringWidth(string, length);
+
+ return NSERROR_OK;
+}
+
+
+static int utf8_char_len(const char *c)
+{
+ uint8 *p = (uint8 *)c;
+ uint8 m = 0xE0;
+ uint8 v = 0xC0;
+ int i;
+
+ if (!*p)
+ return 0;
+ if ((*p & 0x80) == 0)
+ return 1;
+ if ((*p & 0xC0) == 0x80)
+ return 1; // actually one of the remaining bytes...
+ for (i = 2; i < 5; i++) {
+ if ((*p & m) == v)
+ return i;
+ v = (v >> 1) | 0x80;
+ m = (m >> 1) | 0x80;
+ }
+ return i;
+}
+
+
+/**
+ * Find the position in a string where an x coordinate falls.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x x coordinate to search for
+ * \param char_offset updated to offset in string of actual_x, [0..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ */
+static nserror beos_font_position(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ //LOG("(, '%s', %d, %d, , )", string, length, x);
+ //fprintf(stderr, "%s(, '%s', %d, %d, , )\n", __FUNCTION__, string, length, x);
+ int index;
+ BFont font;
+
+ nsbeos_style_to_font(font, fstyle);
+ BString str(string);
+ int32 len = str.CountChars();
+ float escapements[len];
+ float esc = 0.0;
+ float current = 0.0;
+ int i;
+
+ index = 0;
+ font.GetEscapements(string, len, escapements);
+ // slow but it should work
+ for (i = 0; string[index] && i < len; i++) {
+ esc += escapements[i];
+ current = font.Size() * esc;
+ index += utf8_char_len(&string[index]);
+ // is current char already too far away?
+ if (x < current)
+ break;
+ }
+ *actual_x = (int)current;
+ *char_offset = i; //index;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find where to split a string to make it fit a width.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string, in bytes
+ * \param x width available
+ * \param char_offset updated to offset in string of actual_x, [1..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ *
+ * On exit, char_offset indicates first character after split point.
+ *
+ * Note: char_offset of 0 should never be returned.
+ *
+ * Returns:
+ * char_offset giving split point closest to x, where actual_x <= x
+ * else
+ * char_offset giving split point closest to x, where actual_x > x
+ *
+ * Returning char_offset == length means no split possible
+ */
+static nserror beos_font_split(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ //fprintf(stderr, "%s(, '%s', %d, %d, , )\n", __FUNCTION__, string, length, x);
+ //LOG("(, '%s', %d, %d, , )", string, length, x);
+ int index = 0;
+ BFont font;
+
+ nsbeos_style_to_font(font, fstyle);
+ BString str(string);
+ int32 len = str.CountChars();
+ float escapements[len];
+ float esc = 0.0;
+ float current = 0.0;
+ float last_x = 0.0;
+ int i;
+ int last_space = 0;
+
+ font.GetEscapements(string, len, escapements);
+ // very slow but it should work
+ for (i = 0; string[index] && i < len; i++) {
+ if (string[index] == ' ') {
+ last_x = current;
+ last_space = index;
+ }
+ if (x < current && last_space != 0) {
+ *actual_x = (int)last_x;
+ *char_offset = last_space;
+ return NSERROR_OK;;
+ }
+ esc += escapements[i];
+ current = font.Size() * esc;
+ index += utf8_char_len(&string[index]);
+ }
+ *actual_x = MIN(*actual_x, (int)current);
+ *char_offset = index;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Render a string.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x x coordinate
+ * \param y y coordinate
+ * \return true on success, false on error and error reported
+ */
+
+bool nsfont_paint(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, int y)
+{
+ //fprintf(stderr, "%s(, '%s', %d, %d, %d, )\n", __FUNCTION__, string, length, x, y);
+ //CALLED();
+ BFont font;
+ rgb_color oldbg;
+ rgb_color background;
+ rgb_color foreground;
+ BView *view;
+ float size;
+
+ if (length == 0)
+ return true;
+
+ nsbeos_style_to_font(font, fstyle);
+ background = nsbeos_rgb_colour(fstyle->background);
+ foreground = nsbeos_rgb_colour(fstyle->foreground);
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ oldbg = view->LowColor();
+ drawing_mode oldmode = view->DrawingMode();
+ view->SetLowColor(B_TRANSPARENT_32_BIT);
+
+ //view->SetScale() XXX
+
+//printf("nsfont_paint: Size: %f\n", font.Size());
+ size = (float)font.Size();
+#warning XXX use scale
+
+ view->SetFont(&font);
+ view->SetHighColor(foreground);
+ view->SetDrawingMode(B_OP_OVER);
+
+ BString line(string, length);
+
+ BPoint where(x, y + 1);
+ view->DrawString(line.String(), where);
+
+ view->SetDrawingMode(oldmode);
+ if (memcmp(&oldbg, &background, sizeof(rgb_color)))
+ view->SetLowColor(oldbg);
+
+ //nsbeos_current_gc_unlock();
+
+ return true;
+}
+
+
+static struct gui_layout_table layout_table = {
+ /*.width = */beos_font_width,
+ /*.position = */beos_font_position,
+ /*.split = */beos_font_split
+};
+
+struct gui_layout_table *beos_layout_table = &layout_table;
diff --git a/frontends/beos/font.h b/frontends/beos/font.h
new file mode 100644
index 000000000..63909efcf
--- /dev/null
+++ b/frontends/beos/font.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Beos font layout handling interface.
+ */
+
+#ifndef NS_BEOS_FONT_H
+#define NS_BEOS_FONT_H
+
+#include "desktop/plot_style.h"
+
+bool nsfont_paint(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, int y);
+
+void nsbeos_style_to_font(BFont &font, const struct plot_font_style *fstyle);
+
+extern struct gui_layout_table *beos_layout_table;
+
+#endif
diff --git a/frontends/beos/gui.cpp b/frontends/beos/gui.cpp
new file mode 100644
index 000000000..2e0aa4cc5
--- /dev/null
+++ b/frontends/beos/gui.cpp
@@ -0,0 +1,1109 @@
+/*
+ * Copyright 2015 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <curl/curl.h>
+
+#include <Alert.h>
+#include <Application.h>
+#include <BeBuild.h>
+#include <FindDirectory.h>
+#include <Mime.h>
+#include <Path.h>
+#include <PathFinder.h>
+#include <Resources.h>
+#include <Roster.h>
+#include <Screen.h>
+#include <String.h>
+
+extern "C" {
+
+#include "utils/nsoption.h"
+#include "utils/filename.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/corestrings.h"
+#include "utils/utf8.h"
+#include "utils/utils.h"
+
+#include "content/content.h"
+#include "content/content_protected.h"
+#include "content/fetch.h"
+#include "content/fetchers.h"
+#include "content/fetchers/resource.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/gui_misc.h"
+#include "desktop/gui_clipboard.h"
+#include "desktop/gui_search.h"
+#include "desktop/gui_fetch.h"
+#include "desktop/netsurf.h"
+
+}
+
+#include "beos/gui.h"
+#include "beos/gui_options.h"
+//#include "beos/completion.h"
+#include "beos/window.h"
+#include "beos/throbber.h"
+#include "beos/filetype.h"
+#include "beos/download.h"
+#include "beos/schedule.h"
+#include "beos/fetch_rsrc.h"
+#include "beos/scaffolding.h"
+#include "beos/bitmap.h"
+#include "beos/font.h"
+
+//TODO: use resources
+// enable using resources instead of files
+#define USE_RESOURCES 1
+
+bool nsbeos_done = false;
+
+bool replicated = false; /**< if we are running as a replicant */
+
+char *options_file_location;
+char *glade_file_location;
+
+struct gui_window *search_current_window = 0;
+
+BWindow *wndAbout;
+BWindow *wndWarning;
+//GladeXML *gladeWindows;
+BWindow *wndTooltip;
+//beosLabel *labelTooltip;
+BFilePanel *wndOpenFile;
+
+static thread_id sBAppThreadID;
+
+static BMessage *gFirstRefsReceived = NULL;
+
+static int sEventPipe[2];
+
+// #pragma mark - class NSBrowserFrameView
+
+
+/* exported function defined in beos/gui.h */
+nserror beos_warn_user(const char *warning, const char *detail)
+{
+ LOG("warn_user: %s (%s)", warning, detail);
+ BAlert *alert;
+ BString text(warning);
+ if (detail)
+ text << ":\n" << detail;
+
+ alert = new BAlert("NetSurf Warning", text.String(), "Debug", "Ok",
+ NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
+ if (alert->Go() < 1) {
+ debugger("warn_user");
+ }
+
+ return NSERROR_OK;
+}
+
+NSBrowserApplication::NSBrowserApplication()
+ : BApplication("application/x-vnd.NetSurf")
+{
+}
+
+
+NSBrowserApplication::~NSBrowserApplication()
+{
+}
+
+
+void
+NSBrowserApplication::MessageReceived(BMessage *message)
+{
+ switch (message->what) {
+ case B_REFS_RECEIVED:
+ case B_UI_SETTINGS_CHANGED:
+ // messages for top-level
+ // we'll just send them to the first window
+ case 'back':
+ case 'forw':
+ case 'stop':
+ case 'relo':
+ case 'home':
+ case 'urlc':
+ case 'urle':
+ case 'sear':
+ case 'menu':
+ // NetPositive messages
+ case B_NETPOSITIVE_OPEN_URL:
+ case B_NETPOSITIVE_BACK:
+ case B_NETPOSITIVE_FORWARD:
+ case B_NETPOSITIVE_HOME:
+ case B_NETPOSITIVE_RELOAD:
+ case B_NETPOSITIVE_STOP:
+ case B_NETPOSITIVE_DOWN:
+ case B_NETPOSITIVE_UP:
+ //DetachCurrentMessage();
+ //nsbeos_pipe_message(message, this, fGuiWindow);
+ break;
+ default:
+ BApplication::MessageReceived(message);
+ }
+}
+
+
+void
+NSBrowserApplication::ArgvReceived(int32 argc, char **argv)
+{
+ NSBrowserWindow *win = nsbeos_find_last_window();
+ if (!win) {
+ return;
+ }
+ win->Unlock();
+ BMessage *message = DetachCurrentMessage();
+ nsbeos_pipe_message_top(message, win, win->Scaffolding());
+}
+
+
+void
+NSBrowserApplication::RefsReceived(BMessage *message)
+{
+ DetachCurrentMessage();
+ NSBrowserWindow *win = nsbeos_find_last_window();
+ if (!win) {
+ gFirstRefsReceived = message;
+ return;
+ }
+ win->Unlock();
+ nsbeos_pipe_message_top(message, win, win->Scaffolding());
+}
+
+
+void
+NSBrowserApplication::AboutRequested()
+{
+ nsbeos_pipe_message(new BMessage(B_ABOUT_REQUESTED), NULL, NULL);
+}
+
+
+bool
+NSBrowserApplication::QuitRequested()
+{
+ // let it notice it
+ nsbeos_pipe_message(new BMessage(B_QUIT_REQUESTED), NULL, NULL);
+ // we'll let the main thread Quit() ourselves when it's done.
+ return false;
+}
+
+
+// #pragma mark - implementation
+
+
+
+/* realpath fallback on R5 */
+#if !defined(__HAIKU__) && !defined(B_BEOS_VERSION_DANO)
+extern "C" char *realpath(const char *f, char *buf);
+char *realpath(const char *f, char *buf)
+{
+ BPath path(f, NULL, true);
+ if (path.InitCheck() < 0) {
+ strncpy(buf, f, MAXPATHLEN);
+ return NULL;
+ }
+ //printf("RP: '%s'\n", path.Path());
+ strncpy(buf, path.Path(), MAXPATHLEN);
+ return buf;
+}
+#endif
+
+/* finds the NetSurf binary image ID and path
+ *
+ */
+image_id nsbeos_find_app_path(char *path)
+{
+ image_info info;
+ int32 cookie = 0;
+ while (get_next_image_info(0, &cookie, &info) == B_OK) {
+//fprintf(stderr, "%p <> %p, %p\n", (char *)&find_app_resources, (char *)info.text, (char *)info.text + info.text_size);
+ if (((char *)&nsbeos_find_app_path >= (char *)info.text)
+ && ((char *)&nsbeos_find_app_path < (char *)info.text + info.text_size)) {
+//fprintf(stderr, "match\n");
+ if (path) {
+ memset(path, 0, B_PATH_NAME_LENGTH);
+ strncpy(path, info.name, B_PATH_NAME_LENGTH-1);
+ }
+ return info.id;
+ }
+ }
+ return B_ERROR;
+}
+
+/**
+ * Locate a shared resource file by searching known places in order.
+ *
+ * Search order is: ~/config/settings/NetSurf/, ~/.netsurf/, $NETSURFRES/
+ * (where NETSURFRES is an environment variable), and finally the path
+ * specified by the macro at the top of this file.
+ *
+ * \param buf buffer to write to. must be at least PATH_MAX chars
+ * \param filename file to look for
+ * \param def default to return if file not found
+ * \return path to resource.
+ */
+char *find_resource(char *buf, const char *filename, const char *def)
+{
+ const char *cdir = NULL;
+ status_t err;
+ BPath path;
+ char t[PATH_MAX];
+
+ err = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
+ path.Append("NetSurf");
+ if (err >= B_OK)
+ cdir = path.Path();
+ if (cdir != NULL) {
+ strcpy(t, cdir);
+ strcat(t, "/");
+ strcat(t, filename);
+ realpath(t, buf);
+ if (access(buf, R_OK) == 0)
+ return buf;
+ }
+
+ cdir = getenv("HOME");
+ if (cdir != NULL) {
+ strcpy(t, cdir);
+ strcat(t, "/.netsurf/");
+ strcat(t, filename);
+ realpath(t, buf);
+ if (access(buf, R_OK) == 0)
+ return buf;
+ }
+
+ cdir = getenv("NETSURFRES");
+
+ if (cdir != NULL) {
+ realpath(cdir, buf);
+ strcat(buf, "/");
+ strcat(buf, filename);
+ if (access(buf, R_OK) == 0)
+ return buf;
+ }
+
+
+ BPathFinder f((void*)find_resource);
+
+ BPath p;
+ if (f.FindPath(B_FIND_PATH_APPS_DIRECTORY, "netsurf/res", p) == B_OK) {
+ strcpy(t, p.Path());
+ strcat(t, filename);
+ realpath(t, buf);
+ if (access(buf, R_OK) == 0)
+ return buf;
+ }
+
+ if (def[0] == '%') {
+ snprintf(t, PATH_MAX, "%s%s", path.Path(), def + 1);
+ if (realpath(t, buf) == NULL) {
+ strcpy(buf, t);
+ }
+ } else if (def[0] == '~') {
+ snprintf(t, PATH_MAX, "%s%s", getenv("HOME"), def + 1);
+ if (realpath(t, buf) == NULL) {
+ strcpy(buf, t);
+ }
+ } else {
+ if (realpath(def, buf) == NULL) {
+ strcpy(buf, def);
+ }
+ }
+
+ return buf;
+}
+
+/**
+ * Check that ~/.netsurf/ exists, and if it doesn't, create it.
+ */
+static void check_homedir(void)
+{
+ status_t err;
+
+ BPath path;
+ err = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
+
+ if (err < B_OK) {
+ /* we really can't continue without a home directory. */
+ LOG("Can't find user settings directory - nowhere to store state!");
+ die("NetSurf needs to find the user settings directory in order to run.\n");
+ }
+
+ path.Append("NetSurf");
+ err = create_directory(path.Path(), 0644);
+ if (err < B_OK) {
+ LOG("Unable to create %s", path.Path());
+ die("NetSurf could not create its settings directory.\n");
+ }
+}
+
+static int32 bapp_thread(void *arg)
+{
+ be_app->Lock();
+ be_app->Run();
+ return 0;
+}
+
+static nsurl *gui_get_resource_url(const char *path)
+{
+ nsurl *url = NULL;
+ BString u("rsrc:///");
+
+ /* default.css -> beosdefault.css */
+ if (strcmp(path, "default.css") == 0)
+ path = "beosdefault.css";
+
+ /* favicon.ico -> favicon.png */
+ if (strcmp(path, "favicon.ico") == 0)
+ path = "favicon.png";
+
+ u << path;
+ LOG("(%s) -> '%s'\n", path, u.String());
+ nsurl_create(u.String(), &url);
+ return url;
+}
+
+
+
+#if !defined(__HAIKU__) && !defined(B_BEOS_VERSION_DANO)
+/* more ui_colors, R5 only had a few defined... */
+#define B_PANEL_TEXT_COLOR ((color_which)10)
+#define B_DOCUMENT_BACKGROUND_COLOR ((color_which)11)
+#define B_DOCUMENT_TEXT_COLOR ((color_which)12)
+#define B_CONTROL_BACKGROUND_COLOR ((color_which)13)
+#define B_CONTROL_TEXT_COLOR ((color_which)14)
+#define B_CONTROL_BORDER_COLOR ((color_which)15)
+#define B_CONTROL_HIGHLIGHT_COLOR ((color_which)16)
+#define B_NAVIGATION_BASE_COLOR ((color_which)4)
+#define B_NAVIGATION_PULSE_COLOR ((color_which)17)
+#define B_SHINE_COLOR ((color_which)18)
+#define B_SHADOW_COLOR ((color_which)19)
+#define B_MENU_SELECTED_BORDER_COLOR ((color_which)9)
+#define B_TOOL_TIP_BACKGROUND_COLOR ((color_which)20)
+#define B_TOOL_TIP_TEXT_COLOR ((color_which)21)
+#define B_SUCCESS_COLOR ((color_which)100)
+#define B_FAILURE_COLOR ((color_which)101)
+#define B_MENU_SELECTED_BACKGROUND_COLOR B_MENU_SELECTION_BACKGROUND_COLOR
+#define B_RANDOM_COLOR ((color_which)0x80000000)
+#define B_MICHELANGELO_FAVORITE_COLOR ((color_which)0x80000001)
+#define B_DSANDLER_FAVORITE_SKY_COLOR ((color_which)0x80000002)
+#define B_DSANDLER_FAVORITE_INK_COLOR ((color_which)0x80000003)
+#define B_DSANDLER_FAVORITE_SHOES_COLOR ((color_which)0x80000004)
+#define B_DAVE_BROWN_FAVORITE_COLOR ((color_which)0x80000005)
+#endif
+#if defined(B_BEOS_VERSION_DANO)
+#define B_TOOL_TIP_BACKGROUND_COLOR B_TOOLTIP_BACKGROUND_COLOR
+#define B_TOOL_TIP_TEXT_COLOR B_TOOLTIP_TEXT_COLOR
+#define
+#endif
+#define NOCOL ((color_which)0)
+
+/**
+ * set option from pen
+ */
+static nserror
+set_colour_from_ui(struct nsoption_s *opts,
+ color_which ui,
+ enum nsoption_e option,
+ colour def_colour)
+{
+ if (ui != NOCOL) {
+ rgb_color c;
+ if (ui == B_DESKTOP_COLOR) {
+ BScreen s;
+ c = s.DesktopColor();
+ } else {
+ c = ui_color(ui);
+ }
+
+ def_colour = ((((uint32_t)c.blue << 16) & 0xff0000) |
+ ((c.green << 8) & 0x00ff00) |
+ ((c.red) & 0x0000ff));
+ }
+
+ opts[option].value.c = def_colour;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Set option defaults for framebuffer frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
+{
+ /* set system colours for beos ui */
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ActiveBorder, 0x00000000);
+ set_colour_from_ui(defaults, B_WINDOW_TAB_COLOR, NSOPTION_sys_colour_ActiveCaption, 0x00dddddd);
+ set_colour_from_ui(defaults, B_PANEL_BACKGROUND_COLOR, NSOPTION_sys_colour_AppWorkspace, 0x00eeeeee);
+ set_colour_from_ui(defaults, B_DESKTOP_COLOR, NSOPTION_sys_colour_Background, 0x00aa0000);
+ set_colour_from_ui(defaults, B_CONTROL_BACKGROUND_COLOR, NSOPTION_sys_colour_ButtonFace, 0x00aaaaaa);
+ set_colour_from_ui(defaults, B_CONTROL_HIGHLIGHT_COLOR, NSOPTION_sys_colour_ButtonHighlight, 0x00cccccc);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ButtonShadow, 0x00bbbbbb);
+ set_colour_from_ui(defaults, B_CONTROL_TEXT_COLOR, NSOPTION_sys_colour_ButtonText, 0x00000000);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_CaptionText, 0x00000000);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_GrayText, 0x00777777);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_Highlight, 0x00ee0000);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_HighlightText, 0x00000000);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_InactiveBorder, 0x00000000);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_InactiveCaption, 0x00ffffff);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_InactiveCaptionText, 0x00cccccc);
+ set_colour_from_ui(defaults, B_TOOL_TIP_BACKGROUND_COLOR, NSOPTION_sys_colour_InfoBackground, 0x00aaaaaa);
+ set_colour_from_ui(defaults, B_TOOL_TIP_TEXT_COLOR, NSOPTION_sys_colour_InfoText, 0x00000000);
+ set_colour_from_ui(defaults, B_MENU_BACKGROUND_COLOR, NSOPTION_sys_colour_Menu, 0x00aaaaaa);
+ set_colour_from_ui(defaults, B_MENU_ITEM_TEXT_COLOR, NSOPTION_sys_colour_MenuText, 0x00000000);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_Scrollbar, 0x00aaaaaa);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDDarkShadow, 0x00555555);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDFace, 0x00dddddd);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDHighlight, 0x00aaaaaa);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDLightShadow, 0x00999999);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDShadow, 0x00777777);
+ set_colour_from_ui(defaults, B_DOCUMENT_BACKGROUND_COLOR, NSOPTION_sys_colour_Window, 0x00aaaaaa);
+ set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_WindowFrame, 0x00000000);
+ set_colour_from_ui(defaults, B_DOCUMENT_TEXT_COLOR, NSOPTION_sys_colour_WindowText, 0x00000000);
+
+ return NSERROR_OK;
+}
+
+void nsbeos_update_system_ui_colors(void)
+{
+ set_defaults(nsoptions);
+}
+
+/**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+ /* set log stream to be non-buffering */
+ setbuf(fptr, NULL);
+
+ return true;
+}
+
+static BPath get_messages_path()
+{
+ BPathFinder f((void*)get_messages_path);
+
+ BPath p;
+ f.FindPath(B_FIND_PATH_APPS_DIRECTORY, "netsurf/res", p);
+ // TODO: use Haiku's BLocale stuff
+ BString lang(getenv("LC_MESSAGES"));
+ lang.Truncate(2);
+ BDirectory d(p.Path());
+ if (!d.Contains(lang.String(), B_DIRECTORY_NODE))
+ lang = "en";
+ p.Append(lang.String());
+ p.Append("Messages");
+ return p;
+}
+
+
+static void gui_init(int argc, char** argv)
+{
+ const char *addr;
+ nsurl *url;
+ nserror error;
+ char buf[PATH_MAX];
+
+ if (pipe(sEventPipe) < 0)
+ return;
+ if (!replicated) {
+ sBAppThreadID = spawn_thread(bapp_thread, "BApplication(NetSurf)", B_NORMAL_PRIORITY, (void *)find_thread(NULL));
+ if (sBAppThreadID < B_OK)
+ return; /* #### handle errors */
+ if (resume_thread(sBAppThreadID) < B_OK)
+ return;
+ }
+
+ nsbeos_update_system_ui_colors();
+
+ fetch_rsrc_register();
+
+ check_homedir();
+
+ // make sure the cache dir exists
+ create_directory(TEMP_FILENAME_PREFIX, 0700);
+
+ //nsbeos_completion_init();
+
+
+ /* This is an ugly hack to just get the new-style throbber going.
+ * It, along with the PNG throbber loader, need making more generic.
+ */
+ {
+#define STROF(n) #n
+#define FIND_THROB(n) filenames[(n)] = \
+ "throbber/throbber" STROF(n) ".png";
+ const char *filenames[9];
+ FIND_THROB(0);
+ FIND_THROB(1);
+ FIND_THROB(2);
+ FIND_THROB(3);
+ FIND_THROB(4);
+ FIND_THROB(5);
+ FIND_THROB(6);
+ FIND_THROB(7);
+ FIND_THROB(8);
+ nsbeos_throbber_initialise_from_png(9,
+ filenames[0], filenames[1], filenames[2], filenames[3],
+ filenames[4], filenames[5], filenames[6], filenames[7],
+ filenames[8]);
+#undef FIND_THROB
+#undef STROF
+ }
+
+ if (nsbeos_throbber == NULL)
+ die("Unable to load throbber image.\n");
+
+ find_resource(buf, "Choices", "%/Choices");
+ LOG("Using '%s' as Preferences file", buf);
+ options_file_location = strdup(buf);
+ nsoption_read(buf, NULL);
+
+
+ /* check what the font settings are, setting them to a default font
+ * if they're not set - stops Pango whinging
+ */
+#define SETFONTDEFAULT(OPTION,y) if (nsoption_charp(OPTION) == NULL) nsoption_set_charp(OPTION, strdup((y)))
+
+ //XXX: use be_plain_font & friends, when we can check if font is serif or not.
+/*
+ font_family family;
+ font_style style;
+ be_plain_font->GetFamilyAndStyle(&family, &style);
+ SETFONTDEFAULT(font_sans, family);
+ SETFONTDEFAULT(font_serif, family);
+ SETFONTDEFAULT(font_mono, family);
+ SETFONTDEFAULT(font_cursive, family);
+ SETFONTDEFAULT(font_fantasy, family);
+*/
+#ifdef __HAIKU__
+ SETFONTDEFAULT(font_sans, "DejaVu Sans");
+ SETFONTDEFAULT(font_serif, "DejaVu Serif");
+ SETFONTDEFAULT(font_mono, "DejaVu Mono");
+ SETFONTDEFAULT(font_cursive, "DejaVu Sans");
+ SETFONTDEFAULT(font_fantasy, "DejaVu Sans");
+#else
+ SETFONTDEFAULT(font_sans, "Bitstream Vera Sans");
+ SETFONTDEFAULT(font_serif, "Bitstream Vera Serif");
+ SETFONTDEFAULT(font_mono, "Bitstream Vera Sans Mono");
+ SETFONTDEFAULT(font_cursive, "Bitstream Vera Serif");
+ SETFONTDEFAULT(font_fantasy, "Bitstream Vera Serif");
+#endif
+
+ nsbeos_options_init();
+
+ /* We don't yet have an implementation of "select" form elements (they should use a popup menu)
+ * So we use the cross-platform code instead. */
+ nsoption_set_bool(core_select_menu, true);
+
+ if (nsoption_charp(cookie_file) == NULL) {
+ find_resource(buf, "Cookies", "%/Cookies");
+ LOG("Using '%s' as Cookies file", buf);
+ nsoption_set_charp(cookie_file, strdup(buf));
+ }
+ if (nsoption_charp(cookie_jar) == NULL) {
+ find_resource(buf, "Cookies", "%/Cookies");
+ LOG("Using '%s' as Cookie Jar file", buf);
+ nsoption_set_charp(cookie_jar, strdup(buf));
+ }
+ if ((nsoption_charp(cookie_file) == NULL) ||
+ (nsoption_charp(cookie_jar) == NULL))
+ die("Failed initialising cookie options");
+
+ if (nsoption_charp(url_file) == NULL) {
+ find_resource(buf, "URLs", "%/URLs");
+ LOG("Using '%s' as URL file", buf);
+ nsoption_set_charp(url_file, strdup(buf));
+ }
+
+ if (nsoption_charp(ca_path) == NULL) {
+ find_resource(buf, "certs", "/etc/ssl/certs");
+ LOG("Using '%s' as certificate path", buf);
+ nsoption_set_charp(ca_path, strdup(buf));
+ }
+
+ //find_resource(buf, "mime.types", "/etc/mime.types");
+ beos_fetch_filetype_init();
+
+ urldb_load(nsoption_charp(url_file));
+ urldb_load_cookies(nsoption_charp(cookie_file));
+
+ //nsbeos_download_initialise();
+
+ if (!replicated)
+ be_app->Unlock();
+
+ if (argc > 1) {
+ addr = argv[1];
+ } else if (nsoption_charp(homepage_url) != NULL) {
+ addr = nsoption_charp(homepage_url);
+ } else {
+ addr = NETSURF_HOMEPAGE;
+ }
+
+ /* create an initial browser window */
+ error = nsurl_create(addr, &url);
+ if (error == NSERROR_OK) {
+ error = browser_window_create(
+ BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (error != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(error), 0);
+ }
+
+ if (gFirstRefsReceived) {
+ // resend the refs we got before having a window to send them to
+ be_app_messenger.SendMessage(gFirstRefsReceived);
+ delete gFirstRefsReceived;
+ gFirstRefsReceived = NULL;
+ }
+
+}
+
+
+
+
+void nsbeos_pipe_message(BMessage *message, BView *_this, struct gui_window *gui)
+{
+ if (message == NULL) {
+ fprintf(stderr, "%s(NULL)!\n", __FUNCTION__);
+ return;
+ }
+ if (_this)
+ message->AddPointer("View", _this);
+ if (gui)
+ message->AddPointer("gui_window", gui);
+ write(sEventPipe[1], &message, sizeof(void *));
+}
+
+
+void nsbeos_pipe_message_top(BMessage *message, BWindow *_this, struct beos_scaffolding *scaffold)
+{
+ if (message == NULL) {
+ fprintf(stderr, "%s(NULL)!\n", __FUNCTION__);
+ return;
+ }
+ if (_this)
+ message->AddPointer("Window", _this);
+ if (scaffold)
+ message->AddPointer("scaffolding", scaffold);
+ write(sEventPipe[1], &message, sizeof(void *));
+}
+
+
+void nsbeos_gui_poll(void)
+{
+ fd_set read_fd_set, write_fd_set, exc_fd_set;
+ int max_fd;
+ struct timeval timeout;
+ unsigned int fd_count = 0;
+ bigtime_t next_schedule = 0;
+
+ /* get any active fetcher fd */
+ fetcher_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd);
+
+ /* run the scheduler */
+ schedule_run();
+
+ // our own event pipe
+ FD_SET(sEventPipe[0], &read_fd_set);
+
+ // max of all the fds in the set, plus one for select()
+ max_fd = MAX(max_fd, sEventPipe[0]) + 1;
+
+ // compute schedule timeout
+ if (earliest_callback_timeout != B_INFINITE_TIMEOUT) {
+ next_schedule = earliest_callback_timeout - system_time();
+ } else {
+ next_schedule = earliest_callback_timeout;
+ }
+
+ // we're quite late already...
+ if (next_schedule < 0)
+ next_schedule = 0;
+
+ timeout.tv_sec = (long)(next_schedule / 1000000LL);
+ timeout.tv_usec = (long)(next_schedule % 1000000LL);
+
+ //LOG("gui_poll: select(%d, ..., %Ldus", max_fd, next_schedule);
+ fd_count = select(max_fd, &read_fd_set, &write_fd_set, &exc_fd_set,
+ &timeout);
+ //LOG("select: %d\n", fd_count);
+
+ if (fd_count > 0 && FD_ISSET(sEventPipe[0], &read_fd_set)) {
+ BMessage *message;
+ int len = read(sEventPipe[0], &message, sizeof(void *));
+ //LOG("gui_poll: BMessage ? %d read", len);
+ if (len == sizeof(void *)) {
+ //LOG("gui_poll: BMessage.what %-4.4s\n", &(message->what));
+ nsbeos_dispatch_event(message);
+ }
+ }
+}
+
+
+static void gui_quit(void)
+{
+ urldb_save_cookies(nsoption_charp(cookie_jar));
+ urldb_save(nsoption_charp(url_file));
+ //options_save_tree(hotlist,nsoption_charp(hotlist_file),messages_get("TreeHotlist"));
+
+ free(nsoption_charp(cookie_file));
+ free(nsoption_charp(cookie_jar));
+ beos_fetch_filetype_fin();
+ fetch_rsrc_unregister();
+}
+
+static char *url_to_path(const char *url)
+{
+ char *url_path = curl_unescape(url, 0);
+ char *path;
+
+ /* return the absolute path including leading / */
+ path = strdup(url_path + (FILE_SCHEME_PREFIX_LEN - 1));
+ curl_free(url_path);
+
+ return path;
+}
+
+/**
+ * Send the source of a content to a text editor.
+ */
+
+void nsbeos_gui_view_source(struct hlcache_handle *content)
+{
+ char *temp_name;
+ bool done = false;
+ BPath path;
+ status_t err;
+ size_t size;
+ const char *source = content_get_source_data(content, &size);
+
+ if (!content || !source) {
+ beos_warn_user("MiscError", "No document source");
+ return;
+ }
+
+ /* try to load local files directly. */
+ temp_name = url_to_path(nsurl_access(hlcache_handle_get_url(content)));
+ if (temp_name) {
+ path.SetTo(temp_name);
+ BEntry entry;
+ if (entry.SetTo(path.Path()) >= B_OK
+ && entry.Exists() && entry.IsFile())
+ done = true;
+ }
+ if (!done) {
+ /* We cannot release the requested filename until after it
+ * has finished being used. As we can't easily find out when
+ * this is, we simply don't bother releasing it and simply
+ * allow it to be re-used next time NetSurf is started. The
+ * memory overhead from doing this is under 1 byte per
+ * filename. */
+ const char *filename = filename_request();
+ if (!filename) {
+ beos_warn_user("NoMemory", 0);
+ return;
+ }
+ path.SetTo(TEMP_FILENAME_PREFIX);
+ path.Append(filename);
+ BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE);
+ err = file.InitCheck();
+ if (err < B_OK) {
+ beos_warn_user("IOError", strerror(err));
+ return;
+ }
+ err = file.Write(source, size);
+ if (err < B_OK) {
+ beos_warn_user("IOError", strerror(err));
+ return;
+ }
+ lwc_string *mime = content_get_mime_type(content);
+ if (mime) {
+ file.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0LL,
+ lwc_string_data(mime), lwc_string_length(mime) + 1);
+ lwc_string_unref(mime);
+ }
+
+ }
+
+ entry_ref ref;
+ if (get_ref_for_path(path.Path(), &ref) < B_OK)
+ return;
+
+ BMessage m(B_REFS_RECEIVED);
+ m.AddRef("refs", &ref);
+
+
+ // apps to try
+ const char *editorSigs[] = {
+ "application/x-vnd.beunited.pe",
+ "application/x-vnd.XEmacs",
+ "application/x-vnd.Haiku-StyledEdit",
+ "application/x-vnd.Be-STEE",
+ "application/x-vnd.yT-STEE",
+ NULL
+ };
+ int i;
+ for (i = 0; editorSigs[i]; i++) {
+ team_id team = -1;
+ {
+ BMessenger msgr(editorSigs[i], team);
+ if (msgr.SendMessage(&m) >= B_OK)
+ break;
+ }
+
+ err = be_roster->Launch(editorSigs[i], (BMessage *)&m, &team);
+ if (err >= B_OK)
+ break;
+ }
+}
+
+/**
+ * Broadcast an URL that we can't handle.
+ */
+
+static nserror gui_launch_url(struct nsurl *url)
+{
+ status_t status;
+ // try to open it as an URI
+ BString mimeType = "application/x-vnd.Be.URL.";
+ BString arg(nsurl_access(url));
+
+ mimeType.Append(arg, arg.FindFirst(":"));
+
+ // special case, text/x-email is used traditionally
+ // use it instead
+ if (arg.IFindFirst("mailto:") == 0)
+ mimeType = "text/x-email";
+
+ // the protocol should be alphanum
+ // we just check if it's registered
+ // if not there is likely no supporting app anyway
+ if (!BMimeType::IsValid(mimeType.String()))
+ return NSERROR_NO_FETCH_HANDLER;
+ char *args[2] = { (char *)nsurl_access(url), NULL };
+ status = be_roster->Launch(mimeType.String(), 1, args);
+ if (status < B_OK)
+ beos_warn_user("Cannot launch url", strerror(status));
+ return NSERROR_OK;
+}
+
+
+
+void die(const char * const error)
+{
+ fprintf(stderr, "%s", error);
+ BAlert *alert;
+ BString text("Cannot continue:\n");
+ text << error;
+
+ alert = new BAlert("NetSurf Error", text.String(), "Debug", "Ok", NULL,
+ B_WIDTH_AS_USUAL, B_STOP_ALERT);
+ if (alert->Go() < 1)
+ debugger("die");
+
+ exit(EXIT_FAILURE);
+}
+
+
+static struct gui_fetch_table beos_fetch_table = {
+ fetch_filetype,
+ gui_get_resource_url,
+ NULL, // ???
+ NULL, // release_resource_data
+ NULL, // fetch_mimetype
+};
+
+static struct gui_misc_table beos_misc_table = {
+ beos_schedule,
+ beos_warn_user,
+ gui_quit,
+ gui_launch_url,
+ NULL, //cert_verify
+ gui_401login_open,
+ NULL, // pdf_password (if we have Haru support)
+};
+
+
+/** Normal entry point from OS */
+int main(int argc, char** argv)
+{
+ nserror ret;
+ BPath options;
+ struct netsurf_table beos_table = {
+ &beos_misc_table,
+ beos_window_table,
+ beos_download_table,
+ beos_clipboard_table,
+ &beos_fetch_table,
+ NULL, /* use POSIX file */
+ NULL, /* default utf8 */
+ NULL, /* default search */
+ NULL, /* default web search */
+ NULL, /* default low level cache persistant storage */
+ beos_bitmap_table,
+ beos_layout_table
+ };
+
+ ret = netsurf_register(&beos_table);
+ if (ret != NSERROR_OK) {
+ die("NetSurf operation table failed registration");
+ }
+
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, &options, true) == B_OK) {
+ options.Append("x-vnd.NetSurf");
+ }
+
+ if (!replicated) {
+ // create the Application object before trying to use messages
+ // so we can open an alert in case of error.
+ new NSBrowserApplication;
+ }
+
+ /* initialise logging. Not fatal if it fails but not much we
+ * can do about it either.
+ */
+ nslog_init(nslog_stream_configure, &argc, argv);
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ die("Options failed to initialise");
+ }
+ nsoption_read(options.Path(), NULL);
+ nsoption_commandline(&argc, argv, NULL);
+
+ /* common initialisation */
+ BResources resources;
+ resources.SetToImage((const void*)main);
+ size_t size = 0;
+
+ char path[12];
+ sprintf(path,"%.2s/Messages", getenv("LC_MESSAGES"));
+ fprintf(stderr, "Loading messages from resource %s\n", path);
+
+ const uint8_t* res = (const uint8_t*)resources.LoadResource('data', path, &size);
+ if (size > 0 && res != NULL) {
+ ret = messages_add_from_inline(res, size);
+ } else {
+ BPath messages = get_messages_path();
+ ret = messages_add_from_file(messages.Path());
+ }
+
+ ret = netsurf_init(NULL);
+ if (ret != NSERROR_OK) {
+ die("NetSurf failed to initialise");
+ }
+
+ gui_init(argc, argv);
+
+ while (!nsbeos_done) {
+ nsbeos_gui_poll();
+ }
+
+ netsurf_exit();
+
+ return 0;
+}
+
+/** called when replicated from NSBaseView::Instantiate() */
+int gui_init_replicant(int argc, char** argv)
+{
+ nserror ret;
+ BPath options;
+ struct netsurf_table beos_table = {
+ &beos_misc_table,
+ beos_window_table,
+ beos_download_table,
+ beos_clipboard_table,
+ &beos_fetch_table,
+ NULL, /* use POSIX file */
+ NULL, /* default utf8 */
+ NULL, /* default search */
+ NULL, /* default web search */
+ NULL, /* default low level cache persistant storage */
+ beos_bitmap_table,
+ beos_layout_table
+ };
+
+ ret = netsurf_register(&beos_table);
+ if (ret != NSERROR_OK) {
+ die("NetSurf operation table failed registration");
+ }
+
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, &options, true) == B_OK) {
+ options.Append("x-vnd.NetSurf");
+ }
+
+ /* initialise logging. Not fatal if it fails but not much we
+ * can do about it either.
+ */
+ nslog_init(nslog_stream_configure, &argc, argv);
+
+ // FIXME: use options as readonly for replicants
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ // FIXME: must not die when in replicant!
+ die("Options failed to initialise");
+ }
+ nsoption_read(options.Path(), NULL);
+ nsoption_commandline(&argc, argv, NULL);
+
+ /* common initialisation */
+ BPath messages = get_messages_path();
+ ret = messages_add_from_file(messages.Path());
+
+ ret = netsurf_init(NULL);
+ if (ret != NSERROR_OK) {
+ // FIXME: must not die when in replicant!
+ die("NetSurf failed to initialise");
+ }
+
+ gui_init(argc, argv);
+
+ return 0;
+}
diff --git a/frontends/beos/gui.h b/frontends/beos/gui.h
new file mode 100644
index 000000000..774820baa
--- /dev/null
+++ b/frontends/beos/gui.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <Application.h>
+#include <FilePanel.h>
+#include <Window.h>
+#include <BeBuild.h>
+
+#ifndef B_BEOS_VERSION_DANO
+#define B_UI_SETTINGS_CHANGED '_UIC'
+#endif
+
+#define CALLED() fprintf(stderr, "%s()\n", __FUNCTION__);
+
+extern bool nsbeos_done;
+
+extern bool replicated;
+int gui_init_replicant(int argc, char** argv);
+
+extern "C" void gui_401login_open(nsurl *url, const char *realm,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw);
+
+extern "C" void nsbeos_gui_poll(void);
+
+extern char *options_file_location;
+
+class NSBrowserApplication : public BApplication {
+public:
+ NSBrowserApplication();
+virtual ~NSBrowserApplication();
+
+virtual void MessageReceived(BMessage *message);
+virtual void RefsReceived(BMessage *message);
+virtual void ArgvReceived(int32 argc, char **argv);
+
+virtual void AboutRequested();
+virtual bool QuitRequested();
+};
+
+extern BWindow *wndAbout;
+
+extern BWindow *wndTooltip;
+
+extern BFilePanel *wndOpenFile;
+
+void nsbeos_pipe_message(BMessage *message, BView *_this, struct gui_window *gui);
+void nsbeos_pipe_message_top(BMessage *message, BWindow *_this, struct beos_scaffolding *scaffold);
+
+void nsbeos_gui_view_source(struct hlcache_handle *content);
+image_id nsbeos_find_app_path(char *path);
+char *find_resource(char *buf, const char *filename, const char *def);
+
+void nsbeos_update_system_ui_colors(void);
+
+/**
+ * Cause an abnormal program termination.
+ *
+ * \note This never returns and is intended to terminate without any cleanup.
+ *
+ * \param error The message to display to the user.
+ */
+void die(const char * const error) __attribute__ ((noreturn));
+
+/**
+ * Display a warning for a serious problem (eg memory exhaustion).
+ *
+ * \param warning message key for warning message
+ * \param detail additional message, or 0
+ */
+nserror beos_warn_user(const char *warning, const char *detail);
diff --git a/frontends/beos/gui_options.cpp b/frontends/beos/gui_options.cpp
new file mode 100644
index 000000000..035c62941
--- /dev/null
+++ b/frontends/beos/gui_options.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+extern "C" {
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "utils/nsurl.h"
+}
+#include "beos/gui.h"
+#include "beos/scaffolding.h"
+#include "beos/gui_options.h"
+
+#include <View.h>
+#include <Window.h>
+
+BWindow *wndPreferences;
+
+void nsbeos_options_init(void) {
+ /* set the widgets to reflect the current options */
+ nsbeos_options_load();
+}
+
+void nsbeos_options_load(void) {
+#warning WRITEME
+}
+
+
+void nsbeos_options_save(void) {
+#warning WRITEME
+}
diff --git a/frontends/beos/gui_options.h b/frontends/beos/gui_options.h
new file mode 100644
index 000000000..e5c91a797
--- /dev/null
+++ b/frontends/beos/gui_options.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_BEOS_OPTIONS_H
+#define NETSURF_BEOS_OPTIONS_H
+
+#include <Window.h>
+
+extern BWindow *wndPreferences;
+
+void nsbeos_options_init(void); /** Init options and load window */
+void nsbeos_options_load(void); /** Load current options into window */
+void nsbeos_options_save(void); /** Save options from window */
+
+#endif
diff --git a/frontends/beos/login.cpp b/frontends/beos/login.cpp
new file mode 100644
index 000000000..7689c9d35
--- /dev/null
+++ b/frontends/beos/login.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <Alert.h>
+#include <String.h>
+#include <TextControl.h>
+#include <View.h>
+#include <Window.h>
+extern "C" {
+#include "utils/log.h"
+#include "content/content.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+#include "desktop/gui_clipboard.h"
+}
+#include "beos/gui.h"
+#include "beos/scaffolding.h"
+#include "beos/window.h"
+
+class LoginAlert : public BAlert {
+public:
+ LoginAlert(nserror (*callback)(bool proceed, void *pw),
+ void *callbaclpw,
+ nsurl *url,
+ const char *host,
+ const char *realm,
+ const char *text);
+ virtual ~LoginAlert();
+ void MessageReceived(BMessage *message);
+
+private:
+ nsurl* fUrl; /**< URL being fetched */
+ BString fHost; /**< Host for user display */
+ BString fRealm; /**< Authentication realm */
+ nserror (*fCallback)(bool proceed, void *pw);
+ void *fCallbackPw;
+
+ BTextControl *fUserControl;
+ BTextControl *fPassControl;
+};
+
+static void create_login_window(nsurl *host,
+ lwc_string *realm, const char *fetchurl,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw);
+
+
+#define TC_H 25
+#define TC_MARGIN 10
+
+LoginAlert::LoginAlert(nserror (*callback)(bool proceed, void *pw),
+ void *callbackpw,
+ nsurl *url,
+ const char *host,
+ const char *realm,
+ const char *text)
+ : BAlert("Login", text, "Cancel", "Ok", NULL,
+ B_WIDTH_AS_USUAL, B_WARNING_ALERT)
+{
+ fCallback = callback;
+ fCallbackPw = callbackpw;
+ fUrl = url;
+ fHost = host;
+ fRealm = realm;
+
+ SetFeel(B_MODAL_SUBSET_WINDOW_FEEL);
+ /*
+ // XXX: can't do that anymore
+ nsbeos_scaffolding *s = nsbeos_get_scaffold(bw->window);
+ if (s) {
+ NSBrowserWindow *w = nsbeos_get_bwindow_for_scaffolding(s);
+ if (w)
+ AddToSubset(w);
+ }*/
+
+ // make space for controls
+ ResizeBy(0, 2 * TC_H);
+ MoveTo(AlertPosition(Frame().Width() + 1,
+ Frame().Height() + 1));
+
+
+ BTextView *tv = TextView();
+ BRect r(TC_MARGIN, tv->Bounds().bottom - 2 * TC_H,
+ tv->Bounds().right - TC_MARGIN, tv->Bounds().bottom - TC_H);
+
+ fUserControl = new BTextControl(r, "user", "Username", "",
+ new BMessage(), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT);
+ fUserControl->SetDivider(60);
+ tv->AddChild(fUserControl);
+
+ r.OffsetBySelf(0, TC_H);
+
+ fPassControl = new BTextControl(r, "pass", "Password", "",
+ new BMessage(), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT);
+ fPassControl->TextView()->HideTyping(true);
+ fPassControl->SetDivider(60);
+ tv->AddChild(fPassControl);
+
+ SetShortcut(0, B_ESCAPE);
+}
+
+LoginAlert::~LoginAlert()
+{
+}
+
+void
+LoginAlert::MessageReceived(BMessage *message)
+{
+ switch (message->what) {
+ case 'ALTB':
+ {
+ int32 which;
+ if (message->FindInt32("which", &which) < B_OK)
+ break;
+ // not 'Ok'
+ if (which != 1)
+ break;
+ BMessage *m = new BMessage(*message);
+ m->what = 'nsLO';
+ m->AddPointer("URL", fUrl);
+ m->AddString("Host", fHost.String());
+ m->AddString("Realm", fRealm.String());
+ m->AddPointer("callback", (void *)fCallback);
+ m->AddPointer("callback_pw", (void *)fCallbackPw);
+ m->AddString("User", fUserControl->Text());
+ m->AddString("Pass", fPassControl->Text());
+ BString auth(fUserControl->Text());
+ auth << ":" << fPassControl->Text();
+ m->AddString("Auth", auth.String());
+
+ // notify the main thread
+ // the event dispatcher will handle it
+ nsbeos_pipe_message(m, NULL, NULL);
+ }
+ break;
+ default:
+ break;
+ }
+ BAlert::MessageReceived(message);
+}
+
+
+extern "C" void gui_401login_open(nsurl *url, const char *realm,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw)
+{
+ lwc_string *host;
+
+ host = nsurl_get_component(url, NSURL_HOST);
+
+ create_login_window(url, host, realm, cb, cbpw);
+
+ free(host);
+}
+
+//void create_login_window(struct browser_window *bw, const char *host,
+// const char *realm, const char *fetchurl)
+static void create_login_window(nsurl *url, lwc_string *host,
+ const char *realm, nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
+{
+ BString r("Secure Area");
+ if (realm)
+ r = realm;
+ BString text(/*messages_get(*/"Please login\n");
+ text << "Realm: " << r << "\n";
+ text << "Host: " << host << "\n";
+ //text << "\n";
+
+ LoginAlert *a = new LoginAlert(cb, cbpw, url, lwc_string_data(host),
+ r.String(), text.String());
+ // asynchronously
+ a->Go(NULL);
+
+}
diff --git a/frontends/beos/options.h b/frontends/beos/options.h
new file mode 100644
index 000000000..40d23a3bc
--- /dev/null
+++ b/frontends/beos/options.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _NETSURF_BEOS_OPTIONS_H_
+#define _NETSURF_BEOS_OPTIONS_H_
+
+/* currently nothing here */
+
+#endif
+
+NSOPTION_BOOL(render_resample, false)
+NSOPTION_STRING(url_file, NULL)
+
diff --git a/frontends/beos/plotters.cpp b/frontends/beos/plotters.cpp
new file mode 100644
index 000000000..3fd786ecd
--- /dev/null
+++ b/frontends/beos/plotters.cpp
@@ -0,0 +1,659 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Target independent plotting (BeOS/Haiku implementation).
+ */
+
+#define __STDBOOL_H__ 1
+#include <math.h>
+#include <BeBuild.h>
+#include <Bitmap.h>
+#include <GraphicsDefs.h>
+#include <Region.h>
+#include <View.h>
+#include <Shape.h>
+extern "C" {
+#include "desktop/plotters.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/nsoption.h"
+#include "utils/nsurl.h"
+}
+#include "beos/font.h"
+#include "beos/gui.h"
+#include "beos/plotters.h"
+#include "beos/bitmap.h"
+
+#warning MAKE ME static
+/*static*/ BView *current_view;
+
+/*
+ * NOTE: BeOS rects differ from NetSurf ones:
+ * the right-bottom pixel is actually part of the BRect!
+ */
+
+static bool nsbeos_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style);
+static bool nsbeos_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style);
+static bool nsbeos_plot_polygon(const int *p, unsigned int n, const plot_style_t *style);
+static bool nsbeos_plot_path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6]);
+static bool nsbeos_plot_clip(const struct rect *ns_clip);
+static bool nsbeos_plot_text(int x, int y, const char *text, size_t length,
+ const plot_font_style_t *fstyle);
+static bool nsbeos_plot_disc(int x, int y, int radius, const plot_style_t *style);
+static bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2,
+ const plot_style_t *style);
+static bool nsbeos_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bitmap_flags_t flags);
+
+
+#warning make patterns nicer
+static const pattern kDottedPattern = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
+static const pattern kDashedPattern = { 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33 };
+
+static const rgb_color kBlackColor = { 0, 0, 0, 255 };
+
+struct plotter_table plot;
+
+const struct plotter_table nsbeos_plotters = {
+ nsbeos_plot_clip,
+ nsbeos_plot_arc,
+ nsbeos_plot_disc,
+ nsbeos_plot_line,
+ nsbeos_plot_rectangle,
+ nsbeos_plot_polygon,
+ nsbeos_plot_path,
+ nsbeos_plot_bitmap,
+ nsbeos_plot_text,
+ NULL, // Group Start
+ NULL, // Group End
+ NULL, // Flush
+ true // option_knockout
+};
+
+
+// #pragma mark - implementation
+
+
+BView *nsbeos_current_gc(void)
+{
+ return current_view;
+}
+
+BView *nsbeos_current_gc_lock(void)
+{
+ BView *view = current_view;
+ if (view && view->LockLooper())
+ return view;
+ return NULL;
+}
+
+void nsbeos_current_gc_unlock(void)
+{
+ if (current_view)
+ current_view->UnlockLooper();
+}
+
+void nsbeos_current_gc_set(BView *view)
+{
+ // XXX: (un)lock previous ?
+ current_view = view;
+}
+
+bool nsbeos_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ nsbeos_set_colour(style->fill_colour);
+
+ BRect rect(x0, y0, x1 - 1, y1 - 1);
+ view->FillRect(rect);
+
+ //nsbeos_current_gc_unlock();
+
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ pattern pat;
+ BView *view;
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ pat = B_SOLID_HIGH;
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ pat = kDottedPattern;
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ pat = kDashedPattern;
+ break;
+ }
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ nsbeos_set_colour(style->stroke_colour);
+
+ float pensize = view->PenSize();
+ view->SetPenSize(style->stroke_width);
+
+ BRect rect(x0, y0, x1, y1);
+ view->StrokeRect(rect, pat);
+
+ view->SetPenSize(pensize);
+
+ //nsbeos_current_gc_unlock();
+
+ }
+
+ return true;
+}
+
+
+
+bool nsbeos_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ pattern pat;
+ BView *view;
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ pat = B_SOLID_HIGH;
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ pat = kDottedPattern;
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ pat = kDashedPattern;
+ break;
+ }
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ nsbeos_set_colour(style->stroke_colour);
+
+ float pensize = view->PenSize();
+ view->SetPenSize(style->stroke_width);
+
+ BPoint start(x0, y0);
+ BPoint end(x1, y1);
+ view->StrokeLine(start, end, pat);
+
+ view->SetPenSize(pensize);
+
+ //nsbeos_current_gc_unlock();
+
+ return true;
+}
+
+
+bool nsbeos_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+{
+ unsigned int i;
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ nsbeos_set_colour(style->fill_colour);
+
+ BPoint points[n];
+
+ for (i = 0; i < n; i++) {
+ points[i] = BPoint(p[2 * i] - 0.5, p[2 * i + 1] - 0.5);
+ }
+
+ if (style->fill_colour == NS_TRANSPARENT)
+ view->StrokePolygon(points, (int32)n);
+ else
+ view->FillPolygon(points, (int32)n);
+
+ return true;
+}
+
+
+
+
+bool nsbeos_plot_clip(const struct rect *ns_clip)
+{
+ BView *view;
+ //fprintf(stderr, "%s(%d, %d, %d, %d)\n", __FUNCTION__, clip_x0, clip_y0, clip_x1, clip_y1);
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ BRect rect(ns_clip->x0, ns_clip->y0, ns_clip->x1 - 1,
+ ns_clip->y1 - 1);
+ BRegion clip(rect);
+ view->ConstrainClippingRegion(NULL);
+ if (view->Bounds() != rect)
+ view->ConstrainClippingRegion(&clip);
+
+
+ //nsbeos_current_gc_unlock();
+
+ return true;
+}
+
+
+bool nsbeos_plot_text(int x, int y, const char *text, size_t length,
+ const plot_font_style_t *fstyle)
+{
+ return nsfont_paint(fstyle, text, length, x, y);
+}
+
+
+bool nsbeos_plot_disc(int x, int y, int radius, const plot_style_t *style)
+{
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ nsbeos_set_colour(style->fill_colour);
+
+ BPoint center(x, y);
+ if (style->fill_type != PLOT_OP_TYPE_NONE)
+ view->FillEllipse(center, radius, radius);
+ else
+ view->StrokeEllipse(center, radius, radius);
+
+ //nsbeos_current_gc_unlock();
+
+ return true;
+}
+
+bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+{
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ nsbeos_set_colour(style->fill_colour);
+
+ BPoint center(x, y);
+ float angle = angle1; // in degree
+ float span = angle2 - angle1; // in degree
+ view->StrokeArc(center, radius, radius, angle, span);
+
+ //nsbeos_current_gc_unlock();
+
+ return true;
+}
+
+static bool nsbeos_plot_bbitmap(int x, int y, int width, int height,
+ BBitmap *b, colour bg)
+{
+ /* XXX: This currently ignores the background colour supplied.
+ * Does this matter?
+ */
+
+ if (width == 0 || height == 0)
+ return true;
+
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ drawing_mode oldmode = view->DrawingMode();
+ source_alpha alpha;
+ alpha_function func;
+ view->GetBlendingMode(&alpha, &func);
+ //view->SetDrawingMode(B_OP_OVER);
+ view->SetDrawingMode(B_OP_ALPHA);
+ view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
+
+ // XXX DrawBitmap() resamples if rect doesn't match,
+ // but doesn't do any filtering
+ // XXX: use Zeta API if available ?
+
+ BRect rect(x, y, x + width - 1, y + height - 1);
+ /*
+ rgb_color old = view->LowColor();
+ if (bg != NS_TRANSPARENT) {
+ view->SetLowColor(nsbeos_rgb_colour(bg));
+ view->FillRect(rect, B_SOLID_LOW);
+ }
+ */
+ view->DrawBitmap(b, rect);
+ // maybe not needed?
+ //view->SetLowColor(old);
+ view->SetBlendingMode(alpha, func);
+ view->SetDrawingMode(oldmode);
+
+ //nsbeos_current_gc_unlock();
+
+ return true;
+}
+
+
+bool nsbeos_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bitmap_flags_t flags)
+{
+ int doneheight = 0, donewidth = 0;
+ BBitmap *primary;
+ BBitmap *pretiled;
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+
+ if (!(repeat_x || repeat_y)) {
+ /* Not repeating at all, so just plot it */
+ primary = nsbeos_bitmap_get_primary(bitmap);
+ return nsbeos_plot_bbitmap(x, y, width, height, primary, bg);
+ }
+
+ if (repeat_x && !repeat_y)
+ pretiled = nsbeos_bitmap_get_pretile_x(bitmap);
+ if (repeat_x && repeat_y)
+ pretiled = nsbeos_bitmap_get_pretile_xy(bitmap);
+ if (!repeat_x && repeat_y)
+ pretiled = nsbeos_bitmap_get_pretile_y(bitmap);
+ primary = nsbeos_bitmap_get_primary(bitmap);
+
+ /* use the primary and pretiled widths to scale the w/h provided */
+ width *= pretiled->Bounds().Width() + 1;
+ width /= primary->Bounds().Width() + 1;
+ height *= pretiled->Bounds().Height() + 1;
+ height /= primary->Bounds().Height() + 1;
+
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return false;
+ }
+
+ // XXX: do we really need to use clipping reg ?
+ // I guess it's faster to not draw clipped out stuff...
+
+ BRect cliprect;
+ BRegion clipreg;
+ view->GetClippingRegion(&clipreg);
+ cliprect = clipreg.Frame();
+
+ //XXX: FIXME
+
+ if (y > cliprect.top)
+ doneheight = ((int)cliprect.top - height) + ((y - (int)cliprect.top) % height);
+ else
+ doneheight = y;
+
+ while (doneheight < ((int)cliprect.bottom)) {
+ if (x > cliprect.left)
+ donewidth = ((int)cliprect.left - width) + ((x - (int)cliprect.left) % width);
+ else
+ donewidth = x;
+ while (donewidth < (cliprect.right)) {
+ nsbeos_plot_bbitmap(donewidth, doneheight,
+ width, height, pretiled, bg);
+ donewidth += width;
+ if (!repeat_x) break;
+ }
+ doneheight += height;
+ if (!repeat_y) break;
+ }
+
+#warning WRITEME
+ return true;
+}
+
+static BPoint transform_pt(float x, float y, const float transform[6])
+{
+#warning XXX: verify
+ //return BPoint(x, y);
+ BPoint pt;
+ pt.x = x * transform[0] + y * transform[1] + transform[4];
+ pt.y = x * transform[2] + y * transform[3] + transform[5];
+ /*
+ printf("TR: {%f, %f} { %f, %f, %f, %f, %f, %f} = { %f, %f }\n",
+ x, y,
+ transform[0], transform[1], transform[2],
+ transform[3], transform[4], transform[5],
+ pt.x, pt.y);
+ */
+ return pt;
+}
+
+bool nsbeos_plot_path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6])
+{
+ unsigned int i;
+
+ if (n == 0)
+ return true;
+
+ if (p[0] != PLOTTER_PATH_MOVE) {
+ LOG("path doesn't start with a move");
+ return false;
+ }
+
+ BShape shape;
+
+ for (i = 0; i < n; ) {
+ if (p[i] == PLOTTER_PATH_MOVE) {
+ BPoint pt(transform_pt(p[i + 1], p[i + 2], transform));
+ shape.MoveTo(pt);
+ i += 3;
+ } else if (p[i] == PLOTTER_PATH_CLOSE) {
+ shape.Close();
+ i++;
+ } else if (p[i] == PLOTTER_PATH_LINE) {
+ BPoint pt(transform_pt(p[i + 1], p[i + 2], transform));
+ shape.LineTo(pt);
+ i += 3;
+ } else if (p[i] == PLOTTER_PATH_BEZIER) {
+ BPoint pt[3] = {
+ transform_pt(p[i + 1], p[i + 2], transform),
+ transform_pt(p[i + 3], p[i + 4], transform),
+ transform_pt(p[i + 5], p[i + 6], transform)
+ };
+ shape.BezierTo(pt);
+ i += 7;
+ } else {
+ LOG("bad path command %f", p[i]);
+ return false;
+ }
+ }
+ shape.Close();
+
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL)
+ return false;
+
+ rgb_color old_high = view->HighColor();
+ float old_pen = view->PenSize();
+ view->SetPenSize(width);
+ view->MovePenTo(0, 0);
+ if (fill != NS_TRANSPARENT) {
+ view->SetHighColor(nsbeos_rgb_colour(fill));
+ view->FillShape(&shape);
+ }
+ if (c != NS_TRANSPARENT) {
+ view->SetHighColor(nsbeos_rgb_colour(c));
+ view->StrokeShape(&shape);
+ }
+ // restore
+ view->SetPenSize(old_pen);
+ view->SetHighColor(old_high);
+
+ //nsbeos_current_gc_unlock();
+
+ return true;
+}
+
+rgb_color nsbeos_rgb_colour(colour c)
+{
+ rgb_color color;
+ if (c == NS_TRANSPARENT)
+ return B_TRANSPARENT_32_BIT;
+ color.red = c & 0x0000ff;
+ color.green = (c & 0x00ff00) >> 8;
+ color.blue = (c & 0xff0000) >> 16;
+ return color;
+}
+
+void nsbeos_set_colour(colour c)
+{
+ rgb_color color = nsbeos_rgb_colour(c);
+ BView *view = nsbeos_current_gc();
+ view->SetHighColor(color);
+}
+
+/** Plot a caret. It is assumed that the plotters have been set up. */
+void nsbeos_plot_caret(int x, int y, int h)
+{
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL)
+ /* TODO: report an error here */
+ return;
+
+ BPoint start(x, y);
+ BPoint end(x, y + h - 1);
+#if defined(__HAIKU__) || defined(B_BEOS_VERSION_DANO)
+ view->SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR));
+#else
+ view->SetHighColor(kBlackColor);
+#endif
+ view->StrokeLine(start, end);
+
+ //nsbeos_current_gc_unlock();
+
+}
+
+#ifdef TEST_PLOTTERS
+//
+static void test_plotters(void)
+{
+ int x0, y0;
+ int x1, y1;
+ struct rect r;
+
+ x0 = 5;
+ y0 = 5;
+ x1 = 35;
+ y1 = 6;
+
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, false);
+ y0+=2; y1+=2;
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, false);
+ y0+=2; y1+=2;
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, true);
+ y0+=2; y1+=2;
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, true);
+ y0+=10; y1+=20;
+
+ plot.fill(x0, y0, x1, y1, 0x00ff0000);
+ plot.rectangle(x0+10, y0+10, x1-x0+1, y1-y0+1, 2, 0x00ffff00, true, false);
+ y0+=30; y1+=30;
+
+ r.x0 = x0 + 2;
+ r.y0 = y0 + 2;
+ r.x1 = x1 - 2;
+ r.y1 = y1 - 2;
+ plot.clip(&r);
+
+ plot.fill(x0, y0, x1, y1, 0x00000000);
+ plot.disc(x1, y1, 8, 0x000000ff, false);
+
+ r.x0 = 0;
+ r.y0 = 0;
+ r.x1 = 300;
+ r.y1 = 300;
+ plot.clip(&r);
+
+ y0+=30; y1+=30;
+
+}
+
+#include <Application.h>
+#include <View.h>
+#include <Window.h>
+class PTView : public BView {
+public:
+ PTView(BRect frame) : BView(frame, "view", B_FOLLOW_NONE, B_WILL_DRAW) {};
+ virtual ~PTView() {};
+ virtual void Draw(BRect update)
+ {
+ test_plotters();
+ };
+
+};
+
+extern "C" void test_plotters_main(void);
+void test_plotters_main(void)
+{
+ BApplication app("application/x-vnd.NetSurf");
+ memcpy(&plot, &nsbeos_plotters, sizeof(plot));
+ BRect frame(0,0,300,300);
+ PTView *view = new PTView(frame);
+ frame.OffsetBySelf(100,100);
+ BWindow *win = new BWindow(frame, "NetSurfPlotterTest", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE);
+ win->AddChild(view);
+ nsbeos_current_gc_set(view);
+ win->Show();
+ app.Run();
+}
+#endif /* TEST_PLOTTERS */
+
diff --git a/frontends/beos/plotters.h b/frontends/beos/plotters.h
new file mode 100644
index 000000000..523f3c7c6
--- /dev/null
+++ b/frontends/beos/plotters.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Target independent plotting (BeOS interface).
+ */
+
+#ifndef NETSURF_BEOS_PLOTTERS_H
+#define NETSURF_BEOS_PLOTTERS_H 1
+
+extern "C" {
+
+struct plotter_table;
+
+extern const struct plotter_table nsbeos_plotters;
+
+}
+
+#include <View.h>
+
+extern BView *current_view;
+
+extern BView *nsbeos_current_gc(void);
+extern BView *nsbeos_current_gc_lock(void);
+extern void nsbeos_current_gc_unlock(void);
+extern void nsbeos_current_gc_set(BView *view);
+
+rgb_color nsbeos_rgb_colour(colour c);
+void nsbeos_set_colour(colour c);
+void nsbeos_plot_caret(int x, int y, int h);
+
+#endif /* NETSURF_GTK_PLOTTERS_H */
diff --git a/frontends/beos/res.h b/frontends/beos/res.h
new file mode 100644
index 000000000..278ffb545
--- /dev/null
+++ b/frontends/beos/res.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
diff --git a/frontends/beos/res.rdef b/frontends/beos/res.rdef
new file mode 100644
index 000000000..07012356c
--- /dev/null
+++ b/frontends/beos/res.rdef
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "res.h"
+
+/* files exported as resource: via rsrc:// mapping are added by the makefile */
+
+/* application flags (multiple launch) */
+resource(1, "BEOS:APP_FLAGS") (#'APPF') $"01000000";
+
+/* application MIME signature */
+resource(1, "BEOS:APP_SIG") (#'MIMS') "application/x-vnd.NetSurf";
+
+/* list of supported MIME types */
+resource(1, "BEOS:FILE_TYPES") message {
+ "types" = "text/html",
+ "types" = "image/gif",
+ "types" = "image/jpeg",
+ "types" = "application/x-vnd.Be-bookmark",
+ "types" = "text",
+ "types" = "application/x-vnd.Be-doc_bookmark",
+ "types" = "application/x-vnd.Be.URL.file",
+ "types" = "application/x-vnd.Be.URL.ftp",
+ "types" = "application/x-vnd.Be.URL.http",
+ "types" = "application/x-vnd.Be.URL.https"
+};
+
+/* BeOS large (32x32) icon */
+resource(101, "BEOS:L:STD_ICON") #'ICON' array {
+ $"FFFFFFFFFFFFFFFFFFFFFF0E0A00D600D6000AAF0EFFFFFFFFFFFFFFFFFFFFFF"
+ $"FFFFFFFFFFFFFFFF0E0A000001DED5D5D5DE020000090EFFFFFFFFFFFFFFFFFF"
+ $"FFFFFFFFFFFFFF0B0001B58D6666666C6C6C6C93B50200090EFFFFFFFFFFFFFF"
+ $"FFFFFFFFFF0E0000016D66666666666C6C6C6C6C6C6CB40104AFFFFFFFFFFFFF"
+ $"FFFFFFFF0E0001B503464666666666666C6C6C6C6C6C6C9303000DFFFFFFFFFF"
+ $"FFFFFF0E000267AEB5464666666666666C6C6C6C66666C7292DE000DFFFFFFFF"
+ $"FFFFFF070167464666464646666666666C666C6C1F1F66664092DE000EFFFFFF"
+ $"FFFF0B008E46464646464646666666666C403F1E3F3F3F3F6692930100FFFFFF"
+ $"FFFF00074646668D46464666666666666C663F3F3F3F3F3F6672927E000EFFFF"
+ $"FF0B006D6646670246464666666666666C663F3F3F3F3F3F3F1E6C923D00FFFF"
+ $"FF00D56666668E044646666666666666403F3F3F3F3F3F3F1F6692927E000EFF"
+ $"0E008E666666678E666666666666666C6C661E3F3F3F3F3F1D92929293000BFF"
+ $"0B016C66666666666666666666666C6C6C6C403F3F3F3F3F3F6C929292DE00FF"
+ $"08036C666666666666666666666C6C6C6C6C1E1D403F1E6C666C929292DD00FF"
+ $"00D56C6C66668D06666666666C6C6C6C6C6C6C6C6C1D667292929292927E03FF"
+ $"00D56C6C6C6C8D02666C6C6C6C6C6C6C6C6C6C6C6C6C729292929292927E03FF"
+ $"00D56C6C6C6C6CDE6C6C6C6C6C6C6C6C6C6C6C6C7272729292929292927E03FF"
+ $"00DE6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C7272729292929292925F0103FF"
+ $"09026C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C72727292929292929293010100FF"
+ $"0B008D6C6C6C6C8DD56C6C6C6C6C6C6C6C72727272929292929292927E3D29FF"
+ $"0E00B46C6C6C6C6C01936C6C6C6C6C6C72727292929292927E7E92925F000BFF"
+ $"FF00DE6C6C6C6C6CB5B46C6C6C6C727272729292929292DE297E9292DD020EFF"
+ $"FF0C0002B4726C6C6C6C7272727272727292B4DD7F929293929292920100FFFF"
+ $"FFFF00007F7272B4DDDD927293DDDEB49292DEDDB3929292929292DD000EFFFF"
+ $"FFFFAF00B4727293B47FDEB4937E7E93929292929292929292925F0009FFFFFF"
+ $"FFFFFF0A00B4929292929301939292929292929292929292925F0100FFFFFFFF"
+ $"FFFFFFFF0700B4929292927E9392929292929292929292925F01000EFFFFFFFF"
+ $"FFFFFFFFFF0700DD9292929292929292929292929292927E01000EFFFFFFFFFF"
+ $"FFFFFFFFFFFF0A003D7E9292927E7E9292929292925FDE00000EFFFFFFFFFFFF"
+ $"FFFFFFFFFFFFFF0D00003D7F5F5F017E92925F7EDE000300FFFFFFFFFFFFFFFF"
+ $"FFFFFFFFFFFFFFFFFF0D00030000000001010000000C0EFFFFFFFFFFFFFFFFFF"
+ $"FFFFFFFFFFFFFFFFFFFFFFFF0E0B000A0A0A0D0EFFFFFFFFFFFFFFFFFFFFFFFF"
+};
+
+/* BeOS small (16x16) icon */
+resource(101, "BEOS:M:STD_ICON") #'MICN' array {
+ $"FFFFFFFF0E0900020205000DFFFFFFFF"
+ $"FFFFFF09038E66666C6C93DD000EFFFF"
+ $"FFFF00B5AE4666666C6C666CB4050EFF"
+ $"FF098E464646666666401D4066B400FF"
+ $"0E05668E664666666C1E3F3F1D6CDDAF"
+ $"098E668E66666666661F3F3F1E729300"
+ $"006C66666666666C6C401E1E40729204"
+ $"026C6CB46C666C6C6C6C6C66929292DE"
+ $"026C6C8D6C6C6C6C6C6C72729292923D"
+ $"006C6C6C8D6C6C6C6C72729292927E04"
+ $"09946C6CB56C6C6C72729292DD935F00"
+ $"0E009492B49293B492B47E929292DE0D"
+ $"FF0A7F92937F939392929292927E00FF"
+ $"FFFF08DD92929292929292927E00FFFF"
+ $"FFFFFF0B017E93DD92927EDE09FFFFFF"
+ $"FFFFFFFF0E0B000500000A0EFFFFFFFF"
+};
+
+/* Haiku vector icon */
+resource(101, "BEOS:ICON") #'VICN' array {
+ $"6E6369660A02010203AE259A400198BFFA65AE20E548AF9547F2037F30A0FFFF"
+ $"00E8F1FDFFF131A0FFFB02000602B83B85BC57333C5733B83B8549EAE1481199"
+ $"00359FFFFFFFFFFF05FF05010400600500020002033D9F21B889EB3A4CEE3F48"
+ $"204AB4B1440D2D10339DFF51369381810DB3339DFF68020002013E7E6E26628C"
+ $"A83C7540569A4565A3CA24492BEEF3F70001EEF3F731017D828B95160204BFE6"
+ $"B413C670B413B95DB413B411BF78B411B92DB411C5C3BFE6CADDB95CCADDC66F"
+ $"CADDCBBCBF78CBBCC5C4CBBCB92E0204BC63B4EAC0E922B7DDB608B570BBF0B4"
+ $"C0B92EB61EBEB2BEDDBEE8BA56C007C363BDCBC5D0B7E2C67FBAA5C522B52002"
+ $"04BFDEB448C60DB448B9ADB448B4ADBF9AB4ADB955B4ADC5DABFDECAEDB9ABCA"
+ $"EDC60BCAEDCB0FBF9ACB0FC5DCCB0FB9570204BFDFB4D8C5BFB4D8B9FEB4D8B5"
+ $"3DBF9AB53DB9A5B53DC58ABFDFCA5CB9FCCA5CC5BDCA5CCA81BF9ACA81C58BCA"
+ $"81B9A70606BA0BBF11CB5CC71BCAFECB92C8F7CA15CAF2CCF9C666CA36C48EC4"
+ $"A7CA76C78DC943C2BECB40BF11CB5D0A04BB16B6B2BA9C2EB9CFB86BBA5AB65D"
+ $"0A04BA10BC6AB954BC62B96CBADFBA3EBAE70A04BA21BEB5BA5AC047B98DC071"
+ $"B93ABEF30A04BAFDC28BBB88C3E9BAD5C43EBA59C2CD0A04BD84C730BCE154BC"
+ $"1CC679BCAAC5F90A04BEF3C932C015CA3BBF51CAA0BE4FC9AB0A04B812C4E6B8"
+ $"1CC5AEB693C46DB6DEC3F70A04BA6AC535BBD4C545BBCDC617BAACC6020A04BE"
+ $"1EC565BF9AC51CBFB2C5E6BE5FC6340A04C1DCC4D3C348C459C381C524C244C5"
+ $"8D0A04C6D0C2EDC721C39FC5E5C45FC595C3AA0A04C8E6C175C9A042CA54C102"
+ $"C962C20E0611AAAAAAAE02C14FB955C2EAB96FC38BB7E6C47FB928C628B8C3C6"
+ $"04BA40C793BB18C64ABC15C6B4BDE0C50CBDCAC479BF41C372BE11C17FBE79C1"
+ $"FEBCB2C207BCB3C1F5BCB2C047BC1CC1A7BAEBC14EB9540205C03CC10EC030C0"
+ $"EFC0B9C250BFCBC606BE8FC591C21CC6E2C5DBC385C74DC4AAC5AAC35EC643BC"
+ $"27C7D2BF42C4B3B90CC27CB994C3B1BA28C084B8A30605EF03B6CFBA0EB779B7"
+ $"92B672BB6AB633BD29B598BCA2B7B3BE77BD4BBD3EC58CB654C86EB88FC42DB5"
+ $"45BC71B55CBF70B47FB920B65000000204CB77C91ACB76C797CB79CAACC293CB"
+ $"88C456CB8AC0CCCB86BAB3C975BAACCAF2BABAC7F6C286C704C0CCC704C44DC7"
+ $"04250A090115023FFFDCB41DBB3451734030CDBF6EE7C3CF400A000100023F88"
+ $"1AB4F02F34DE2C3F9E484326CF4422000A060112023CDC96413114C145263E69"
+ $"DE4C32CFCB0EE00A0301031A4002C300000000000040012FBD3E023BCFC439BF"
+ $"01178100040A0301031A4002C300000000000040012FBD3E023BCFC42F390117"
+ $"8200040A0301031A4002C300000000000040012FBD3E023BCFC41A2F01178200"
+ $"040A050105023EF4D13E9DFDBE66B43EB65E491E02C6E7CA0A0501051A3EE861"
+ $"3EABC8BE735C3EAAF54929C0C6EFBE1A3901178100040A050106023F4B963E44"
+ $"75BE44753F4B9648D9CDC72B1A0A0501061A3F4B963E4475BE44753F4B9648D9"
+ $"CDC72B1A1A3901178100040A0501061A3F4B963E4475BE44753F4B9648D9CDC7"
+ $"2B1A001901178300040A050107023F4B963E4475BE44753F4B9648D9CDC72B1A"
+ $"0A0501071A3F4B963E4475BE44753F4B9648D9CDC72B1A1A3901178100040A05"
+ $"0108023F4B963E4475BE44753F4B9648D9CDC72B1A0A0501081A3F4B963E4475"
+ $"BE44753F4B9648D9CDC72B1A1A3901178100040A0501081A3F4B963E4475BE44"
+ $"753F4B9648D9CDC72B1A001901178300040A050109023F70F53E0A00BE0A003F"
+ $"70F5485F8CC6CD790A0501091A3F70F53E0A00BE0A003F70F5485F8CC6CD791A"
+ $"3901178100040A05010A023F4B963E4475BD81043E8BD247F0BEC26F710A0501"
+ $"0A1A3F4B963E4475BD81043E8BD247F0BEC26F711A3901178100040A05010A1A"
+ $"3F4B963E4475BD81043E8BD247F0BEC26F71001901178300040A05010B023F7B"
+ $"673D4154BE6C8B3F3385495313C5FE290A05010B1A3F7B673D4154BE6C8B3F33"
+ $"85495313C5FE291A3901178100040A05010C023F70093E0B8EBE0B8E3F700948"
+ $"A7CCC721CF0A05010C1A3F70093E0B8EBE0B8E3F700948A7CCC721CF1A390117"
+ $"8100040A05010D023F70093E0B8EBE0B8E3F700948A7CCC721CF0A05010D1A3F"
+ $"70093E0B8EBE0B8E3F700948A7CCC721CF1A3901178100040A05010D1A3F7009"
+ $"3E0B8EBE0B8E3F700948A7CCC721CF001901178300040A05010E023F70093E0B"
+ $"8EBE0B8E3F700948A7CCC721CF0A05010E1A3F70093E0B8EBE0B8E3F700948A7"
+ $"CCC721CF1A3901178100040A05010F023FB1173D145ABD145A3FB117474282C6"
+ $"7CF80A05010F1A3FB1173D145ABD145A3FB117474282C67CF81A390117810004"
+ $"0A05010F1A3FB1173D145ABD145A3FB117474282C67CF8001901178300040A05"
+ $"0110023F68373CD78FBD05193F9ECF48132CC5E0A80A0501101A3F68373CD78F"
+ $"BD05193F9ECF48132CC5E0A81A3901178100040A020111000A0301031A4002C3"
+ $"00000000000040012FBD3E023BCFC400190117850004"
+};
+
+/* ZETA SVG icon descriptor */
+resource(101, "BEOS:D:STD_ICON") (#'iICO') $"4944585A055300";
+
+/* ZETA SVG compressed icon */
+resource(101, "BEOS:V:STD_ICON") #'zICO' array {
+ $"7A10000078DAED57DD6EDB3618BDEF5310CA4D03C40C7F3E8A6466B7C002AC37"
+ $"2C066CCD03B8B1EC6853A44052B3644FBFF351769C7601D68B41BB5814C03AA2"
+ $"8EA8C3F3FD5059BE7FB86DC47DD50F75D7AE0A2D5521AAF6BADBD4ED6E555C7D"
+ $"FA69110A318CEB76B36EBAB65A158FD550BC7FF76639DCEFC41FF566BC591525"
+ $"15E2A6AA7737E384AFBBA6EB17753B56FD5DD7ACC73C7353B7D5BAFFE5C38FC5"
+ $"BB3762B9C38F58DEADC71B4CFED860DE6DDD341727DB7C14B8391D9B55F131C8"
+ $"6085355299CB0C8D92C10BEDF3AFCE231137277C494AEAC3384569F49E3FE169"
+ $"9A099365E6C4772633F33C195F4EF34FE3F9B513FD28E6CFA3CAB15FB7C3B6EB"
+ $"6F57C5ED7AECEB87B75A928E670A7F135AE08D21B8B385B6D2913FE567CF5FF6"
+ $"A085CD3F60A4EF7EAF0E861CAE17D9F10B92D6C5F26990ADFDADABDB8BCFD57D"
+ $"D5FC9FCCEBD79B7ADD7CE053D58EA2C68A77FB0BE4F1015EB5F538AC8A2F43D5"
+ $"FF7AB7BEAE7E6EAF860A69FAB02AC0BA7ECCA77ECADDC3339FFEA64A49174C56"
+ $"B598A00ED2C4F20C0E292277CA790D49C3D8DD896EBB1DAA31CFCBD78B5C11AB"
+ $"E2E473D83AA4F7F90B54FD0D55A9E80FD4E5F9D70B7D3971BEF4CDDB93A7E59F"
+ $"BE16D15311A97C7C53445A3AEBC26B117D6717262309EB0CD287449A8518278D"
+ $"4F445295C260529BB0923208A36524E638811229CB64BD8C41E828A34DB69486"
+ $"D83A054CB2746C0EE964B5B49E39A01B5912CFA875821F1E9864C03846A0A094"
+ $"44CCB1D92D6F9275321856468E5FE5BCE0C980A3D450869743E551FD7FD8B7D1"
+ $"29BCF9BEBEFD6AF73F25E954D45FBBC68BC6B2E09449C02A5B02CD30C069C604"
+ $"1CA42B858619E9197D5E9921DB89CA8E90C39185DFBA942E66CC30F26D45E919"
+ $"7566891C6E477BBB900CCAB18DE84EC0F6492E3248A70379EE5813C494B23489"
+ $"1B2C9A629441735029705325CBC24088313D23CF2A1281837B68DCCA2794150A"
+ $"8D9C8C09D54668FFA50CC05A9A4C0958C7913EAF4C98640405CE438E64291CFA"
+ $"0970902AF2166493C9658F7DCB43F2913E6FC8D1080D875621FF48EA2828B71E"
+ $"6DB3366E64893981C7C384F7FC79757AE9598ECAD1B591B1A58CF32E1EFCBE23"
+ $"01E7AADAB3E78DB9934AF37B89C3CC9969789730874F0DC721577EAFF7C89E55"
+ $"A4CD5F3F882605DE78BCE668A2E3A09235ED2D06C7E5E847979EF1E7D589E70D"
+ $"37206C8A6C12FACEB4115A2E20BE5BF206E9F3D75EC8F8C09F5527BA0F3666B8"
+ $"A774227C5F46EEE6E8F2FC3D4A025F088025F726C8D7907FA4FF2B3297E7F8C7"
+ $"7F793EDCE3F417BB10DA0B"
+};
+
+/* toolbar icons from Zumi <http://zumi.xoom.it/myhaiku>
+ * (generated by Icon-O-Matic from the HFIV source file,
+ * can't be automated)
+ */
+
+resource(102, "forward_button") #'VICN' array {
+ $"6E6369660304006603005900020006020000003C6000C000000000004C000048"
+ $"A0000080FF80FF00B300010A0748353448343E223E222C342C3422030A000100"
+ $"30222201178322040A0101001001178322040A02010000"
+};
+
+resource(103, "back_button") #'VICN' array {
+ $"6E6369660304006603005900020006020000003C6000C000000000004C000048"
+ $"A0000080FF80FF00B300010A0722353622362C482C483E363E3648030A000100"
+ $"30222201178322040A0101001001178322040A02010000"
+};
+
+resource(104, "stop_button") #'VICN' array {
+ $"6E6369660304006603800000020006020000003C6000C000000000004C000048"
+ $"A00000FFABABFFD900000208022A40402A02043525BEE325B7D825253525B7D8"
+ $"25BEE33545B7D845BEE345453545BEE345B7D8030A0002000130222201178900"
+ $"040A010200011001178900040A02020100100117850004"
+};
+
+resource(105, "reload_button") #'VICN' array {
+ $"6E6369660404006603004080020006020000003A0000C000000000004C000046"
+ $"7FFF00ABD5FFFF006CD9020006020000003A0000C000000000004C0000467FFF"
+ $"FFAAD4FF00006CD9010606C60F482232383D2D3D2D3826222A2B2329224327BC"
+ $"B7B25A4327060A00010030222201178322040A0101001001178322040A020100"
+ $"000A00010012C00000000000000000C000004AC0004AC00001178422040A0101"
+ $"0012C00000000000000000C000004AA0004AA00001178422040A03010002C000"
+ $"00000000000000C000004AA0004AA000"
+};
+
+resource(106, "home_button") #'VICN' array {
+ $"6E6369660804006603800000020006020000003A8000C000000000004C000047"
+ $"000000FFABABFFD900000554020016020000003AC000C000000000004BE00048"
+ $"A00000FFFFE50300590002000602000000370000C000000000004C00004A5000"
+ $"0080FF80FF00B20003806040040A064836483035222230223635280A04484848"
+ $"42224222480A0542404234352A283428400A042C342C4032403234080A030102"
+ $"1001178400040A040102000A0101001001178402040A020100000A0501011001"
+ $"178402040A060101000A070103000A0701030240AAAA0000000000003E000045"
+ $"0000468000"
+};
+
diff --git a/frontends/beos/res/SearchEngines b/frontends/beos/res/SearchEngines
new file mode 120000
index 000000000..df5252e07
--- /dev/null
+++ b/frontends/beos/res/SearchEngines
@@ -0,0 +1 @@
+../../resources/SearchEngines \ No newline at end of file
diff --git a/frontends/beos/res/adblock.css b/frontends/beos/res/adblock.css
new file mode 120000
index 000000000..e3811f62b
--- /dev/null
+++ b/frontends/beos/res/adblock.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
diff --git a/frontends/beos/res/beosdefault.css b/frontends/beos/res/beosdefault.css
new file mode 100644
index 000000000..9b457d448
--- /dev/null
+++ b/frontends/beos/res/beosdefault.css
@@ -0,0 +1,22 @@
+/*
+ * This file is part of NetSurf, http://netsurf-browser.org/
+ */
+
+/* Load base stylesheet. */
+
+/*@import "default.css";*/
+@import "rsrc:///default.css";
+
+/* Apply GTK specific rules. */
+
+input { font-size: 95%; border: medium inset #ddd; }
+input[type=button], input[type=reset], input[type=submit], button {
+ background-color: #ddd; border: medium outset #ddd; }
+input[type=checkbox], input[type=radio] { font-size: 105%; }
+input[type=file] { background-color: #ddd; border: medium inset #ddd; }
+
+select { background-color: #ddd; border: medium inset #ddd; font-size: 95%; }
+select:after { border-left:4px ridge #ddd; }
+
+textarea { font-size: 95%; border: medium inset #ddd; }
+
diff --git a/frontends/beos/res/ca-bundle.txt b/frontends/beos/res/ca-bundle.txt
new file mode 120000
index 000000000..ad2dd6b55
--- /dev/null
+++ b/frontends/beos/res/ca-bundle.txt
@@ -0,0 +1 @@
+../../!NetSurf/Resources/ca-bundle \ No newline at end of file
diff --git a/frontends/beos/res/credits.html b/frontends/beos/res/credits.html
new file mode 120000
index 000000000..ca85d3d27
--- /dev/null
+++ b/frontends/beos/res/credits.html
@@ -0,0 +1 @@
+en/credits.html \ No newline at end of file
diff --git a/frontends/beos/res/de/welcome.html b/frontends/beos/res/de/welcome.html
new file mode 120000
index 000000000..b2ddfc796
--- /dev/null
+++ b/frontends/beos/res/de/welcome.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/de/welcome.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/default.css b/frontends/beos/res/default.css
new file mode 120000
index 000000000..6d2d4da5b
--- /dev/null
+++ b/frontends/beos/res/default.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
diff --git a/frontends/beos/res/en/credits.html b/frontends/beos/res/en/credits.html
new file mode 120000
index 000000000..1ba17392b
--- /dev/null
+++ b/frontends/beos/res/en/credits.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/en/credits.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/en/licence.html b/frontends/beos/res/en/licence.html
new file mode 120000
index 000000000..147dd6db2
--- /dev/null
+++ b/frontends/beos/res/en/licence.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/en/maps.html b/frontends/beos/res/en/maps.html
new file mode 120000
index 000000000..bb1eedd5a
--- /dev/null
+++ b/frontends/beos/res/en/maps.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/en/maps.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/en/welcome.html b/frontends/beos/res/en/welcome.html
new file mode 120000
index 000000000..28362130a
--- /dev/null
+++ b/frontends/beos/res/en/welcome.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/favicon.png b/frontends/beos/res/favicon.png
new file mode 120000
index 000000000..d968c3827
--- /dev/null
+++ b/frontends/beos/res/favicon.png
@@ -0,0 +1 @@
+../../gtk/res/favicon.png \ No newline at end of file
diff --git a/frontends/beos/res/icons b/frontends/beos/res/icons
new file mode 120000
index 000000000..4a0ebabc6
--- /dev/null
+++ b/frontends/beos/res/icons
@@ -0,0 +1 @@
+../../!NetSurf/Resources/Icons \ No newline at end of file
diff --git a/frontends/beos/res/internal.css b/frontends/beos/res/internal.css
new file mode 120000
index 000000000..e777d8ae1
--- /dev/null
+++ b/frontends/beos/res/internal.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
diff --git a/frontends/beos/res/it/credits.html b/frontends/beos/res/it/credits.html
new file mode 120000
index 000000000..6e1e15ed5
--- /dev/null
+++ b/frontends/beos/res/it/credits.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/it/credits.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/it/licence.html b/frontends/beos/res/it/licence.html
new file mode 120000
index 000000000..3a7c056b6
--- /dev/null
+++ b/frontends/beos/res/it/licence.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/it/licence.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/it/welcome.html b/frontends/beos/res/it/welcome.html
new file mode 120000
index 000000000..dea1e839c
--- /dev/null
+++ b/frontends/beos/res/it/welcome.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/it/welcome.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/ja/welcome.html b/frontends/beos/res/ja/welcome.html
new file mode 120000
index 000000000..827796f02
--- /dev/null
+++ b/frontends/beos/res/ja/welcome.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/ja/welcome.html,faf \ No newline at end of file
diff --git a/frontends/beos/res/licence.html b/frontends/beos/res/licence.html
new file mode 120000
index 000000000..86f8c54bf
--- /dev/null
+++ b/frontends/beos/res/licence.html
@@ -0,0 +1 @@
+en/licence.html \ No newline at end of file
diff --git a/frontends/beos/res/license b/frontends/beos/res/license
new file mode 100644
index 000000000..6c2a58f90
--- /dev/null
+++ b/frontends/beos/res/license
@@ -0,0 +1,332 @@
+The source code, documentation, translatable messages files and UI
+definitions contained within NetSurf are licensed under the following terms:
+
+ NetSurf is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ In addition, as a special exception, permission is granted to link the
+ code of this release of NetSurf with the OpenSSL project's "OpenSSL"
+ library (or with modified versions of it that use the same licence as
+ the "OpenSSL" library), and distribute the linked executables. You must
+ obey the GNU General Public License version 2 in all respects for all of
+ the code used other than "OpenSSL". If you modify the code, you may
+ extend this exception to your version of the code, but you are not
+ obligated to do so. If you do not wish to do so, delete this exception
+ statement from your version.
+
+All visual artwork contained within NetSurf is licensed under the terms of
+the MIT License.
+
+The full text of the MIT and GPL licenses are provided in Annex A and
+Annex B of this document.
+
+
+Annex A: The MIT License
+------------------------
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+Annex B: The GNU General Public License
+---------------------------------------
+
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software
+ interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the
+Free Software Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS
+NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
+LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS
+AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF
+ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OFMERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU
+ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
+MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE
+TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISE
+OF THE POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/frontends/beos/res/maps.html b/frontends/beos/res/maps.html
new file mode 120000
index 000000000..a32f725fb
--- /dev/null
+++ b/frontends/beos/res/maps.html
@@ -0,0 +1 @@
+en/maps.html \ No newline at end of file
diff --git a/frontends/beos/res/netsurf.png b/frontends/beos/res/netsurf.png
new file mode 120000
index 000000000..0fbf42709
--- /dev/null
+++ b/frontends/beos/res/netsurf.png
@@ -0,0 +1 @@
+../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
diff --git a/frontends/beos/res/quirks.css b/frontends/beos/res/quirks.css
new file mode 120000
index 000000000..d9fb80334
--- /dev/null
+++ b/frontends/beos/res/quirks.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
diff --git a/frontends/beos/res/throbber/throbber0.png b/frontends/beos/res/throbber/throbber0.png
new file mode 100644
index 000000000..7c79be47b
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber0.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber1.png b/frontends/beos/res/throbber/throbber1.png
new file mode 100644
index 000000000..b5b83a465
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber1.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber2.png b/frontends/beos/res/throbber/throbber2.png
new file mode 100644
index 000000000..dc1019dbd
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber2.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber3.png b/frontends/beos/res/throbber/throbber3.png
new file mode 100644
index 000000000..5d458ac0b
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber3.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber4.png b/frontends/beos/res/throbber/throbber4.png
new file mode 100644
index 000000000..4940aba02
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber4.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber5.png b/frontends/beos/res/throbber/throbber5.png
new file mode 100644
index 000000000..4c70ba64b
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber5.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber6.png b/frontends/beos/res/throbber/throbber6.png
new file mode 100644
index 000000000..3242b06b4
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber6.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber7.png b/frontends/beos/res/throbber/throbber7.png
new file mode 100644
index 000000000..c4605101f
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber7.png
Binary files differ
diff --git a/frontends/beos/res/throbber/throbber8.png b/frontends/beos/res/throbber/throbber8.png
new file mode 100644
index 000000000..68f451e5b
--- /dev/null
+++ b/frontends/beos/res/throbber/throbber8.png
Binary files differ
diff --git a/frontends/beos/res/welcome.html b/frontends/beos/res/welcome.html
new file mode 120000
index 000000000..1abdc5e8a
--- /dev/null
+++ b/frontends/beos/res/welcome.html
@@ -0,0 +1 @@
+en/welcome.html \ No newline at end of file
diff --git a/frontends/beos/scaffolding.cpp b/frontends/beos/scaffolding.cpp
new file mode 100644
index 000000000..630e059f2
--- /dev/null
+++ b/frontends/beos/scaffolding.cpp
@@ -0,0 +1,2332 @@
+/*
+ * Copyright 2015 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <BeBuild.h>
+#include <Bitmap.h>
+#include <Box.h>
+#include <Button.h>
+#include <Dragger.h>
+#include <Menu.h>
+#include <MenuBar.h>
+#include <MenuItem.h>
+#include <Node.h>
+#include <Path.h>
+#include <PopUpMenu.h>
+#include <Resources.h>
+#include <Roster.h>
+#include <Screen.h>
+#include <ScrollView.h>
+#include <String.h>
+#include <StringView.h>
+#include <TextControl.h>
+#include <View.h>
+#include <Window.h>
+
+#if defined(__HAIKU__)
+#include <IconUtils.h>
+#include "WindowStack.h"
+#endif
+
+#include <fs_attr.h>
+extern "C" {
+#include "content/content.h"
+#include "desktop/browser_history.h"
+#include "desktop/browser.h"
+#include "desktop/netsurf.h"
+#include "desktop/version.h"
+#include "desktop/searchweb.h"
+#include "desktop/search.h"
+#include "desktop/plotters.h"
+#include "utils/nsoption.h"
+#include "desktop/textinput.h"
+#include "render/form.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "utils/nsurl.h"
+#include "desktop/gui_clipboard.h"
+}
+#include "beos/about.h"
+#include "beos/bitmap.h"
+#include "beos/gui.h"
+#include "beos/plotters.h"
+#include "beos/scaffolding.h"
+#include "beos/gui_options.h"
+//#include "beos/completion.h"
+#include "beos/throbber.h"
+#include "beos/window.h"
+#include "beos/schedule.h"
+//#include "beos/download.h"
+#include "beos/cookies.h"
+
+#define TOOLBAR_HEIGHT 32
+#define DRAGGER_WIDTH 8
+
+struct beos_history_window;
+
+class NSIconTextControl;
+class NSBrowserWindow;
+class NSThrobber;
+
+struct beos_scaffolding {
+ NSBrowserWindow *window; // top-level container object
+
+ // top-level view, contains toolbar & top-level browser view
+ NSBaseView *top_view;
+
+ BMenuBar *menu_bar;
+
+ BPopUpMenu *popup_menu;
+
+#ifdef ENABLE_DRAGGER
+ BDragger *dragger;
+#endif
+
+ BView *tool_bar;
+
+ BControl *back_button;
+ BControl *forward_button;
+ BControl *stop_button;
+ BControl *reload_button;
+ BControl *home_button;
+
+ NSIconTextControl *url_bar;
+ BTextControl *search_bar;
+ //BMenuField *url_bar_completion;
+
+ NSThrobber *throbber;
+
+ BStringView *status_bar;
+
+ BScrollView *scroll_view;
+
+ struct beos_history_window *history_window;
+
+ int throb_frame;
+ struct gui_window *top_level;
+ int being_destroyed;
+
+ bool fullscreen;
+};
+
+struct beos_history_window {
+ struct beos_scaffolding *g;
+ BWindow *window;
+
+};
+
+struct menu_events {
+ const char *widget;
+};
+
+// passed to the replicant main thread
+struct replicant_thread_info {
+ char app[B_PATH_NAME_LENGTH];
+ BString url;
+ char *args[3];
+};
+
+
+static int open_windows = 0; /**< current number of open browsers */
+static NSBaseView *replicant_view = NULL; /**< if not NULL, the replicant View we are running NetSurf for */
+static sem_id replicant_done_sem = -1;
+static thread_id replicant_thread = -1;
+
+static void nsbeos_window_update_back_forward(struct beos_scaffolding *);
+static void nsbeos_throb(void *);
+static int32 nsbeos_replicant_main_thread(void *_arg);
+
+// in beos_gui.cpp
+extern int main(int argc, char** argv);
+
+// in fetch_rsrc.cpp
+extern BResources *gAppResources;
+
+// #pragma mark - class NSIconTextControl
+
+#define ICON_WIDTH 16
+
+class NSIconTextControl : public BTextControl {
+public:
+ NSIconTextControl(BRect frame, const char* name,
+ const char* label, const char* initialText,
+ BMessage* message,
+ uint32 resizeMode
+ = B_FOLLOW_LEFT | B_FOLLOW_TOP,
+ uint32 flags
+ = B_WILL_DRAW | B_NAVIGABLE | B_DRAW_ON_CHILDREN);
+virtual ~NSIconTextControl();
+
+virtual void FrameResized(float newWidth, float newHeight);
+virtual void Draw(BRect updateRect);
+virtual void DrawAfterChildren(BRect updateRect);
+virtual void AttachedToWindow();
+
+void SetBitmap(const BBitmap *bitmap);
+void FixupTextRect();
+
+private:
+ BPoint fIconOffset;
+ BRect fIconFrame;
+ const BBitmap *fIconBitmap;
+};
+
+NSIconTextControl::NSIconTextControl(BRect frame, const char* name,
+ const char* label, const char* initialText,
+ BMessage* message,
+ uint32 resizeMode,
+ uint32 flags)
+ : BTextControl(frame, name, label, initialText, message, resizeMode, flags),
+ fIconOffset(0,0),
+ fIconBitmap(NULL)
+{
+ BRect r(Bounds());
+ fIconFrame = r;
+ fIconFrame.right = fIconFrame.left + ICON_WIDTH - 1;
+ fIconFrame.bottom = fIconFrame.top + ICON_WIDTH - 1;
+ fIconFrame.OffsetBy((int32)((r.IntegerHeight() - ICON_WIDTH + 3) / 2),
+ (int32)((r.IntegerHeight() - ICON_WIDTH + 1) / 2));
+ FixupTextRect();
+}
+
+
+NSIconTextControl::~NSIconTextControl()
+{
+ delete fIconBitmap;
+}
+
+
+void
+NSIconTextControl::FrameResized(float newWidth, float newHeight)
+{
+ BTextControl::FrameResized(newWidth, newHeight);
+ FixupTextRect();
+}
+
+
+void
+NSIconTextControl::Draw(BRect updateRect)
+{
+ FixupTextRect();
+ BTextControl::Draw(updateRect);
+}
+
+
+void
+NSIconTextControl::DrawAfterChildren(BRect updateRect)
+{
+ BTextControl::DrawAfterChildren(updateRect);
+
+ PushState();
+
+ SetDrawingMode(B_OP_ALPHA);
+ DrawBitmap(fIconBitmap, fIconFrame);
+
+ //XXX: is this needed?
+ PopState();
+}
+
+
+void
+NSIconTextControl::AttachedToWindow()
+{
+ BTextControl::AttachedToWindow();
+ FixupTextRect();
+}
+
+
+void
+NSIconTextControl::SetBitmap(const BBitmap *bitmap)
+{
+ delete fIconBitmap;
+ fIconBitmap = NULL;
+
+ // keep a copy
+ if (bitmap)
+ fIconBitmap = new BBitmap(bitmap);
+ // invalidate just the icon area
+ Invalidate(fIconFrame);
+}
+
+
+void
+NSIconTextControl::FixupTextRect()
+{
+ // FIXME: this flickers on resize, quite ugly
+ BRect r(TextView()->TextRect());
+
+ // don't fix the fix
+ if (r.left > ICON_WIDTH)
+ return;
+
+ r.left += r.bottom - r.top;
+ TextView()->SetTextRect(r);
+}
+
+
+#undef ICON_WIDTH
+
+// #pragma mark - class NSResizeKnob
+
+class NSResizeKnob : public BView {
+public:
+ NSResizeKnob(BRect frame, BView *target);
+virtual ~NSResizeKnob();
+
+virtual void MouseDown(BPoint where);
+virtual void MouseUp(BPoint where);
+virtual void MouseMoved(BPoint where, uint32 code,
+ const BMessage* dragMessage);
+
+virtual void Draw(BRect updateRect);
+
+void SetBitmap(const BBitmap *bitmap);
+
+private:
+ const BBitmap *fBitmap;
+ BView *fTarget;
+ BPoint fOffset;
+};
+
+NSResizeKnob::NSResizeKnob(BRect frame, BView *target)
+ : BView(frame, "NSResizeKnob", B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT, B_WILL_DRAW),
+ fBitmap(NULL),
+ fTarget(target),
+ fOffset(-1, -1)
+{
+ SetViewColor(0, 255, 0);
+}
+
+
+NSResizeKnob::~NSResizeKnob()
+{
+}
+
+
+void
+NSResizeKnob::MouseDown(BPoint where)
+{
+ SetMouseEventMask(B_POINTER_EVENTS,
+ B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS);
+ fOffset = where;
+}
+
+
+void
+NSResizeKnob::MouseUp(BPoint where)
+{
+ fOffset.Set(-1, -1);
+}
+
+
+void
+NSResizeKnob::MouseMoved(BPoint where, uint32 code,
+ const BMessage* dragMessage)
+{
+ if (fOffset.x >= 0) {
+ fTarget->ResizeBy(where.x - fOffset.x, where.y - fOffset.y);
+ }
+}
+
+
+void
+NSResizeKnob::Draw(BRect updateRect)
+{
+ if (!fBitmap)
+ return;
+ DrawBitmap(fBitmap);
+}
+
+
+void
+NSResizeKnob::SetBitmap(const BBitmap *bitmap)
+{
+ fBitmap = bitmap;
+ Invalidate();
+}
+
+
+// #pragma mark - class NSThrobber
+
+class NSThrobber : public BView {
+public:
+ NSThrobber(BRect frame);
+virtual ~NSThrobber();
+
+virtual void MessageReceived(BMessage *message);
+virtual void Draw(BRect updateRect);
+void SetBitmap(const BBitmap *bitmap);
+
+private:
+ const BBitmap *fBitmap;
+};
+
+NSThrobber::NSThrobber(BRect frame)
+ : BView(frame, "NSThrobber", B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW),
+ fBitmap(NULL)
+{
+}
+
+
+NSThrobber::~NSThrobber()
+{
+}
+
+
+void
+NSThrobber::MessageReceived(BMessage *message)
+{
+ BView::MessageReceived(message);
+}
+
+
+void
+NSThrobber::Draw(BRect updateRect)
+{
+ if (!fBitmap)
+ return;
+ DrawBitmap(fBitmap);
+}
+
+
+void
+NSThrobber::SetBitmap(const BBitmap *bitmap)
+{
+ fBitmap = bitmap;
+ Invalidate();
+}
+
+
+// #pragma mark - class NSBaseView
+
+
+NSBaseView::NSBaseView(BRect frame)
+ : BView(frame, "NetSurf", B_FOLLOW_ALL_SIDES,
+ 0 /*B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS*/ /*| B_SUBPIXEL_PRECISE*/),
+ fScaffolding(NULL)
+{
+}
+
+NSBaseView::NSBaseView(BMessage *archive)
+ : BView(archive),
+ fScaffolding(NULL)
+{
+}
+
+
+NSBaseView::~NSBaseView()
+{
+ //beos_warn_user("~NSBaseView()", NULL);
+ if (replicated) {
+ BMessage *message = new BMessage(B_QUIT_REQUESTED);
+ nsbeos_pipe_message_top(message, NULL, fScaffolding);
+ while (acquire_sem(replicant_done_sem) == EINTR);
+ //debugger("plop");
+ status_t status = -1;
+ wait_for_thread(replicant_thread, &status);
+ }
+}
+
+
+void
+NSBaseView::MessageReceived(BMessage *message)
+{
+ switch (message->what) {
+ case B_SIMPLE_DATA:
+ case B_ABOUT_REQUESTED:
+ case B_ARGV_RECEIVED:
+ case B_REFS_RECEIVED:
+ case B_COPY:
+ case B_CUT:
+ case B_PASTE:
+ case B_SELECT_ALL:
+ //case B_MOUSE_WHEEL_CHANGED:
+ case B_UI_SETTINGS_CHANGED:
+ // NetPositive messages
+ case B_NETPOSITIVE_OPEN_URL:
+ case B_NETPOSITIVE_BACK:
+ case B_NETPOSITIVE_FORWARD:
+ case B_NETPOSITIVE_HOME:
+ case B_NETPOSITIVE_RELOAD:
+ case B_NETPOSITIVE_STOP:
+ case B_NETPOSITIVE_DOWN:
+ case B_NETPOSITIVE_UP:
+ // messages for top-level
+ case 'back':
+ case 'forw':
+ case 'stop':
+ case 'relo':
+ case 'home':
+ case 'urlc':
+ case 'urle':
+ case 'sear':
+ case 'menu':
+ case NO_ACTION:
+ case HELP_OPEN_CONTENTS:
+ case HELP_OPEN_GUIDE:
+ case HELP_OPEN_INFORMATION:
+ case HELP_OPEN_ABOUT:
+ case HELP_OPEN_LICENCE:
+ case HELP_LAUNCH_INTERACTIVE:
+ case HISTORY_SHOW_LOCAL:
+ case HISTORY_SHOW_GLOBAL:
+ case HOTLIST_ADD_URL:
+ case HOTLIST_SHOW:
+ case COOKIES_SHOW:
+ case COOKIES_DELETE:
+ case BROWSER_PAGE:
+ case BROWSER_PAGE_INFO:
+ case BROWSER_PRINT:
+ case BROWSER_NEW_WINDOW:
+ case BROWSER_VIEW_SOURCE:
+ case BROWSER_OBJECT:
+ case BROWSER_OBJECT_INFO:
+ case BROWSER_OBJECT_RELOAD:
+ case BROWSER_OBJECT_SAVE:
+ case BROWSER_OBJECT_EXPORT_SPRITE:
+ case BROWSER_OBJECT_SAVE_URL_URI:
+ case BROWSER_OBJECT_SAVE_URL_URL:
+ case BROWSER_OBJECT_SAVE_URL_TEXT:
+ case BROWSER_SAVE:
+ case BROWSER_SAVE_COMPLETE:
+ case BROWSER_EXPORT_DRAW:
+ case BROWSER_EXPORT_TEXT:
+ case BROWSER_SAVE_URL_URI:
+ case BROWSER_SAVE_URL_URL:
+ case BROWSER_SAVE_URL_TEXT:
+ case HOTLIST_EXPORT:
+ case HISTORY_EXPORT:
+ case BROWSER_NAVIGATE_HOME:
+ case BROWSER_NAVIGATE_BACK:
+ case BROWSER_NAVIGATE_FORWARD:
+ case BROWSER_NAVIGATE_UP:
+ case BROWSER_NAVIGATE_RELOAD:
+ case BROWSER_NAVIGATE_RELOAD_ALL:
+ case BROWSER_NAVIGATE_STOP:
+ case BROWSER_NAVIGATE_URL:
+ case BROWSER_SCALE_VIEW:
+ case BROWSER_FIND_TEXT:
+ case BROWSER_IMAGES_FOREGROUND:
+ case BROWSER_IMAGES_BACKGROUND:
+ case BROWSER_BUFFER_ANIMS:
+ case BROWSER_BUFFER_ALL:
+ case BROWSER_SAVE_VIEW:
+ case BROWSER_WINDOW_DEFAULT:
+ case BROWSER_WINDOW_STAGGER:
+ case BROWSER_WINDOW_COPY:
+ case BROWSER_WINDOW_RESET:
+ case TREE_NEW_FOLDER:
+ case TREE_NEW_LINK:
+ case TREE_EXPAND_ALL:
+ case TREE_EXPAND_FOLDERS:
+ case TREE_EXPAND_LINKS:
+ case TREE_COLLAPSE_ALL:
+ case TREE_COLLAPSE_FOLDERS:
+ case TREE_COLLAPSE_LINKS:
+ case TREE_SELECTION:
+ case TREE_SELECTION_EDIT:
+ case TREE_SELECTION_LAUNCH:
+ case TREE_SELECTION_DELETE:
+ case TREE_SELECT_ALL:
+ case TREE_CLEAR_SELECTION:
+ case TOOLBAR_BUTTONS:
+ case TOOLBAR_ADDRESS_BAR:
+ case TOOLBAR_THROBBER:
+ case TOOLBAR_EDIT:
+ case CHOICES_SHOW:
+ case APPLICATION_QUIT:
+ if (Window())
+ Window()->DetachCurrentMessage();
+ nsbeos_pipe_message_top(message, NULL, fScaffolding);
+ break;
+ default:
+ //message->PrintToStream();
+ BView::MessageReceived(message);
+ }
+}
+
+
+status_t
+NSBaseView::Archive(BMessage *archive, bool deep) const
+{
+ // force archiving only the base view
+ deep = false;
+ status_t err;
+ err = BView::Archive(archive, deep);
+ if (err < B_OK)
+ return err;
+ // add our own fields
+ // we try to reuse the same fields as NetPositive
+ archive->AddString("add_on", "application/x-vnd.NetSurf");
+ //archive->AddInt32("version", 2);
+ archive->AddString("url", fScaffolding->url_bar->Text());
+ archive->AddBool("openAsText", false);
+ archive->AddInt32("encoding", 258);
+ return err;
+}
+
+
+BArchivable *
+NSBaseView::Instantiate(BMessage *archive)
+{
+ if (!validate_instantiation(archive, "NSBaseView"))
+ return NULL;
+ const char *url;
+ if (archive->FindString("url", &url) < B_OK
+ || url == NULL || strlen(url) == 0) {
+ url = "about:";
+ }
+
+ struct replicant_thread_info *info = new replicant_thread_info;
+ info->url = BString(url);
+ if (nsbeos_find_app_path(info->app) < B_OK)
+ return NULL;
+ info->args[0] = info->app;
+ info->args[1] = (char *)info->url.String();
+ info->args[2] = NULL;
+ NSBaseView *view = new NSBaseView(archive);
+ replicant_view = view;
+ replicated = true;
+
+ //TODO:FIXME: fix replicants
+ // do as much as possible in this thread to avoid deadlocks
+
+ gui_init_replicant(2, info->args);
+
+ replicant_done_sem = create_sem(0, "NS Replicant created");
+ replicant_thread = spawn_thread(nsbeos_replicant_main_thread,
+ "NetSurf Main Thread", B_NORMAL_PRIORITY, info);
+ if (replicant_thread < B_OK) {
+ delete_sem(replicant_done_sem);
+ delete info;
+ delete view;
+ return NULL;
+ }
+ resume_thread(replicant_thread);
+ //XXX: deadlocks BeHappy
+ //while (acquire_sem(replicant_done_sem) == EINTR);
+
+ return view;
+}
+
+
+void
+NSBaseView::SetScaffolding(struct beos_scaffolding *scaf)
+{
+ fScaffolding = scaf;
+}
+
+
+// AttachedToWindow() is not enough to get the dragger and status bar
+// stick to the panel color
+void
+NSBaseView::AllAttached()
+{
+ BView::AllAttached();
+
+ struct beos_scaffolding *g = fScaffolding;
+ if (!g)
+ return;
+ // set targets to the topmost ns view
+ g->back_button->SetTarget(this);
+ g->forward_button->SetTarget(this);
+ g->stop_button->SetTarget(this);
+ g->reload_button->SetTarget(this);
+ g->home_button->SetTarget(this);
+
+ rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR);
+ SetViewColor(c);
+
+ g->tool_bar->SetViewColor(c);
+ g->back_button->SetViewColor(c);
+ g->back_button->SetLowColor(c);
+ g->forward_button->SetViewColor(c);
+ g->forward_button->SetLowColor(c);
+ g->stop_button->SetViewColor(c);
+ g->stop_button->SetLowColor(c);
+ g->reload_button->SetViewColor(c);
+ g->reload_button->SetLowColor(c);
+ g->home_button->SetViewColor(c);
+ g->home_button->SetLowColor(c);
+ g->url_bar->SetViewColor(c);
+ g->search_bar->SetViewColor(c);
+ g->throbber->SetViewColor(c);
+ g->scroll_view->SetViewColor(c);
+
+#ifdef ENABLE_DRAGGER
+ g->dragger->SetViewColor(c);
+#endif
+
+ g->status_bar->SetViewColor(c);
+ g->status_bar->SetLowColor(c);
+#if defined(__HAIKU__) || defined(B_DANO_VERSION)
+ g->status_bar->SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
+#endif
+}
+
+
+// #pragma mark - class NSBrowserWindow
+
+
+NSBrowserWindow::NSBrowserWindow(BRect frame, struct beos_scaffolding *scaf)
+ : BWindow(frame, "NetSurf", B_DOCUMENT_WINDOW, 0),
+ fScaffolding(scaf)
+{
+}
+
+
+NSBrowserWindow::~NSBrowserWindow()
+{
+ if(activeWindow == this)
+ activeWindow = NULL;
+}
+
+
+void
+NSBrowserWindow::DispatchMessage(BMessage *message, BHandler *handler)
+{
+ BMessage *msg;
+ switch (message->what) {
+ case B_UI_SETTINGS_CHANGED:
+ msg = new BMessage(*message);
+ nsbeos_pipe_message_top(msg, this, fScaffolding);
+ break;
+ }
+ BWindow::DispatchMessage(message, handler);
+}
+
+
+void
+NSBrowserWindow::MessageReceived(BMessage *message)
+{
+ switch (message->what) {
+ case B_ARGV_RECEIVED:
+ case B_REFS_RECEIVED:
+ case B_UI_SETTINGS_CHANGED:
+ DetachCurrentMessage();
+ nsbeos_pipe_message_top(message, this, fScaffolding);
+ break;
+ default:
+ BWindow::MessageReceived(message);
+ }
+}
+
+bool
+NSBrowserWindow::QuitRequested(void)
+{
+ BWindow::QuitRequested();
+ BMessage *message = DetachCurrentMessage();
+ // BApplication::Quit() calls us directly...
+ if (message == NULL)
+ message = new BMessage(B_QUIT_REQUESTED);
+ nsbeos_pipe_message_top(message, this, fScaffolding);
+ return false; // we will Quit() ourselves from the main thread
+}
+
+
+void
+NSBrowserWindow::WindowActivated(bool active)
+{
+ if(active)
+ activeWindow = this;
+ else if(activeWindow == this)
+ activeWindow = NULL;
+}
+
+
+// #pragma mark - implementation
+
+int32 nsbeos_replicant_main_thread(void *_arg)
+{
+ struct replicant_thread_info *info = (struct replicant_thread_info *)_arg;
+ int32 ret = 0;
+
+ while (!nsbeos_done) {
+ nsbeos_gui_poll();
+ }
+
+ netsurf_exit();
+ delete info;
+ delete_sem(replicant_done_sem);
+ return ret;
+}
+
+
+/* event handlers and support functions for them */
+
+static void nsbeos_window_destroy_event(NSBrowserWindow *window, nsbeos_scaffolding *g, BMessage *event)
+{
+ LOG("Being Destroyed = %d", g->being_destroyed);
+
+ if (--open_windows == 0)
+ nsbeos_done = true;
+
+ if (window) {
+ window->Lock();
+ window->Quit();
+ }
+
+ if (!g->being_destroyed) {
+ g->being_destroyed = 1;
+ nsbeos_window_destroy_browser(g->top_level);
+ }
+}
+
+
+static void nsbeos_scaffolding_update_colors(nsbeos_scaffolding *g)
+{
+ if (!g->top_view->LockLooper())
+ return;
+ rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR);
+ g->top_view->SetViewColor(c);
+
+ g->tool_bar->SetViewColor(c);
+ g->back_button->SetViewColor(c);
+ g->forward_button->SetViewColor(c);
+ g->stop_button->SetViewColor(c);
+ g->reload_button->SetViewColor(c);
+ g->home_button->SetViewColor(c);
+ g->url_bar->SetViewColor(c);
+ g->search_bar->SetViewColor(c);
+ g->throbber->SetViewColor(c);
+ g->scroll_view->SetViewColor(c);
+
+#ifdef ENABLE_DRAGGER
+ g->dragger->SetViewColor(c);
+#endif
+
+ g->status_bar->SetViewColor(c);
+ g->status_bar->SetLowColor(c);
+#if defined(__HAIKU__) || defined(B_DANO_VERSION)
+ g->status_bar->SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
+#endif
+ g->top_view->UnlockLooper();
+}
+
+
+/*static*/ BWindow*
+NSBrowserWindow::activeWindow = NULL;
+
+
+void nsbeos_scaffolding_dispatch_event(nsbeos_scaffolding *scaffold, BMessage *message)
+{
+ struct browser_window *bw;
+ bw = nsbeos_get_browser_for_gui(scaffold->top_level);
+ bool reloadAll = false;
+
+ LOG("nsbeos_scaffolding_dispatch_event() what = 0x%08lx", message->what);
+ switch (message->what) {
+ case B_QUIT_REQUESTED:
+ nsbeos_scaffolding_destroy(scaffold);
+ break;
+ case B_ABOUT_REQUESTED:
+ {
+ nsbeos_about(scaffold->top_level);
+ break;
+ }
+ case B_NETPOSITIVE_DOWN:
+ //XXX WRITEME
+ break;
+ case B_SIMPLE_DATA:
+ {
+ if (!message->HasRef("refs")) {
+ // XXX handle DnD
+ break;
+ }
+ // FALL THROUGH
+ // handle refs
+ }
+ case B_REFS_RECEIVED:
+ {
+ int32 i;
+ entry_ref ref;
+
+ for (i = 0; message->FindRef("refs", i, &ref) >= B_OK; i++) {
+ BString url("file://");
+ BPath path(&ref);
+ if (path.InitCheck() < B_OK)
+ break;
+
+ BNode node(path.Path());
+ if (node.InitCheck() < B_OK)
+ break;
+ if (node.IsSymLink()) {
+ // dereference the symlink
+ BEntry entry(path.Path(), true);
+ if (entry.InitCheck() < B_OK)
+ break;
+ if (entry.GetPath(&path) < B_OK)
+ break;
+ if (node.SetTo(path.Path()) < B_OK)
+ break;
+ }
+
+ attr_info ai;
+ if (node.GetAttrInfo("META:url", &ai) >= B_OK) {
+ char data[(size_t)ai.size + 1];
+ memset(data, 0, (size_t)ai.size + 1);
+ if (node.ReadAttr("META:url", B_STRING_TYPE, 0LL, data, (size_t)ai.size) < 4)
+ break;
+ url = data;
+ } else
+ url << path.Path();
+
+ nsurl *nsurl;
+ nserror error;
+
+ error = nsurl_create(url.String(), &nsurl);
+ if (error == NSERROR_OK) {
+ if (/*message->WasDropped() &&*/ i == 0) {
+ browser_window_navigate(bw, nsurl, NULL,
+ (browser_window_nav_flags)
+ (BW_NAVIGATE_HISTORY),
+ NULL, NULL, NULL);
+ } else {
+ error = browser_window_create(BW_CREATE_CLONE,
+ nsurl,
+ NULL,
+ bw,
+ NULL);
+ }
+ nsurl_unref(nsurl);
+ }
+ if (error != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(error), 0);
+ }
+ }
+ break;
+ }
+ case B_ARGV_RECEIVED:
+ {
+ int32 i;
+ BString urltxt;
+ nsurl *url;
+ nserror error;
+
+ for (i = 1; message->FindString("argv", i, &urltxt) >= B_OK; i++) {
+ error = nsurl_create(urltxt.String(), &url);
+ if (error == NSERROR_OK) {
+ error = browser_window_create(BW_CREATE_CLONE,
+ url,
+ NULL,
+ bw,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (error != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(error), 0);
+ }
+ }
+ break;
+ }
+ case B_UI_SETTINGS_CHANGED:
+ nsbeos_update_system_ui_colors();
+ nsbeos_scaffolding_update_colors(scaffold);
+ break;
+ case B_NETPOSITIVE_OPEN_URL:
+ {
+ BString url;
+ if (message->FindString("be:url", &url) < B_OK)
+ break;
+
+ nsurl *nsurl;
+ nserror error;
+
+ error = nsurl_create(url.String(), &nsurl);
+ if (error != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(error), 0);
+ } else {
+ browser_window_navigate(bw,
+ nsurl,
+ NULL,
+ (browser_window_nav_flags)(BW_NAVIGATE_HISTORY | BW_NAVIGATE_UNVERIFIABLE),
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(nsurl);
+ }
+ break;
+ }
+ case B_COPY:
+ browser_window_key_press(bw, NS_KEY_COPY_SELECTION);
+ break;
+ case B_CUT:
+ browser_window_key_press(bw, NS_KEY_CUT_SELECTION);
+ break;
+ case B_PASTE:
+ browser_window_key_press(bw, NS_KEY_PASTE);
+ break;
+ case B_SELECT_ALL:
+ LOG("Selecting all text");
+ browser_window_key_press(bw, NS_KEY_SELECT_ALL);
+ break;
+ case B_NETPOSITIVE_BACK:
+ case BROWSER_NAVIGATE_BACK:
+ case 'back':
+ if (!browser_window_history_back_available(bw))
+ break;
+ browser_window_history_back(bw, false);
+ nsbeos_window_update_back_forward(scaffold);
+ break;
+ case B_NETPOSITIVE_FORWARD:
+ case BROWSER_NAVIGATE_FORWARD:
+ case 'forw':
+ if (!browser_window_history_forward_available(bw))
+ break;
+ browser_window_history_forward(bw, false);
+ nsbeos_window_update_back_forward(scaffold);
+ break;
+ case B_NETPOSITIVE_STOP:
+ case BROWSER_NAVIGATE_STOP:
+ case 'stop':
+ browser_window_stop(bw);
+ break;
+ case B_NETPOSITIVE_RELOAD:
+ case BROWSER_NAVIGATE_RELOAD_ALL:
+ case 'relo':
+ reloadAll = true;
+ // FALLTHRU
+ case BROWSER_NAVIGATE_RELOAD:
+ browser_window_reload(bw, reloadAll);
+ break;
+ case B_NETPOSITIVE_HOME:
+ case BROWSER_NAVIGATE_HOME:
+ case 'home':
+ {
+ nsurl *url;
+ nserror error;
+
+ static const char *addr = NETSURF_HOMEPAGE;
+
+ if (nsoption_charp(homepage_url) != NULL) {
+ addr = nsoption_charp(homepage_url);
+ }
+
+ error = nsurl_create(addr, &url);
+ if (error != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(error), 0);
+ } else {
+ browser_window_navigate(bw,
+ url,
+ NULL,
+ (browser_window_nav_flags)(BW_NAVIGATE_HISTORY),
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ break;
+ }
+ case 'urle':
+ {
+ nsurl *url;
+ nserror error;
+ BString text;
+
+ if (!scaffold->url_bar->LockLooper())
+ break;
+
+ text = scaffold->url_bar->Text();
+ scaffold->scroll_view->Target()->MakeFocus();
+ scaffold->url_bar->UnlockLooper();
+
+ error = nsurl_create(text.String(), &url);
+ if (error != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(error), 0);
+ } else {
+ browser_window_navigate(bw,
+ url,
+ NULL,
+ (browser_window_nav_flags)(BW_NAVIGATE_HISTORY),
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ break;
+ }
+ case 'urlc':
+ {
+ BString text;
+ if (!scaffold->url_bar->LockLooper())
+ break;
+ text = scaffold->url_bar->Text();
+ scaffold->url_bar->UnlockLooper();
+ //nsbeos_completion_update(text.String());
+ break;
+ }
+ case 'sear':
+ {
+ nserror ret;
+ nsurl* url;
+ BString text;
+ if (!scaffold->search_bar->LockLooper())
+ break;
+ text = scaffold->search_bar->Text();
+ scaffold->search_bar->UnlockLooper();
+
+ char t[PATH_MAX];
+ find_resource(t,"SearchEngines","./beos/res/SearchEngines");
+
+ search_web_init(&t[0]);
+
+ ret = search_web_omni(text.String(),SEARCH_WEB_OMNI_SEARCHONLY
+ ,&url);
+ if (ret == NSERROR_OK) {
+ ret = browser_window_create(
+ (browser_window_create_flags)(BW_CREATE_HISTORY | BW_CREATE_TAB),
+ url,
+ NULL,
+ bw,
+ NULL);
+ nsurl_unref(url);
+ }
+
+ if (ret != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(ret), 0);
+ }
+
+ search_web_finalise();
+
+ break;
+ }
+/*
+ case 'menu':
+ {
+ menu_action action;
+ if (message->FindInt32("action", (int32 *)&action) < B_OK)
+ break;
+ switch (action) {
+ case NO_ACTION:
+ case HELP_OPEN_CONTENTS:
+ case HELP_OPEN_GUIDE:
+ case HELP_OPEN_INFORMATION:
+ case HELP_OPEN_ABOUT:
+ case HELP_LAUNCH_INTERACTIVE:
+
+ break;
+ }
+#warning XXX
+ break;
+ }
+*/
+ case NO_ACTION:
+ break;
+ case HELP_OPEN_CONTENTS:
+ break;
+ case HELP_OPEN_GUIDE:
+ break;
+ case HELP_OPEN_INFORMATION:
+ break;
+ case HELP_OPEN_ABOUT:
+ {
+ const char *goto_url = "about:credits";
+ nserror nserr;
+ nsurl *url;
+ nserr = nsurl_create(goto_url, &url);
+ if (nserr == NSERROR_OK) {
+ nserr = browser_window_navigate(bw,
+ url, NULL,
+ (browser_window_nav_flags)(BW_NAVIGATE_HISTORY),
+ NULL, NULL, NULL);
+ nsurl_unref(url);
+ }
+ if (nserr != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(nserr), 0);
+ }
+ }
+ break;
+ case HELP_OPEN_LICENCE:
+ {
+ const char *goto_url = "about:licence";
+ nserror nserr;
+ nsurl *url;
+ nserr = nsurl_create(goto_url, &url);
+ if (nserr == NSERROR_OK) {
+ nserr = browser_window_navigate(bw,
+ url, NULL,
+ (browser_window_nav_flags)(BW_NAVIGATE_HISTORY),
+ NULL, NULL, NULL);
+ nsurl_unref(url);
+ }
+ if (nserr != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(nserr), 0);
+ }
+ }
+ break;
+ case HELP_LAUNCH_INTERACTIVE:
+ break;
+ case HISTORY_SHOW_LOCAL:
+ break;
+ case HISTORY_SHOW_GLOBAL:
+ break;
+ case HOTLIST_ADD_URL:
+ break;
+ case HOTLIST_SHOW:
+ break;
+ case COOKIES_SHOW:
+ {
+ nsbeos_cookies_init();
+ break;
+ }
+ case COOKIES_DELETE:
+ {
+ nsbeos_cookies_init();
+ break;
+ }
+ case BROWSER_PAGE:
+ break;
+ case BROWSER_PAGE_INFO:
+ break;
+ case BROWSER_PRINT:
+ break;
+ case BROWSER_NEW_WINDOW:
+ {
+ BString text;
+ nsurl *url;
+ nserror error;
+
+ if (!scaffold->url_bar->LockLooper())
+ break;
+ text = scaffold->url_bar->Text();
+ scaffold->url_bar->UnlockLooper();
+
+ NSBrowserWindow::activeWindow = scaffold->window;
+
+ error = nsurl_create(text.String(), &url);
+ if (error == NSERROR_OK) {
+ error = browser_window_create(BW_CREATE_CLONE,
+ url,
+ NULL,
+ bw,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (error != NSERROR_OK) {
+ beos_warn_user(messages_get_errorcode(error), 0);
+ }
+ break;
+ }
+ case BROWSER_VIEW_SOURCE:
+ {
+ if (!bw || browser_window_has_content(bw) == false)
+ break;
+ nsbeos_gui_view_source(browser_window_get_content(bw));
+ break;
+ }
+ case BROWSER_OBJECT:
+ break;
+ case BROWSER_OBJECT_INFO:
+ break;
+ case BROWSER_OBJECT_RELOAD:
+ break;
+ case BROWSER_OBJECT_SAVE:
+ break;
+ case BROWSER_OBJECT_EXPORT_SPRITE:
+ break;
+ case BROWSER_OBJECT_SAVE_URL_URI:
+ break;
+ case BROWSER_OBJECT_SAVE_URL_URL:
+ break;
+ case BROWSER_OBJECT_SAVE_URL_TEXT:
+ break;
+ case BROWSER_SAVE:
+ break;
+ case BROWSER_SAVE_COMPLETE:
+ break;
+ case BROWSER_EXPORT_DRAW:
+ break;
+ case BROWSER_EXPORT_TEXT:
+ break;
+ case BROWSER_SAVE_URL_URI:
+ break;
+ case BROWSER_SAVE_URL_URL:
+ break;
+ case BROWSER_SAVE_URL_TEXT:
+ break;
+ case HOTLIST_EXPORT:
+ break;
+ case HISTORY_EXPORT:
+ break;
+ case B_NETPOSITIVE_UP:
+ case BROWSER_NAVIGATE_UP:
+ break;
+ case BROWSER_NAVIGATE_URL:
+ if (!scaffold->url_bar->LockLooper())
+ break;
+ scaffold->url_bar->MakeFocus();
+ scaffold->url_bar->UnlockLooper();
+ break;
+ case BROWSER_SCALE_VIEW:
+ break;
+ case BROWSER_FIND_TEXT:
+ break;
+ case BROWSER_IMAGES_FOREGROUND:
+ break;
+ case BROWSER_IMAGES_BACKGROUND:
+ break;
+ case BROWSER_BUFFER_ANIMS:
+ break;
+ case BROWSER_BUFFER_ALL:
+ break;
+ case BROWSER_SAVE_VIEW:
+ break;
+ case BROWSER_WINDOW_DEFAULT:
+ break;
+ case BROWSER_WINDOW_STAGGER:
+ break;
+ case BROWSER_WINDOW_COPY:
+ break;
+ case BROWSER_WINDOW_RESET:
+ break;
+ case TREE_NEW_FOLDER:
+ case TREE_NEW_LINK:
+ case TREE_EXPAND_ALL:
+ case TREE_EXPAND_FOLDERS:
+ case TREE_EXPAND_LINKS:
+ case TREE_COLLAPSE_ALL:
+ case TREE_COLLAPSE_FOLDERS:
+ case TREE_COLLAPSE_LINKS:
+ case TREE_SELECTION:
+ case TREE_SELECTION_EDIT:
+ case TREE_SELECTION_LAUNCH:
+ case TREE_SELECTION_DELETE:
+ case TREE_SELECT_ALL:
+ case TREE_CLEAR_SELECTION:
+ break;
+ case TOOLBAR_BUTTONS:
+ break;
+ case TOOLBAR_ADDRESS_BAR:
+ break;
+ case TOOLBAR_THROBBER:
+ break;
+ case TOOLBAR_EDIT:
+ break;
+ case CHOICES_SHOW:
+ break;
+ case APPLICATION_QUIT:
+ nsbeos_done = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void nsbeos_scaffolding_destroy(nsbeos_scaffolding *scaffold)
+{
+ LOG("Being Destroyed = %d", scaffold->being_destroyed);
+ if (scaffold->being_destroyed) return;
+ scaffold->being_destroyed = 1;
+ nsbeos_window_destroy_event(scaffold->window, scaffold, NULL);
+}
+
+
+void nsbeos_window_update_back_forward(struct beos_scaffolding *g)
+{
+ struct browser_window *bw = nsbeos_get_browser_for_gui(g->top_level);
+
+ if (!g->top_view->LockLooper())
+ return;
+
+ g->back_button->SetEnabled(browser_window_history_back_available(bw));
+ g->forward_button->SetEnabled(browser_window_history_forward_available(bw));
+
+ g->top_view->UnlockLooper();
+
+}
+
+void nsbeos_throb(void *p)
+{
+ struct beos_scaffolding *g = (struct beos_scaffolding *)p;
+
+ if (g->throb_frame >= (nsbeos_throbber->nframes - 1))
+ g->throb_frame = 1;
+ else
+ g->throb_frame++;
+
+ if (!g->top_view->LockLooper())
+ return;
+
+ g->throbber->SetBitmap(nsbeos_throbber->framedata[g->throb_frame]);
+ g->throbber->Invalidate();
+
+ g->top_view->UnlockLooper();
+
+ beos_schedule(100, nsbeos_throb, p);
+
+}
+
+
+NSBrowserWindow *nsbeos_find_last_window(void)
+{
+ int32 i;
+ if (!be_app || !be_app->Lock())
+ return NULL;
+ for (i = be_app->CountWindows() - 1; i >= 0; i--) {
+ if (be_app->WindowAt(i) == NULL)
+ continue;
+ NSBrowserWindow *win;
+ win = dynamic_cast<NSBrowserWindow *>(be_app->WindowAt(i));
+ if (win) {
+ win->Lock();
+ be_app->Unlock();
+ return win;
+ }
+ }
+ be_app->Unlock();
+ return NULL;
+}
+
+NSBrowserWindow *nsbeos_get_bwindow_for_scaffolding(nsbeos_scaffolding *scaffold)
+{
+ return scaffold->window;
+}
+
+NSBaseView *nsbeos_get_baseview_for_scaffolding(nsbeos_scaffolding *scaffold)
+{
+ return scaffold->top_view;
+}
+
+static void recursively_set_menu_items_target(BMenu *menu, BHandler *handler)
+{
+ menu->SetTargetForItems(handler);
+ for (int i = 0; menu->ItemAt(i); i++) {
+ if (!menu->SubmenuAt(i))
+ continue;
+ recursively_set_menu_items_target(menu->SubmenuAt(i), handler);
+ }
+}
+
+void nsbeos_attach_toplevel_view(nsbeos_scaffolding *g, BView *view)
+{
+ LOG("Attaching view to scaffolding %p", g);
+
+ // this is a replicant,... and it went bad
+ if (!g->window) {
+ if (g->top_view->Looper() && !g->top_view->LockLooper())
+ return;
+ }
+
+ BRect rect(g->top_view->Bounds());
+ rect.top += TOOLBAR_HEIGHT;
+ rect.right -= B_V_SCROLL_BAR_WIDTH;
+ rect.bottom -= B_H_SCROLL_BAR_HEIGHT;
+
+ view->ResizeTo(rect.Width() /*+ 1*/, rect.Height() /*+ 1*/);
+ view->MoveTo(rect.LeftTop());
+
+
+ g->scroll_view = new BScrollView("NetSurfScrollView", view,
+ B_FOLLOW_ALL, 0, true, true, B_NO_BORDER);
+
+ g->top_view->AddChild(g->scroll_view);
+
+ // for replicants, add a NSResizeKnob to allow resizing
+ if (!g->window) {
+ BRect frame = g->scroll_view->Bounds();
+ frame.left = frame.right - B_V_SCROLL_BAR_WIDTH;
+ frame.top = frame.bottom - B_H_SCROLL_BAR_HEIGHT;
+ NSResizeKnob *knob = new NSResizeKnob(frame, g->top_view);
+ //TODO: set bitmap
+ g->scroll_view->AddChild(knob);
+ }
+
+ view->MakeFocus();
+
+ // resize the horiz scrollbar to make room for the status bar and add it.
+
+ BScrollBar *sb = g->scroll_view->ScrollBar(B_HORIZONTAL);
+ rect = sb->Frame();
+ float divider = rect.Width() + 1;
+ //divider /= 2;
+ divider *= 67.0/100; // 67%
+
+ sb->ResizeBy(-divider, 0);
+ sb->MoveBy(divider, 0);
+
+ rect.right = rect.left + divider - 1;
+
+ /*
+ BBox *statusBarBox = new BBox(rect, "StatusBarBox",
+ B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM,
+ B_WILL_DRAW | B_FRAME_EVENTS,
+ B_RAISED_BORDER);
+ */
+
+ g->status_bar->MoveTo(rect.LeftTop());
+ g->status_bar->ResizeTo(rect.Width() + 1, rect.Height() + 1);
+ g->scroll_view->AddChild(g->status_bar);
+ g->status_bar->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+ g->status_bar->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)) ;
+#if defined(__HAIKU__) || defined(B_DANO_VERSION)
+ g->status_bar->SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
+#endif
+
+
+
+ // set targets to the topmost ns view,
+ // we might not have a window later (replicant ?)
+ // this won't work for replicants, since the base view isn't attached yet
+ // we'll redo this in NSBaseView::AllAttached
+ g->back_button->SetTarget(view);
+ g->forward_button->SetTarget(view);
+ g->stop_button->SetTarget(view);
+ g->reload_button->SetTarget(view);
+ g->home_button->SetTarget(view);
+
+ g->url_bar->SetTarget(view);
+ g->search_bar->SetTarget(view);
+
+ nsbeos_scaffolding_update_colors(g);
+
+ if (g->window) {
+ recursively_set_menu_items_target(g->menu_bar, view);
+
+ // add toolbar shortcuts
+ BMessage *message;
+
+ message = new BMessage('back');
+ message->AddPointer("scaffolding", g);
+ g->window->AddShortcut(B_LEFT_ARROW, 0, message, view);
+
+ message = new BMessage('forw');
+ message->AddPointer("scaffolding", g);
+ g->window->AddShortcut(B_RIGHT_ARROW, 0, message, view);
+
+ message = new BMessage('stop');
+ message->AddPointer("scaffolding", g);
+ g->window->AddShortcut('S', 0, message, view);
+
+ message = new BMessage('relo');
+ message->AddPointer("scaffolding", g);
+ g->window->AddShortcut('R', 0, message, view);
+
+ message = new BMessage('home');
+ message->AddPointer("scaffolding", g);
+ g->window->AddShortcut('H', 0, message, view);
+
+
+#if defined(__HAIKU__)
+ // Make sure the window is layouted and answering to events, but do not
+ // show it before it is actually resized
+ g->window->Hide();
+ g->window->Show();
+
+ if(NSBrowserWindow::activeWindow) {
+ BWindowStack stack(NSBrowserWindow::activeWindow);
+ stack.AddWindow(g->window);
+ }
+#endif
+ g->window->Show();
+
+ } else {
+ if (g->top_view->Looper())
+ g->top_view->UnlockLooper();
+ }
+
+
+}
+
+static BMenuItem *make_menu_item(const char *name, BMessage *message, bool enabled=false)
+{
+ BMenuItem *item;
+ BString label(messages_get(name));
+ BString accel;
+ uint32 mods = 0;
+ char key = 0;
+ // try to understand accelerators
+ int32 start = label.IFindLast(" ");
+ if (start > 0 && (label.Length() - start > 1)
+ && (label.Length() - start < 7)
+ && (label[start + 1] == 'F'
+ || !strcmp(label.String() + start + 1, "PRINT")
+ || label[start + 1] == '\xe2'
+ || label[start + 1] == '^')) {
+
+ label.MoveInto(accel, start + 1, label.Length());
+ // strip the trailing spaces
+ while (label[label.Length() - 1] == ' ')
+ label.Truncate(label.Length() - 1);
+
+ if (accel.FindFirst("\xe2\x87\x91") > -1) {
+ accel.RemoveFirst("\xe2\x87\x91");
+ mods |= B_SHIFT_KEY;
+ }
+ if (accel.FindFirst("^") > -1) {
+ accel.RemoveFirst("^");
+ mods |= B_CONTROL_KEY; // ALT!!!
+ }
+ if (accel.FindFirst("PRINT") > -1) {
+ accel.RemoveFirst("PRINT");
+ //mods |= ; // ALT!!!
+ key = B_PRINT_KEY;
+ }
+ if (accel.Length() > 1 && accel[0] == 'F') { // Function key
+ int num;
+ if (sscanf(accel.String(), "F%d", &num) > 0) {
+ //
+ }
+ } else if (accel.Length() > 0) {
+ key = accel[0];
+ }
+ //printf("MENU: detected accel '%s' mods 0x%08lx, key %d\n", accel.String(), mods, key);
+ }
+
+ // turn ... into ellipsis
+ label.ReplaceAll("...", B_UTF8_ELLIPSIS);
+
+ item = new BMenuItem(label.String(), message, key, mods);
+
+ item->SetEnabled(enabled);
+
+ return item;
+}
+
+
+class BBitmapButton: public BButton
+{
+ public:
+ BBitmapButton(BRect rect, const char* name, const char* label,
+ BMessage* message);
+ ~BBitmapButton();
+
+ void Draw(BRect updateRect);
+ void SetBitmap(const char* attrName);
+ private:
+ BBitmap* fBitmap;
+ BBitmap* fDisabledBitmap;
+};
+
+
+BBitmapButton::BBitmapButton(BRect rect, const char* name, const char* label,
+ BMessage* message)
+ : BButton(rect, name, label, message)
+{
+ SetBitmap(name);
+}
+
+
+BBitmapButton::~BBitmapButton()
+{
+ delete fBitmap;
+ delete fDisabledBitmap;
+}
+
+
+void BBitmapButton::Draw(BRect updateRect)
+{
+ if(fBitmap == NULL) {
+ BButton::Draw(updateRect);
+ return;
+ }
+
+ SetDrawingMode(B_OP_COPY);
+ FillRect(updateRect, B_SOLID_LOW);
+ rgb_color color = LowColor();
+
+ SetDrawingMode(B_OP_ALPHA);
+ if(IsEnabled()) {
+ if(Value() != 0) {
+ // button is clicked
+ DrawBitmap(fBitmap, BPoint(1, 1));
+ } else {
+ // button is released
+ DrawBitmap(fBitmap, BPoint(0, 0));
+ }
+ } else
+ DrawBitmap(fDisabledBitmap, BPoint(0, 0));
+}
+
+
+void BBitmapButton::SetBitmap(const char* attrname)
+{
+#ifdef __HAIKU__
+ size_t size = 0;
+ const void* data = gAppResources->LoadResource('VICN', attrname, &size);
+
+ if (!data) {
+ printf("CANT LOAD RESOURCE %s\n", attrname);
+ return;
+ }
+
+ fBitmap = new BBitmap(BRect(0, 0, 32, 32), B_RGB32);
+ status_t status = BIconUtils::GetVectorIcon((const uint8*)data, size, fBitmap);
+
+ if(status != B_OK) {
+ fprintf(stderr, "%s > oops %s\n", attrname, strerror(status));
+ delete fBitmap;
+ fBitmap = NULL;
+ }
+
+ fDisabledBitmap = new BBitmap(fBitmap);
+ rgb_color* pixel = (rgb_color*)fDisabledBitmap->Bits();
+ for(int i = 0; i < fDisabledBitmap->BitsLength()/4; i++)
+ {
+ *pixel = tint_color(*pixel, B_DISABLED_MARK_TINT);
+ pixel++;
+ }
+#else
+ // No vector icon support on BeOS. We could try to load a bitmap one
+ fBitmap = NULL;
+ fDisabledBitmap = NULL;
+#endif
+}
+
+
+nsbeos_scaffolding *nsbeos_new_scaffolding(struct gui_window *toplevel)
+{
+ struct beos_scaffolding *g = (struct beos_scaffolding *)malloc(sizeof(*g));
+
+ LOG("Constructing a scaffold of %p for gui_window %p", g, toplevel);
+
+ g->top_level = toplevel;
+ g->being_destroyed = 0;
+ g->fullscreen = false;
+
+ open_windows++;
+
+ BMessage *message;
+ BRect rect;
+
+ g->window = NULL;
+ g->menu_bar = NULL;
+
+ if (replicated && !replicant_view) {
+ beos_warn_user("Error: No subwindow allowed when replicated.", NULL);
+ return NULL;
+ }
+
+
+ if (!replicant_view) {
+ BRect frame(0, 0, 600-1, 500-1);
+ if (nsoption_int(window_width) > 0) {
+ frame.Set(0, 0, nsoption_int(window_width) - 1, nsoption_int(window_height) - 1);
+ frame.OffsetToSelf(nsoption_int(window_x), nsoption_int(window_y));
+ } else {
+ BPoint pos(50, 50);
+ // XXX: use last BApplication::WindowAt()'s dynamic_cast<NSBrowserWindow *> Frame()
+ NSBrowserWindow *win = nsbeos_find_last_window();
+ if (win) {
+ pos = win->Frame().LeftTop();
+ win->UnlockLooper();
+ }
+ pos += BPoint(20, 20);
+ BScreen screen;
+ BRect screenFrame(screen.Frame());
+ if (pos.y + frame.Height() >= screenFrame.Height()) {
+ pos.y = 50;
+ pos.x += 50;
+ }
+ if (pos.x + frame.Width() >= screenFrame.Width()) {
+ pos.x = 50;
+ pos.y = 50;
+ }
+ frame.OffsetToSelf(pos);
+ }
+
+ g->window = new NSBrowserWindow(frame, g);
+
+ rect = frame.OffsetToCopy(0,0);
+ rect.bottom = rect.top + 20;
+
+ // build menus
+ g->menu_bar = new BMenuBar(rect, "menu_bar");
+ g->window->AddChild(g->menu_bar);
+
+ BMenu *menu;
+ BMenuItem *item;
+
+ // App menu
+ //XXX: use icon item ?
+
+ menu = new BMenu(messages_get("NetSurf"));
+ g->menu_bar->AddItem(menu);
+
+ message = new BMessage(B_ABOUT_REQUESTED);
+ item = make_menu_item("Info", message, true);
+ menu->AddItem(item);
+
+#if 0
+ message = new BMessage(NO_ACTION);
+ item = make_menu_item("AppHelp", message);
+ menu->AddItem(item);
+
+ submenu = new BMenu(messages_get("Open"));
+ menu->AddItem(submenu);
+
+ message = new BMessage(NO_ACTION);
+ item = make_menu_item("OpenURL", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(CHOICES_SHOW);
+ item = make_menu_item("Choices", message);
+ menu->AddItem(item);
+#endif
+
+ message = new BMessage(APPLICATION_QUIT);
+ item = make_menu_item("Quit", message, true);
+ menu->AddItem(item);
+
+ // Page menu
+
+ menu = new BMenu(messages_get("Page"));
+ g->menu_bar->AddItem(menu);
+
+#if 0
+ message = new BMessage(BROWSER_PAGE_INFO);
+ item = make_menu_item("PageInfo", message);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_SAVE);
+ item = make_menu_item("SaveAsNS", message);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_SAVE_COMPLETE);
+ item = make_menu_item("SaveCompNS", message);
+ menu->AddItem(item);
+
+ submenu = new BMenu(messages_get("Export"));
+ menu->AddItem(submenu);
+
+ /*
+ message = new BMessage(BROWSER_EXPORT_DRAW);
+ item = make_menu_item("Draw", message);
+ submenu->AddItem(item);
+ */
+
+ message = new BMessage(BROWSER_EXPORT_TEXT);
+ item = make_menu_item("LinkText", message);
+ submenu->AddItem(item);
+
+
+ submenu = new BMenu(messages_get("SaveURL"));
+ menu->AddItem(submenu);
+
+ //XXX
+ message = new BMessage(BROWSER_OBJECT_SAVE_URL_URL);
+ item = make_menu_item("URL", message);
+ submenu->AddItem(item);
+
+
+ message = new BMessage(BROWSER_PRINT);
+ item = make_menu_item("PrintNS", message);
+ menu->AddItem(item);
+#endif
+
+ message = new BMessage(BROWSER_NEW_WINDOW);
+ item = make_menu_item("NewWindowNS", message, true);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_VIEW_SOURCE);
+ item = make_menu_item("ViewSrc", message, true);
+ menu->AddItem(item);
+
+#if 0 // FIXME This is supposed to be a popup menu!
+ // Object menu
+
+ menu = new BMenu(messages_get("Object"));
+ g->menu_bar->AddItem(menu);
+
+ message = new BMessage(BROWSER_OBJECT_INFO);
+ item = make_menu_item("ObjInfo", message);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_OBJECT_SAVE);
+ item = make_menu_item("ObjSave", message);
+ menu->AddItem(item);
+ // XXX: submenu: Sprite ?
+
+ message = new BMessage(BROWSER_OBJECT_RELOAD);
+ item = make_menu_item("ObjReload", message);
+ menu->AddItem(item);
+#endif
+
+ // Navigate menu
+
+ menu = new BMenu(messages_get("Navigate"));
+ g->menu_bar->AddItem(menu);
+
+ message = new BMessage(BROWSER_NAVIGATE_HOME);
+ item = make_menu_item("Home", message, true);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_NAVIGATE_BACK);
+ item = make_menu_item("Back", message, true);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_NAVIGATE_FORWARD);
+ item = make_menu_item("Forward", message, true);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_NAVIGATE_UP);
+ item = make_menu_item("UpLevel", message);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_NAVIGATE_RELOAD);
+ item = make_menu_item("Reload", message, true);
+ menu->AddItem(item);
+
+ message = new BMessage(BROWSER_NAVIGATE_STOP);
+ item = make_menu_item("Stop", message, true);
+ menu->AddItem(item);
+
+#if 0
+ // View menu
+
+ menu = new BMenu(messages_get("View"));
+ g->menu_bar->AddItem(menu);
+
+ message = new BMessage(BROWSER_SCALE_VIEW);
+ item = make_menu_item("ScaleView", message);
+ menu->AddItem(item);
+
+ submenu = new BMenu(messages_get("Images"));
+ menu->AddItem(submenu);
+
+ message = new BMessage(BROWSER_IMAGES_FOREGROUND);
+ item = make_menu_item("ForeImg", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(BROWSER_IMAGES_BACKGROUND);
+ item = make_menu_item("BackImg", message);
+ submenu->AddItem(item);
+
+
+ submenu = new BMenu(messages_get("Toolbars"));
+ menu->AddItem(submenu);
+ submenu->SetEnabled(false);
+
+ message = new BMessage(NO_ACTION);
+ item = make_menu_item("ToolButtons", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(NO_ACTION);
+ item = make_menu_item("ToolAddress", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(NO_ACTION);
+ item = make_menu_item("ToolThrob", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(NO_ACTION);
+ item = make_menu_item("ToolStatus", message);
+ submenu->AddItem(item);
+
+
+ submenu = new BMenu(messages_get("Render"));
+ menu->AddItem(submenu);
+
+ message = new BMessage(BROWSER_BUFFER_ANIMS);
+ item = make_menu_item("RenderAnims", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(BROWSER_BUFFER_ALL);
+ item = make_menu_item("RenderAll", message);
+ submenu->AddItem(item);
+
+
+ message = new BMessage(NO_ACTION);
+ item = make_menu_item("OptDefault", message);
+ menu->AddItem(item);
+#endif
+
+ // Utilities menu
+
+ menu = new BMenu(messages_get("Utilities"));
+ g->menu_bar->AddItem(menu);
+
+#if 0
+ submenu = new BMenu(messages_get("Hotlist"));
+ menu->AddItem(submenu);
+
+ message = new BMessage(HOTLIST_ADD_URL);
+ item = make_menu_item("HotlistAdd", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(HOTLIST_SHOW);
+ item = make_menu_item("HotlistShowNS", message);
+ submenu->AddItem(item);
+
+
+ submenu = new BMenu(messages_get("History"));
+ menu->AddItem(submenu);
+
+ message = new BMessage(HISTORY_SHOW_LOCAL);
+ item = make_menu_item("HistLocal", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(HISTORY_SHOW_GLOBAL);
+ item = make_menu_item("HistGlobal", message);
+ submenu->AddItem(item);
+#endif
+
+ message = new BMessage(COOKIES_SHOW);
+ item = make_menu_item("Cookie manager", message, true);
+ menu->AddItem(item);
+
+#if 0
+ message = new BMessage(BROWSER_FIND_TEXT);
+ item = make_menu_item("FindText", message);
+ menu->AddItem(item);
+
+ submenu = new BMenu(messages_get("Window"));
+ menu->AddItem(submenu);
+
+ message = new BMessage(BROWSER_WINDOW_DEFAULT);
+ item = make_menu_item("WindowSave", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(BROWSER_WINDOW_STAGGER);
+ item = make_menu_item("WindowStagr", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(BROWSER_WINDOW_COPY);
+ item = make_menu_item("WindowSize", message);
+ submenu->AddItem(item);
+
+ message = new BMessage(BROWSER_WINDOW_RESET);
+ item = make_menu_item("WindowReset", message);
+ submenu->AddItem(item);
+#endif
+
+
+ // Help menu
+
+ menu = new BMenu(messages_get("Help"));
+ g->menu_bar->AddItem(menu);
+
+#if 0
+ message = new BMessage(HELP_OPEN_CONTENTS);
+ item = make_menu_item("HelpContent", message);
+ menu->AddItem(item);
+
+ message = new BMessage(HELP_OPEN_GUIDE);
+ item = make_menu_item("HelpGuide", message);
+ menu->AddItem(item);
+
+ message = new BMessage(HELP_OPEN_INFORMATION);
+ item = make_menu_item("HelpInfo", message);
+ menu->AddItem(item);
+#endif
+
+ message = new BMessage(HELP_OPEN_ABOUT);
+ item = make_menu_item("HelpCredits", message, true);
+ menu->AddItem(item);
+
+ message = new BMessage(HELP_OPEN_LICENCE);
+ item = make_menu_item("HelpLicence", message, true);
+ menu->AddItem(item);
+
+#if 0
+ message = new BMessage(HELP_LAUNCH_INTERACTIVE);
+ item = make_menu_item("HelpInter", message);
+ menu->AddItem(item);
+#endif
+
+ // the base view that receives the toolbar, statusbar and top-level view.
+ rect = frame.OffsetToCopy(0,0);
+ rect.top = g->menu_bar->Bounds().Height() + 1;
+ //rect.top = 20 + 1; // XXX
+ //rect.bottom -= B_H_SCROLL_BAR_HEIGHT;
+ g->top_view = new NSBaseView(rect);
+ // add the top view to the window
+ g->window->AddChild(g->top_view);
+ } else { // replicant_view
+ // the base view has already been created with the archive constructor
+ g->top_view = replicant_view;
+ }
+ g->top_view->SetScaffolding(g);
+
+ // build popup menu
+ g->popup_menu = new BPopUpMenu("");
+
+
+#ifdef ENABLE_DRAGGER
+ // the dragger to allow replicating us
+ // XXX: try to stuff it in the status bar at the bottom
+ // (BDragger *must* be a parent, sibiling or direct child of NSBaseView!)
+ rect = g->top_view->Bounds();
+ rect.bottom = rect.top + TOOLBAR_HEIGHT - 1;
+ rect.left = rect.right - DRAGGER_WIDTH + 1;
+ g->dragger = new BDragger(rect, g->top_view,
+ B_FOLLOW_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW);
+ g->top_view->AddChild(g->dragger);
+ g->dragger->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+ g->dragger->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)) ;
+#endif
+
+ // tool_bar
+ // the toolbar is also the dragger for now
+ // XXX: try to stuff it in the status bar at the bottom
+ // (BDragger *must* be a parent, sibiling or direct child of NSBaseView!)
+ // XXX: B_FULL_UPDATE_ON_RESIZE avoids leaving bits on resize,
+ // but causes flicker
+ rect = g->top_view->Bounds();
+ rect.bottom = rect.top + TOOLBAR_HEIGHT - 1;
+#ifdef ENABLE_DRAGGER
+ rect.right = rect.right - DRAGGER_WIDTH;
+#else
+ rect.right = rect.right + 1;
+#endif
+ g->tool_bar = new BBox(rect, "Toolbar",
+ B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS
+ | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE_JUMP, B_PLAIN_BORDER);
+ g->top_view->AddChild(g->tool_bar);
+ g->tool_bar->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+ g->tool_bar->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)) ;
+
+ // buttons
+ rect = g->tool_bar->Bounds();
+ rect.right = TOOLBAR_HEIGHT;
+ rect.InsetBySelf(5, 5);
+ rect.OffsetBySelf(0, -1);
+ int nButtons = 0;
+
+ message = new BMessage('back');
+ message->AddPointer("scaffolding", g);
+ g->back_button = new BBitmapButton(rect, "back_button", "<", message);
+ g->tool_bar->AddChild(g->back_button);
+ nButtons++;
+
+ rect.OffsetBySelf(TOOLBAR_HEIGHT, 0);
+ message = new BMessage('forw');
+ message->AddPointer("scaffolding", g);
+ g->forward_button = new BBitmapButton(rect, "forward_button", ">", message);
+ g->tool_bar->AddChild(g->forward_button);
+ nButtons++;
+
+ rect.OffsetBySelf(TOOLBAR_HEIGHT, 0);
+ message = new BMessage('stop');
+ message->AddPointer("scaffolding", g);
+ g->stop_button = new BBitmapButton(rect, "stop_button", "S", message);
+ g->tool_bar->AddChild(g->stop_button);
+ nButtons++;
+
+ rect.OffsetBySelf(TOOLBAR_HEIGHT, 0);
+ message = new BMessage('relo');
+ message->AddPointer("scaffolding", g);
+ g->reload_button = new BBitmapButton(rect, "reload_button", "R", message);
+ g->tool_bar->AddChild(g->reload_button);
+ nButtons++;
+
+ rect.OffsetBySelf(TOOLBAR_HEIGHT, 0);
+ message = new BMessage('home');
+ message->AddPointer("scaffolding", g);
+ g->home_button = new BBitmapButton(rect, "home_button", "H", message);
+ g->tool_bar->AddChild(g->home_button);
+ nButtons++;
+
+
+ // url bar
+ rect = g->tool_bar->Bounds();
+ rect.left += TOOLBAR_HEIGHT * nButtons;
+ rect.right -= TOOLBAR_HEIGHT * 1 + 100;
+ rect.InsetBySelf(5, 5);
+ message = new BMessage('urle');
+ message->AddPointer("scaffolding", g);
+ g->url_bar = new NSIconTextControl(rect, "url_bar", "", "", message,
+ B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
+ g->url_bar->SetDivider(0);
+ rect = g->url_bar->TextView()->TextRect();
+ rect.left += 16;
+ g->url_bar->TextView()->SetTextRect(rect);
+ g->tool_bar->AddChild(g->url_bar);
+
+ // search bar
+
+ rect = g->tool_bar->Bounds();
+ rect.left = g->url_bar->Frame().right;
+ rect.right -= TOOLBAR_HEIGHT * 1;
+ rect.InsetBy(5,5);
+ message = new BMessage('sear');
+ message->AddPointer("scaffolding", g);
+ g->search_bar = new BTextControl(rect, "search_bar", "",
+ "Search" B_UTF8_ELLIPSIS, message, B_FOLLOW_RIGHT | B_FOLLOW_TOP);
+ g->search_bar->SetDivider(0);
+ g->tool_bar->AddChild(g->search_bar);
+
+ // throbber
+ rect.Set(0, 0, 24, 24);
+ rect.OffsetTo(g->tool_bar->Bounds().right - 24 - (TOOLBAR_HEIGHT - 24) / 2,
+ (TOOLBAR_HEIGHT - 24) / 2);
+ g->throbber = new NSThrobber(rect);
+ g->tool_bar->AddChild(g->throbber);
+ g->throbber->SetViewColor(g->tool_bar->ViewColor());
+ g->throbber->SetLowColor(g->tool_bar->ViewColor());
+ g->throbber->SetDrawingMode(B_OP_ALPHA);
+ g->throbber->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
+ /* set up the throbber. */
+ g->throbber->SetBitmap(nsbeos_throbber->framedata[0]);
+ g->throb_frame = 0;
+
+
+ // the status bar at the bottom
+ BString status("NetSurf");
+ status << " " << netsurf_version;
+ g->status_bar = new BStringView(BRect(0,0,-1,-1), "StatusBar",
+ status.String(), B_FOLLOW_LEFT/*_RIGHT*/ | B_FOLLOW_BOTTOM);
+
+ // will be added to the scrollview when adding the top view.
+
+ // notify the thread creating the replicant that we're done
+ if (replicant_view)
+ release_sem(replicant_done_sem);
+
+ replicant_view = NULL;
+
+ return g;
+}
+
+void gui_window_set_title(struct gui_window *_g, const char *title)
+{
+ struct beos_scaffolding *g = nsbeos_get_scaffold(_g);
+ if (g->top_level != _g) return;
+
+ // if we're a replicant, discard
+ if (!g->window)
+ return;
+
+ BString nt(title);
+ if (nt.Length())
+ nt << " - ";
+ nt << "NetSurf";
+
+ if (!g->top_view->LockLooper())
+ return;
+
+ g->window->SetTitle(nt.String());
+
+ g->top_view->UnlockLooper();
+}
+
+void gui_window_set_status(struct gui_window *_g, const char *text)
+{
+ struct beos_scaffolding *g = nsbeos_get_scaffold(_g);
+ assert(g);
+ assert(g->status_bar);
+
+ if (!g->top_view->LockLooper())
+ return;
+
+ if (text == NULL || text[0] == '\0')
+ {
+ BString status("NetSurf");
+ status << " " << netsurf_version;
+ g->status_bar->SetText(status.String());
+ }
+ else
+ {
+ g->status_bar->SetText(text);
+ }
+ g->top_view->UnlockLooper();
+}
+
+nserror gui_window_set_url(struct gui_window *gw, nsurl *url)
+{
+ struct beos_scaffolding *g;
+
+ g = nsbeos_get_scaffold(gw);
+ if (g->top_level != gw)
+ return NSERROR_OK;
+
+ assert(g->status_bar);
+
+ if (g->top_view->LockLooper()) {
+ g->url_bar->SetText(nsurl_access(url));
+
+ g->top_view->UnlockLooper();
+ }
+
+ return NSERROR_OK;
+}
+
+void gui_window_start_throbber(struct gui_window* _g)
+{
+ struct beos_scaffolding *g = nsbeos_get_scaffold(_g);
+
+ if (!g->top_view->LockLooper())
+ return;
+
+ g->stop_button->SetEnabled(true);
+ g->reload_button->SetEnabled(false);
+
+ g->top_view->UnlockLooper();
+
+ nsbeos_window_update_back_forward(g);
+
+ beos_schedule(100, nsbeos_throb, g);
+}
+
+void gui_window_stop_throbber(struct gui_window* _g)
+{
+ struct beos_scaffolding *g = nsbeos_get_scaffold(_g);
+
+ nsbeos_window_update_back_forward(g);
+
+ beos_schedule(-1, nsbeos_throb, g);
+
+ if (!g->top_view->LockLooper())
+ return;
+
+ g->stop_button->SetEnabled(false);
+ g->reload_button->SetEnabled(true);
+
+ g->throbber->SetBitmap(nsbeos_throbber->framedata[0]);
+ g->throbber->Invalidate();
+
+ g->top_view->UnlockLooper();
+}
+
+/**
+ * add retrieved favicon to the gui
+ */
+void gui_window_set_icon(struct gui_window *_g, hlcache_handle *icon)
+{
+ BBitmap *bitmap = NULL;
+ struct bitmap *bmp_icon;
+
+ bmp_icon = (icon != NULL) ? content_get_bitmap(icon) : NULL;
+
+ if (bmp_icon) {
+ bitmap = nsbeos_bitmap_get_primary(bmp_icon);
+ }
+
+ struct beos_scaffolding *g = nsbeos_get_scaffold(_g);
+
+ if (!g->top_view->LockLooper())
+ return;
+
+ g->url_bar->SetBitmap(bitmap);
+
+ g->top_view->UnlockLooper();
+}
+
+
+void nsbeos_scaffolding_popup_menu(nsbeos_scaffolding *g, BPoint where)
+{
+ g->popup_menu->Go(where);
+}
+
diff --git a/frontends/beos/scaffolding.h b/frontends/beos/scaffolding.h
new file mode 100644
index 000000000..3fdca57f6
--- /dev/null
+++ b/frontends/beos/scaffolding.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_BEOS_SCAFFOLDING_H
+#define NETSURF_BEOS_SCAFFOLDING_H 1
+
+#include <View.h>
+#include <Window.h>
+#include <NetPositive.h>
+
+extern "C" {
+struct hlcache_handle;
+struct nsurl;
+}
+
+typedef struct beos_scaffolding nsbeos_scaffolding;
+
+class NSBaseView : public BView {
+public:
+ NSBaseView(BRect frame);
+ NSBaseView(BMessage *archive);
+virtual ~NSBaseView();
+
+virtual void MessageReceived(BMessage *message);
+//virtual void Draw(BRect updateRect);
+
+//virtual void FrameMoved(BPoint new_location);
+//virtual void FrameResized(float new_width, float new_height);
+
+virtual void AllAttached(void);
+
+virtual status_t Archive(BMessage *archive, bool deep=true) const;
+static BArchivable *Instantiate(BMessage *archive);
+
+void SetScaffolding(struct beos_scaffolding *scaf);
+private:
+ struct beos_scaffolding *fScaffolding;
+};
+
+class NSBrowserWindow : public BWindow {
+public:
+ NSBrowserWindow(BRect frame, struct beos_scaffolding *scaf);
+virtual ~NSBrowserWindow();
+
+virtual void DispatchMessage(BMessage *message, BHandler *handler);
+virtual void MessageReceived(BMessage *message);
+virtual bool QuitRequested(void);
+void WindowActivated(bool active);
+
+struct beos_scaffolding *Scaffolding() const { return fScaffolding; };
+
+static BWindow* activeWindow;
+private:
+ struct beos_scaffolding *fScaffolding;
+
+
+};
+
+
+// XXX: clean up
+typedef enum {
+
+ /* no/unknown actions */
+ NO_ACTION = 'nsMA',
+
+ /* help actions */
+ HELP_OPEN_CONTENTS,
+ HELP_OPEN_GUIDE,
+ HELP_OPEN_INFORMATION,
+ HELP_OPEN_ABOUT,
+ HELP_OPEN_LICENCE,
+ HELP_LAUNCH_INTERACTIVE,
+
+ /* history actions */
+ HISTORY_SHOW_LOCAL,
+ HISTORY_SHOW_GLOBAL,
+
+ /* hotlist actions */
+ HOTLIST_ADD_URL,
+ HOTLIST_SHOW,
+
+ /* cookie actions */
+ COOKIES_SHOW,
+ COOKIES_DELETE,
+
+ /* page actions */
+ BROWSER_PAGE,
+ BROWSER_PAGE_INFO,
+ BROWSER_PRINT,
+ BROWSER_NEW_WINDOW,
+ BROWSER_VIEW_SOURCE,
+
+ /* object actions */
+ BROWSER_OBJECT,
+ BROWSER_OBJECT_INFO,
+ BROWSER_OBJECT_RELOAD,
+
+ /* save actions */
+ BROWSER_OBJECT_SAVE,
+ BROWSER_OBJECT_EXPORT_SPRITE,
+ BROWSER_OBJECT_SAVE_URL_URI,
+ BROWSER_OBJECT_SAVE_URL_URL,
+ BROWSER_OBJECT_SAVE_URL_TEXT,
+ BROWSER_SAVE,
+ BROWSER_SAVE_COMPLETE,
+ BROWSER_EXPORT_DRAW,
+ BROWSER_EXPORT_TEXT,
+ BROWSER_SAVE_URL_URI,
+ BROWSER_SAVE_URL_URL,
+ BROWSER_SAVE_URL_TEXT,
+ HOTLIST_EXPORT,
+ HISTORY_EXPORT,
+
+ /* navigation actions */
+ BROWSER_NAVIGATE_HOME,
+ BROWSER_NAVIGATE_BACK,
+ BROWSER_NAVIGATE_FORWARD,
+ BROWSER_NAVIGATE_UP,
+ BROWSER_NAVIGATE_RELOAD,
+ BROWSER_NAVIGATE_RELOAD_ALL,
+ BROWSER_NAVIGATE_STOP,
+ BROWSER_NAVIGATE_URL,
+
+ /* browser window/display actions */
+ BROWSER_SCALE_VIEW,
+ BROWSER_FIND_TEXT,
+ BROWSER_IMAGES_FOREGROUND,
+ BROWSER_IMAGES_BACKGROUND,
+ BROWSER_BUFFER_ANIMS,
+ BROWSER_BUFFER_ALL,
+ BROWSER_SAVE_VIEW,
+ BROWSER_WINDOW_DEFAULT,
+ BROWSER_WINDOW_STAGGER,
+ BROWSER_WINDOW_COPY,
+ BROWSER_WINDOW_RESET,
+
+ /* tree actions */
+ TREE_NEW_FOLDER,
+ TREE_NEW_LINK,
+ TREE_EXPAND_ALL,
+ TREE_EXPAND_FOLDERS,
+ TREE_EXPAND_LINKS,
+ TREE_COLLAPSE_ALL,
+ TREE_COLLAPSE_FOLDERS,
+ TREE_COLLAPSE_LINKS,
+ TREE_SELECTION,
+ TREE_SELECTION_EDIT,
+ TREE_SELECTION_LAUNCH,
+ TREE_SELECTION_DELETE,
+ TREE_SELECT_ALL,
+ TREE_CLEAR_SELECTION,
+
+ /* toolbar actions */
+ TOOLBAR_BUTTONS,
+ TOOLBAR_ADDRESS_BAR,
+ TOOLBAR_THROBBER,
+ TOOLBAR_EDIT,
+
+ /* misc actions */
+ CHOICES_SHOW,
+ APPLICATION_QUIT,
+} menu_action;
+
+
+NSBrowserWindow *nsbeos_find_last_window(void);
+
+NSBrowserWindow *nsbeos_get_bwindow_for_scaffolding(nsbeos_scaffolding *scaffold);
+
+NSBaseView *nsbeos_get_baseview_for_scaffolding(nsbeos_scaffolding *scaffold);
+
+nsbeos_scaffolding *nsbeos_new_scaffolding(struct gui_window *toplevel);
+
+bool nsbeos_scaffolding_is_busy(nsbeos_scaffolding *scaffold);
+
+void nsbeos_attach_toplevel_view(nsbeos_scaffolding *g, BView *view);
+
+
+void nsbeos_scaffolding_dispatch_event(nsbeos_scaffolding *scaffold, BMessage *message);
+
+void nsbeos_scaffolding_destroy(nsbeos_scaffolding *scaffold);
+
+//void nsbeos_window_destroy_event(NSBrowserWindow *window, nsbeos_scaffolding *g, BMessage *event);
+
+
+void nsbeos_scaffolding_popup_menu(nsbeos_scaffolding *g, BPoint where);
+
+void gui_window_set_title(struct gui_window *_g, const char *title);
+nserror gui_window_set_url(struct gui_window *_g, struct nsurl *url);
+void gui_window_set_icon(struct gui_window *_g, struct hlcache_handle *icon);
+void gui_window_set_status(struct gui_window *_g, const char *text);
+void gui_window_start_throbber(struct gui_window* _g);
+void gui_window_stop_throbber(struct gui_window* _g);
+
+#endif /* NETSURF_BEOS_SCAFFOLDING_H */
diff --git a/frontends/beos/schedule.cpp b/frontends/beos/schedule.cpp
new file mode 100644
index 000000000..a9da53501
--- /dev/null
+++ b/frontends/beos/schedule.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdlib.h>
+#include <stdbool.h>
+#include <OS.h>
+#include <List.h>
+
+extern "C" {
+#include "utils/errors.h"
+#include "beos/schedule.h"
+#include "content/content.h"
+#include "desktop/browser.h"
+
+#ifdef DEBUG_BEOS_SCHEDULE
+#include "utils/log.h"
+#else
+#define LOG(x...)
+#endif
+}
+
+/** Killable callback closure embodiment. */
+typedef struct {
+ void (*callback)(void *); /**< The callback function. */
+ void *context; /**< The context for the callback. */
+ bool callback_killed; /**< Whether or not this was killed. */
+ bool callback_fired; /**< Whether or not this has fired yet. */
+ bigtime_t timeout;
+} _nsbeos_callback_t;
+
+/** List of all callbacks. */
+static BList *callbacks = NULL;
+
+/** earliest deadline. It's used for select() in gui_poll() */
+bigtime_t earliest_callback_timeout = B_INFINITE_TIMEOUT;
+
+
+static bool
+nsbeos_schedule_kill_callback(void *_target, void *_match)
+{
+ _nsbeos_callback_t *target = (_nsbeos_callback_t *)_target;
+ _nsbeos_callback_t *match = (_nsbeos_callback_t *)_match;
+ if ((target->callback == match->callback) &&
+ (target->context == match->context)) {
+ LOG("Found match for %p(%p), killing.", target->callback, target->context);
+ target->callback = NULL;
+ target->context = NULL;
+ target->callback_killed = true;
+ }
+ return false;
+}
+
+static void
+schedule_remove(void (*callback)(void *p), void *p)
+{
+ LOG("schedule_remove() for %p(%p)", cb->callback, cb->context);
+ if (callbacks == NULL)
+ return;
+ _nsbeos_callback_t cb_match;
+ cb_match.callback = callback;
+ cb_match.context = p;
+
+ callbacks->DoForEach(nsbeos_schedule_kill_callback, &cb_match);
+}
+
+nserror beos_schedule(int t, void (*callback)(void *p), void *p)
+{
+ LOG("t:%d cb:%p p:%p", t, cb->callback, cb->context);
+
+ if (callbacks == NULL) {
+ callbacks = new BList;
+ }
+
+ /* Kill any pending schedule of this kind. */
+ schedule_remove(callback, p);
+
+ if (t < 0) {
+ return NSERROR_OK;
+ }
+
+ bigtime_t timeout = system_time() + t * 1000LL;
+ _nsbeos_callback_t *cb = (_nsbeos_callback_t *)malloc(sizeof(_nsbeos_callback_t));
+ cb->callback = callback;
+ cb->context = p;
+ cb->callback_killed = cb->callback_fired = false;
+ cb->timeout = timeout;
+ if (earliest_callback_timeout > timeout) {
+ earliest_callback_timeout = timeout;
+ }
+ callbacks->AddItem(cb);
+
+ return NSERROR_OK;
+}
+
+bool
+schedule_run(void)
+{
+ LOG("schedule_run()");
+
+ earliest_callback_timeout = B_INFINITE_TIMEOUT;
+ if (callbacks == NULL)
+ return false; /* Nothing to do */
+
+ bigtime_t now = system_time();
+ int32 i;
+
+ LOG("Checking %ld callbacks to for deadline.", this_run->CountItems());
+
+ /* Run all the callbacks which made it this far. */
+ for (i = 0; i < callbacks->CountItems(); ) {
+ _nsbeos_callback_t *cb = (_nsbeos_callback_t *)(callbacks->ItemAt(i));
+ if (cb->timeout > now) {
+ // update next deadline
+ if (earliest_callback_timeout > cb->timeout)
+ earliest_callback_timeout = cb->timeout;
+ i++;
+ continue;
+ }
+ LOG("Running callbacks %p(%p).", cb->callback, cb->context);
+ if (!cb->callback_killed)
+ cb->callback(cb->context);
+ callbacks->RemoveItem(cb);
+ free(cb);
+ }
+ return true;
+}
diff --git a/frontends/beos/schedule.h b/frontends/beos/schedule.h
new file mode 100644
index 000000000..18f1efd4d
--- /dev/null
+++ b/frontends/beos/schedule.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_BEOS_CALLBACK_H
+#define NETSURF_BEOS_CALLBACK_H 1
+
+extern bigtime_t earliest_callback_timeout;
+
+extern "C" nserror beos_schedule(int t, void (*callback)(void *p), void *p);
+
+extern "C" bool schedule_run(void);
+
+
+#endif /* NETSURF_BEOS_CALLBACK_H */
diff --git a/frontends/beos/search.cpp b/frontends/beos/search.cpp
new file mode 100644
index 000000000..97e3d6d5b
--- /dev/null
+++ b/frontends/beos/search.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+//#include <stdbool.h>
+#include <string.h>
+
+extern "C" {
+#include "utils/log.h"
+}
+/* callback functions for search implementation */
+static void gui_search_set_status(bool found, void *p);
+static void gui_search_set_hourglass(bool active, void *p);
+static void gui_search_add_recent(const char *string, void *p);
+static void gui_search_set_forward_state(bool active, void *p);
+static void gui_search_set_back_state(bool active, void *p);
+
+/**
+ * Change the displayed search status.
+ * \param found search pattern matched in text
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_status(bool found, void *p)
+{
+}
+
+/**
+ * display hourglass while searching
+ * \param active start/stop indicator
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_hourglass(bool active, void *p)
+{
+}
+
+/**
+ * add search string to recent searches list
+ * \param string search pattern
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_add_recent(const char *string, void *p)
+{
+}
+
+/**
+ * activate search forwards button in gui
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_forward_state(bool active, void *p)
+{
+}
+
+/**
+ * activate search forwards button in gui
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_back_state(bool active, void *p)
+{
+}
diff --git a/frontends/beos/throbber.cpp b/frontends/beos/throbber.cpp
new file mode 100644
index 000000000..fe40b3edc
--- /dev/null
+++ b/frontends/beos/throbber.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+extern "C" {
+#include "utils/log.h"
+}
+#include "beos/throbber.h"
+#include "beos/bitmap.h"
+#include "beos/fetch_rsrc.h"
+
+#include <File.h>
+#include <Resources.h>
+#include <TranslationUtils.h>
+
+struct nsbeos_throbber *nsbeos_throbber = NULL;
+
+/**
+ * Creates the throbber using a PNG for each frame. The number of frames must
+ * be at least two. The first frame is the inactive frame, others are the
+ * active frames.
+ *
+ * \param frames The number of frames. Must be at least two.
+ * \param ... Filenames of PNGs containing frames.
+ * \return true on success.
+ */
+bool nsbeos_throbber_initialise_from_png(const int frames, ...)
+{
+ va_list filenames;
+ struct nsbeos_throbber *throb; /**< structure we generate */
+ bool errors_when_loading = false; /**< true if a frame failed */
+
+ if (frames < 2) {
+ /* we need at least two frames - one for idle, one for active */
+ LOG("Insufficent number of frames in throbber animation!");
+ LOG("(called with %d frames, where 2 is a minimum.)", frames);
+ return false;
+ }
+
+ BResources *res = get_app_resources();
+ if (res == NULL) {
+ LOG("Can't find resources for throbber!");
+ return false;
+ }
+
+ throb = (struct nsbeos_throbber *)malloc(sizeof(throb));
+ throb->nframes = frames;
+ throb->framedata = (BBitmap **)malloc(sizeof(BBitmap *) * throb->nframes);
+
+ va_start(filenames, frames);
+
+ for (int i = 0; i < frames; i++) {
+ const char *fn = va_arg(filenames, const char *);
+ const void *data;
+ size_t size;
+ data = res->LoadResource('data', fn, &size);
+ throb->framedata[i] = NULL;
+ if (!data) {
+ LOG("Error when loading resource %s", fn);
+ errors_when_loading = true;
+ continue;
+ }
+ BMemoryIO mem(data, size);
+ throb->framedata[i] = BTranslationUtils::GetBitmap(&mem);
+ if (throb->framedata[i] == NULL) {
+ LOG("Error when loading %s: GetBitmap() returned NULL", fn);
+ errors_when_loading = true;
+ }
+ }
+
+ va_end(filenames);
+
+ if (errors_when_loading == true) {
+ for (int i = 0; i < frames; i++) {
+ delete throb->framedata[i];
+ }
+
+ free(throb->framedata);
+ free(throb);
+
+ return false;
+ }
+
+ nsbeos_throbber = throb;
+
+ return true;
+}
+
+void nsbeos_throbber_finalise(void)
+{
+ int i;
+
+ for (i = 0; i < nsbeos_throbber->nframes; i++)
+ delete nsbeos_throbber->framedata[i];
+
+ free(nsbeos_throbber->framedata);
+ free(nsbeos_throbber);
+
+ nsbeos_throbber = NULL;
+}
diff --git a/frontends/beos/throbber.h b/frontends/beos/throbber.h
new file mode 100644
index 000000000..670c60a06
--- /dev/null
+++ b/frontends/beos/throbber.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BEOS_THROBBER_H__
+#define __BEOS_THROBBER_H__
+
+#include <Bitmap.h>
+
+struct nsbeos_throbber
+{
+ int nframes; /**< Number of frames in the throbber */
+ BBitmap **framedata;
+};
+
+extern struct nsbeos_throbber *nsbeos_throbber;
+
+bool nsbeos_throbber_initialise_from_gif(const char *fn);
+bool nsbeos_throbber_initialise_from_png(const int frames, ...);
+void nsbeos_throbber_finalise(void);
+
+#endif /* __BEOS_THROBBER_H__ */
diff --git a/frontends/beos/window.cpp b/frontends/beos/window.cpp
new file mode 100644
index 000000000..62624f077
--- /dev/null
+++ b/frontends/beos/window.cpp
@@ -0,0 +1,1382 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ * Copyright 2006 Daniel Silverstone <dsilvers@digital-scurf.org>
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __STDBOOL_H__ 1
+#include <stdlib.h>
+#include <assert.h>
+
+extern "C" {
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/utf8.h"
+#include "utils/utils.h"
+#include "content/content.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/mouse.h"
+#include "desktop/textinput.h"
+#include "desktop/plotters.h"
+#include "desktop/gui_window.h"
+#include "desktop/gui_clipboard.h"
+}
+
+#include "beos/about.h"
+#include "beos/window.h"
+#include "beos/font.h"
+#include "beos/gui.h"
+#include "beos/scaffolding.h"
+#include "beos/plotters.h"
+
+#include <AppDefs.h>
+#include <BeBuild.h>
+#include <Clipboard.h>
+#include <Cursor.h>
+#include <InterfaceDefs.h>
+#include <Message.h>
+#include <ScrollBar.h>
+#include <String.h>
+#include <String.h>
+#include <TextView.h>
+#include <View.h>
+#include <Window.h>
+
+class NSBrowserFrameView;
+
+struct gui_window {
+ /* All gui_window objects have an ultimate scaffold */
+ nsbeos_scaffolding *scaffold;
+ bool toplevel;
+ /* A gui_window is the rendering of a browser_window */
+ struct browser_window *bw;
+
+ struct {
+ int pressed_x;
+ int pressed_y;
+ int state; /* browser_mouse_state */
+ } mouse;
+
+ /* These are the storage for the rendering */
+ int caretx, carety, careth;
+ gui_pointer_shape current_pointer;
+ int last_x, last_y;
+
+ NSBrowserFrameView *view;
+
+ // some cached events to speed up things
+ // those are the last queued event of their kind,
+ // we can safely drop others and avoid wasting cpu.
+ // number of pending resizes
+ int32 pending_resizes;
+ // accumulated rects of pending redraws
+ //volatile BMessage *lastRedraw;
+ // UNUSED YET
+ BRect pendingRedraw;
+
+ /* Keep gui_windows in a list for cleanup later */
+ struct gui_window *next, *prev;
+
+ float scale;
+};
+
+
+
+static const rgb_color kWhiteColor = {255, 255, 255, 255};
+
+static struct gui_window *window_list = 0; /**< first entry in win list*/
+
+static BString current_selection;
+static BList current_selection_textruns;
+
+/* Methods which apply only to a gui_window */
+static void nsbeos_window_expose_event(BView *view, gui_window *g, BMessage *message);
+static void nsbeos_window_keypress_event(BView *view, gui_window *g, BMessage *event);
+static void nsbeos_window_resize_event(BView *view, gui_window *g, BMessage *event);
+static void nsbeos_window_moved_event(BView *view, gui_window *g, BMessage *event);
+/* Other useful bits */
+static void nsbeos_redraw_caret(struct gui_window *g);
+
+
+// #pragma mark - class NSBrowserFrameView
+
+
+NSBrowserFrameView::NSBrowserFrameView(BRect frame, struct gui_window *gui)
+ : BView(frame, "NSBrowserFrameView", B_FOLLOW_ALL_SIDES,
+ B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS ),
+ fGuiWindow(gui)
+{
+}
+
+
+NSBrowserFrameView::~NSBrowserFrameView()
+{
+}
+
+
+void
+NSBrowserFrameView::MessageReceived(BMessage *message)
+{
+ switch (message->what) {
+ case B_SIMPLE_DATA:
+ case B_ARGV_RECEIVED:
+ case B_REFS_RECEIVED:
+ case B_COPY:
+ case B_CUT:
+ case B_PASTE:
+ case B_SELECT_ALL:
+ //case B_MOUSE_WHEEL_CHANGED:
+ case B_UI_SETTINGS_CHANGED:
+ // NetPositive messages
+ case B_NETPOSITIVE_OPEN_URL:
+ case B_NETPOSITIVE_BACK:
+ case B_NETPOSITIVE_FORWARD:
+ case B_NETPOSITIVE_HOME:
+ case B_NETPOSITIVE_RELOAD:
+ case B_NETPOSITIVE_STOP:
+ case B_NETPOSITIVE_DOWN:
+ case B_NETPOSITIVE_UP:
+ // messages for top-level
+ case 'back':
+ case 'forw':
+ case 'stop':
+ case 'relo':
+ case 'home':
+ case 'urlc':
+ case 'urle':
+ case 'sear':
+ case 'menu':
+ case NO_ACTION:
+ case HELP_OPEN_CONTENTS:
+ case HELP_OPEN_GUIDE:
+ case HELP_OPEN_INFORMATION:
+ case HELP_OPEN_ABOUT:
+ case HELP_LAUNCH_INTERACTIVE:
+ case HISTORY_SHOW_LOCAL:
+ case HISTORY_SHOW_GLOBAL:
+ case HOTLIST_ADD_URL:
+ case HOTLIST_SHOW:
+ case COOKIES_SHOW:
+ case COOKIES_DELETE:
+ case BROWSER_PAGE:
+ case BROWSER_PAGE_INFO:
+ case BROWSER_PRINT:
+ case BROWSER_NEW_WINDOW:
+ case BROWSER_VIEW_SOURCE:
+ case BROWSER_OBJECT:
+ case BROWSER_OBJECT_INFO:
+ case BROWSER_OBJECT_RELOAD:
+ case BROWSER_OBJECT_SAVE:
+ case BROWSER_OBJECT_EXPORT_SPRITE:
+ case BROWSER_OBJECT_SAVE_URL_URI:
+ case BROWSER_OBJECT_SAVE_URL_URL:
+ case BROWSER_OBJECT_SAVE_URL_TEXT:
+ case BROWSER_SAVE:
+ case BROWSER_SAVE_COMPLETE:
+ case BROWSER_EXPORT_DRAW:
+ case BROWSER_EXPORT_TEXT:
+ case BROWSER_SAVE_URL_URI:
+ case BROWSER_SAVE_URL_URL:
+ case BROWSER_SAVE_URL_TEXT:
+ case HOTLIST_EXPORT:
+ case HISTORY_EXPORT:
+ case BROWSER_NAVIGATE_HOME:
+ case BROWSER_NAVIGATE_BACK:
+ case BROWSER_NAVIGATE_FORWARD:
+ case BROWSER_NAVIGATE_UP:
+ case BROWSER_NAVIGATE_RELOAD:
+ case BROWSER_NAVIGATE_RELOAD_ALL:
+ case BROWSER_NAVIGATE_STOP:
+ case BROWSER_NAVIGATE_URL:
+ case BROWSER_SCALE_VIEW:
+ case BROWSER_FIND_TEXT:
+ case BROWSER_IMAGES_FOREGROUND:
+ case BROWSER_IMAGES_BACKGROUND:
+ case BROWSER_BUFFER_ANIMS:
+ case BROWSER_BUFFER_ALL:
+ case BROWSER_SAVE_VIEW:
+ case BROWSER_WINDOW_DEFAULT:
+ case BROWSER_WINDOW_STAGGER:
+ case BROWSER_WINDOW_COPY:
+ case BROWSER_WINDOW_RESET:
+ case TREE_NEW_FOLDER:
+ case TREE_NEW_LINK:
+ case TREE_EXPAND_ALL:
+ case TREE_EXPAND_FOLDERS:
+ case TREE_EXPAND_LINKS:
+ case TREE_COLLAPSE_ALL:
+ case TREE_COLLAPSE_FOLDERS:
+ case TREE_COLLAPSE_LINKS:
+ case TREE_SELECTION:
+ case TREE_SELECTION_EDIT:
+ case TREE_SELECTION_LAUNCH:
+ case TREE_SELECTION_DELETE:
+ case TREE_SELECT_ALL:
+ case TREE_CLEAR_SELECTION:
+ case TOOLBAR_BUTTONS:
+ case TOOLBAR_ADDRESS_BAR:
+ case TOOLBAR_THROBBER:
+ case TOOLBAR_EDIT:
+ case CHOICES_SHOW:
+ case APPLICATION_QUIT:
+ Window()->DetachCurrentMessage();
+ nsbeos_pipe_message_top(message, NULL, fGuiWindow->scaffold);
+ break;
+ default:
+ //message->PrintToStream();
+ BView::MessageReceived(message);
+ }
+}
+
+
+void
+NSBrowserFrameView::Draw(BRect updateRect)
+{
+ BMessage *message = NULL;
+ //message = Window()->DetachCurrentMessage();
+ // might be called directly...
+ if (message == NULL)
+ message = new BMessage(_UPDATE_);
+ message->AddRect("rect", updateRect);
+ nsbeos_pipe_message(message, this, fGuiWindow);
+}
+
+
+
+void
+NSBrowserFrameView::FrameResized(float new_width, float new_height)
+{
+ BMessage *message = Window()->DetachCurrentMessage();
+ // discard any other pending resize,
+ // so we don't end up processing them all, the last one matters.
+ atomic_add(&fGuiWindow->pending_resizes, 1);
+ nsbeos_pipe_message(message, this, fGuiWindow);
+ BView::FrameResized(new_width, new_height);
+}
+
+
+void
+NSBrowserFrameView::KeyDown(const char *bytes, int32 numBytes)
+{
+ BMessage *message = Window()->DetachCurrentMessage();
+ nsbeos_pipe_message(message, this, fGuiWindow);
+}
+
+
+void
+NSBrowserFrameView::MouseDown(BPoint where)
+{
+ BMessage *message = Window()->DetachCurrentMessage();
+ BPoint screenWhere;
+ if (message->FindPoint("screen_where", &screenWhere) < B_OK) {
+ screenWhere = ConvertToScreen(where);
+ message->AddPoint("screen_where", screenWhere);
+ }
+ nsbeos_pipe_message(message, this, fGuiWindow);
+}
+
+
+void
+NSBrowserFrameView::MouseUp(BPoint where)
+{
+ //BMessage *message = Window()->DetachCurrentMessage();
+ //nsbeos_pipe_message(message, this, fGuiWindow);
+ BMessage *message = Window()->DetachCurrentMessage();
+ BPoint screenWhere;
+ if (message->FindPoint("screen_where", &screenWhere) < B_OK) {
+ screenWhere = ConvertToScreen(where);
+ message->AddPoint("screen_where", screenWhere);
+ }
+ nsbeos_pipe_message(message, this, fGuiWindow);
+}
+
+
+void
+NSBrowserFrameView::MouseMoved(BPoint where, uint32 transit, const BMessage *msg)
+{
+ if (transit != B_INSIDE_VIEW) {
+ BView::MouseMoved(where, transit, msg);
+ return;
+ }
+ BMessage *message = Window()->DetachCurrentMessage();
+ nsbeos_pipe_message(message, this, fGuiWindow);
+}
+
+
+// #pragma mark - gui_window
+
+struct browser_window *nsbeos_get_browser_window(struct gui_window *g)
+{
+ return g->bw;
+}
+
+nsbeos_scaffolding *nsbeos_get_scaffold(struct gui_window *g)
+{
+ return g->scaffold;
+}
+
+struct browser_window *nsbeos_get_browser_for_gui(struct gui_window *g)
+{
+ return g->bw;
+}
+
+float nsbeos_get_scale_for_gui(struct gui_window *g)
+{
+ return g->scale;
+}
+
+/* Create a gui_window */
+static struct gui_window *gui_window_create(struct browser_window *bw,
+ struct gui_window *existing,
+ gui_window_create_flags flags)
+{
+ struct gui_window *g; /**< what we're creating to return */
+
+ g = (struct gui_window *)malloc(sizeof(*g));
+ if (!g) {
+ beos_warn_user("NoMemory", 0);
+ return 0;
+ }
+
+ LOG("Creating gui window %p for browser window %p", g, bw);
+
+ g->bw = bw;
+ g->mouse.state = 0;
+ g->current_pointer = GUI_POINTER_DEFAULT;
+ g->scale = browser_window_get_scale(bw);
+
+ g->careth = 0;
+ g->pending_resizes = 0;
+
+ /* Attach ourselves to the list (push_top) */
+ if (window_list)
+ window_list->prev = g;
+ g->next = window_list;
+ g->prev = NULL;
+ window_list = g;
+
+ /* Now construct and attach a scaffold */
+ g->scaffold = nsbeos_new_scaffolding(g);
+ if (!g->scaffold)
+ return NULL;
+
+ /* Construct our primary elements */
+ BRect frame(0,0,-1,-1); // will be resized later
+ g->view = new NSBrowserFrameView(frame, g);
+ /* set the default background colour of the drawing area to white. */
+ //g->view->SetViewColor(kWhiteColor);
+ /* NOOO! Since we defer drawing (DetachCurrent()), the white flickers,
+ * besides sometimes text was drawn twice, making it ugly.
+ * Instead we set to transparent here, and implement plot_clg() to
+ * do it just before the rest. This almost removes the flicker. */
+ g->view->SetViewColor(B_TRANSPARENT_COLOR);
+ g->view->SetLowColor(kWhiteColor);
+
+#ifdef B_BEOS_VERSION_DANO
+ /* enable double-buffering on the content view */
+/*
+ XXX: doesn't really work
+ g->view->SetDoubleBuffering(B_UPDATE_INVALIDATED
+ | B_UPDATE_SCROLLED
+ //| B_UPDATE_RESIZED
+ | B_UPDATE_EXPOSED);
+*/
+#endif
+
+
+ g->toplevel = true;
+
+ /* Attach our viewport into the scaffold */
+ nsbeos_attach_toplevel_view(g->scaffold, g->view);
+
+
+ return g;
+}
+
+/* exported interface documented in beos/window.h */
+void nsbeos_dispatch_event(BMessage *message)
+{
+ struct gui_window *gui = NULL;
+ NSBrowserFrameView *view = NULL;
+ struct beos_scaffolding *scaffold = NULL;
+ NSBrowserWindow *window = NULL;
+
+ //message->PrintToStream();
+ if (message->FindPointer("View", (void **)&view) < B_OK)
+ view = NULL;
+ if (message->FindPointer("gui_window", (void **)&gui) < B_OK)
+ gui = NULL;
+ if (message->FindPointer("Window", (void **)&window) < B_OK)
+ window = NULL;
+ if (message->FindPointer("scaffolding", (void **)&scaffold) < B_OK)
+ scaffold = NULL;
+
+ struct gui_window *z;
+ for (z = window_list; z && gui && z != gui; z = z->next)
+ continue;
+
+ struct gui_window *y;
+ for (y = window_list; y && scaffold && y->scaffold != scaffold; y = y->next)
+ continue;
+
+ if (gui && gui != z) {
+ LOG("discarding event for destroyed gui_window");
+ delete message;
+ return;
+ }
+ if (scaffold && (!y || scaffold != y->scaffold)) {
+ LOG("discarding event for destroyed scaffolding");
+ delete message;
+ return;
+ }
+
+ // messages for top-level
+ if (scaffold) {
+ LOG("dispatching to top-level");
+ nsbeos_scaffolding_dispatch_event(scaffold, message);
+ delete message;
+ return;
+ }
+
+ //LOG("processing message");
+ switch (message->what) {
+ case B_QUIT_REQUESTED:
+ // from the BApplication
+ nsbeos_done = true;
+ break;
+ case B_ABOUT_REQUESTED:
+ {
+ if (gui == NULL)
+ gui = window_list;
+ nsbeos_about(gui);
+ break;
+ }
+ case _UPDATE_:
+ if (gui && view)
+ nsbeos_window_expose_event(view, gui, message);
+ break;
+ case B_MOUSE_MOVED:
+ {
+ if (gui == NULL)
+ break;
+
+ BPoint where;
+ int32 mods;
+ // where refers to Window coords !?
+ // check be:view_where first
+ if (message->FindPoint("be:view_where", &where) < B_OK) {
+ if (message->FindPoint("where", &where) < B_OK)
+ break;
+ }
+ if (message->FindInt32("modifiers", &mods) < B_OK)
+ mods = 0;
+
+
+ if (gui->mouse.state & BROWSER_MOUSE_PRESS_1) {
+ /* Start button 1 drag */
+ browser_window_mouse_click(gui->bw, BROWSER_MOUSE_DRAG_1,
+ gui->mouse.pressed_x, gui->mouse.pressed_y);
+ /* Replace PRESS with HOLDING and declare drag in progress */
+ gui->mouse.state ^= (BROWSER_MOUSE_PRESS_1 |
+ BROWSER_MOUSE_HOLDING_1);
+ gui->mouse.state |= BROWSER_MOUSE_DRAG_ON;
+ } else if (gui->mouse.state & BROWSER_MOUSE_PRESS_2) {
+ /* Start button 2 drag */
+ browser_window_mouse_click(gui->bw, BROWSER_MOUSE_DRAG_2,
+ gui->mouse.pressed_x, gui->mouse.pressed_y);
+ /* Replace PRESS with HOLDING and declare drag in progress */
+ gui->mouse.state ^= (BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_HOLDING_2);
+ gui->mouse.state |= BROWSER_MOUSE_DRAG_ON;
+ }
+
+ bool shift = mods & B_SHIFT_KEY;
+ bool ctrl = mods & B_CONTROL_KEY;
+
+ /* Handle modifiers being removed */
+ if (gui->mouse.state & BROWSER_MOUSE_MOD_1 && !shift)
+ gui->mouse.state ^= BROWSER_MOUSE_MOD_1;
+ if (gui->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl)
+ gui->mouse.state ^= BROWSER_MOUSE_MOD_2;
+
+ browser_window_mouse_track(gui->bw, (browser_mouse_state)gui->mouse.state,
+ (int)(where.x / gui->scale),
+ (int)(where.y / gui->scale));
+
+ gui->last_x = (int)where.x;
+ gui->last_y = (int)where.y;
+ break;
+ }
+ case B_MOUSE_DOWN:
+ {
+ if (gui == NULL)
+ break;
+
+ BPoint where;
+ int32 buttons;
+ int32 mods;
+ BPoint screenWhere;
+ if (message->FindPoint("be:view_where", &where) < B_OK) {
+ if (message->FindPoint("where", &where) < B_OK)
+ break;
+ }
+ if (message->FindInt32("buttons", &buttons) < B_OK)
+ break;
+ if (message->FindPoint("screen_where", &screenWhere) < B_OK)
+ break;
+ if (message->FindInt32("modifiers", &mods) < B_OK)
+ mods = 0;
+
+ if (buttons & B_SECONDARY_MOUSE_BUTTON) {
+ /* 2 == right button on BeOS */
+
+ nsbeos_scaffolding_popup_menu(gui->scaffold, screenWhere);
+ break;
+ }
+
+ gui->mouse.state = BROWSER_MOUSE_PRESS_1;
+
+ if (buttons & B_TERTIARY_MOUSE_BUTTON) /* 3 == middle button on BeOS */
+ gui->mouse.state = BROWSER_MOUSE_PRESS_2;
+
+ if (mods & B_SHIFT_KEY)
+ gui->mouse.state |= BROWSER_MOUSE_MOD_1;
+ if (mods & B_CONTROL_KEY)
+ gui->mouse.state |= BROWSER_MOUSE_MOD_2;
+
+ gui->mouse.pressed_x = where.x / gui->scale;
+ gui->mouse.pressed_y = where.y / gui->scale;
+
+ // make sure the view is in focus
+ if (view && view->LockLooper()) {
+ if (!view->IsFocus())
+ view->MakeFocus();
+ view->UnlockLooper();
+ }
+
+ browser_window_mouse_click(gui->bw,
+ (browser_mouse_state)gui->mouse.state,
+ gui->mouse.pressed_x, gui->mouse.pressed_y);
+
+ break;
+ }
+ case B_MOUSE_UP:
+ {
+ if (gui == NULL)
+ break;
+
+ BPoint where;
+ int32 buttons;
+ int32 mods;
+ BPoint screenWhere;
+ if (message->FindPoint("be:view_where", &where) < B_OK) {
+ if (message->FindPoint("where", &where) < B_OK)
+ break;
+ }
+ if (message->FindInt32("buttons", &buttons) < B_OK)
+ break;
+ if (message->FindPoint("screen_where", &screenWhere) < B_OK)
+ break;
+ if (message->FindInt32("modifiers", &mods) < B_OK)
+ mods = 0;
+
+ /* If the mouse state is PRESS then we are waiting for a release to emit
+ * a click event, otherwise just reset the state to nothing*/
+ if (gui->mouse.state & BROWSER_MOUSE_PRESS_1)
+ gui->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1);
+ else if (gui->mouse.state & BROWSER_MOUSE_PRESS_2)
+ gui->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2);
+
+ bool shift = mods & B_SHIFT_KEY;
+ bool ctrl = mods & B_CONTROL_KEY;
+
+ /* Handle modifiers being removed */
+ if (gui->mouse.state & BROWSER_MOUSE_MOD_1 && !shift)
+ gui->mouse.state ^= BROWSER_MOUSE_MOD_1;
+ if (gui->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl)
+ gui->mouse.state ^= BROWSER_MOUSE_MOD_2;
+
+ /*
+ if (view && view->LockLooper()) {
+ view->MakeFocus();
+ view->UnlockLooper();
+ }
+ */
+
+ if (gui->mouse.state & (BROWSER_MOUSE_CLICK_1|BROWSER_MOUSE_CLICK_2))
+ browser_window_mouse_click(gui->bw,
+ (browser_mouse_state)gui->mouse.state,
+ where.x / gui->scale,
+ where.y / gui->scale);
+ else
+ browser_window_mouse_track(gui->bw, (browser_mouse_state)0,
+ where.x, where.y);
+
+ gui->mouse.state = 0;
+
+ break;
+ }
+ case B_KEY_DOWN:
+ if (gui && view)
+ nsbeos_window_keypress_event(view, gui, message);
+ break;
+ case B_VIEW_RESIZED:
+ if (gui && view)
+ nsbeos_window_resize_event(view, gui, message);
+ break;
+ case B_VIEW_MOVED:
+ if (gui && view)
+ nsbeos_window_moved_event(view, gui, message);
+ break;
+ case B_MOUSE_WHEEL_CHANGED:
+ break;
+ case B_UI_SETTINGS_CHANGED:
+ nsbeos_update_system_ui_colors();
+ break;
+ case 'nsLO': // login
+ {
+ nsurl* url;
+ BString realm;
+ BString auth;
+ void* cbpw;
+ nserror (*cb)(bool proceed, void* pw);
+
+ if (message->FindPointer("URL", (void**)&url) < B_OK)
+ break;
+ if (message->FindString("Realm", &realm) < B_OK)
+ break;
+ if (message->FindString("Auth", &auth) < B_OK)
+ break;
+ if (message->FindPointer("callback", (void**)&cb) < B_OK)
+ break;
+ if (message->FindPointer("callback_pw", (void**)&cbpw) < B_OK)
+ break;
+ //printf("login to '%s' with '%s'\n", url.String(), auth.String());
+ urldb_set_auth_details(url, realm.String(), auth.String());
+ cb(true, cbpw);
+ break;
+ }
+ default:
+ break;
+ }
+ delete message;
+}
+
+void nsbeos_window_expose_event(BView *view, gui_window *g, BMessage *message)
+{
+ BRect updateRect;
+ float scale = g->scale;
+ struct rect clip;
+
+ struct redraw_context ctx = { true, true, &nsbeos_plotters };
+
+ assert(g);
+ assert(g->bw);
+
+ struct gui_window *z;
+ for (z = window_list; z && z != g; z = z->next)
+ continue;
+ assert(z);
+ assert(g->view == view);
+
+ // we'll be resizing = reflowing = redrawing everything anyway...
+ if (g->pending_resizes > 1)
+ return;
+
+ if (message->FindRect("rect", &updateRect) < B_OK)
+ return;
+
+ if (browser_window_has_content(g->bw) == false)
+ return;
+
+ if (!view->LockLooper())
+ return;
+ nsbeos_current_gc_set(view);
+
+ if (view->Window())
+ view->Window()->BeginViewTransaction();
+
+ clip.x0 = (int)updateRect.left;
+ clip.y0 = (int)updateRect.top;
+ clip.x1 = (int)updateRect.right + 1;
+ clip.y1 = (int)updateRect.bottom + 1;
+
+ browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
+
+ if (g->careth != 0)
+ nsbeos_plot_caret(g->caretx, g->carety, g->careth);
+
+ if (view->Window())
+ view->Window()->EndViewTransaction();
+
+ // reset clipping just in case
+ view->ConstrainClippingRegion(NULL);
+ nsbeos_current_gc_set(NULL);
+ view->UnlockLooper();
+}
+
+void nsbeos_window_keypress_event(BView *view, gui_window *g, BMessage *event)
+{
+ const char *bytes;
+ char buff[6];
+ int numbytes = 0;
+ uint32 mods;
+ uint32 key;
+ uint32 raw_char;
+ uint32_t nskey;
+ int i;
+
+ if (event->FindInt32("modifiers", (int32 *)&mods) < B_OK)
+ mods = modifiers();
+ if (event->FindInt32("key", (int32 *)&key) < B_OK)
+ key = 0;
+ if (event->FindInt32("raw_char", (int32 *)&raw_char) < B_OK)
+ raw_char = 0;
+ /* check for byte[] first, because C-space gives bytes="" (and byte[0] = '\0') */
+ for (i = 0; i < 5; i++) {
+ buff[i] = '\0';
+ if (event->FindInt8("byte", i, (int8 *)&buff[i]) < B_OK)
+ break;
+ }
+
+ if (i) {
+ bytes = buff;
+ numbytes = i;
+ } else if (event->FindString("bytes", &bytes) < B_OK)
+ bytes = "";
+
+ if (!numbytes)
+ numbytes = strlen(bytes);
+
+ LOG("mods 0x%08lx key %ld raw %ld byte[0] %d", mods, key, raw_char, buff[0]);
+
+ char byte;
+ if (numbytes == 1) {
+ byte = bytes[0];
+ if (mods & B_CONTROL_KEY)
+ byte = (char)raw_char;
+ if (byte >= '!' && byte <= '~')
+ nskey = (uint32_t)byte;
+ else {
+ switch (byte) {
+ case B_BACKSPACE: nskey = NS_KEY_DELETE_LEFT; break;
+ case B_TAB: nskey = NS_KEY_TAB; break;
+ /*case XK_Linefeed: return QKlinefeed;*/
+ case B_ENTER: nskey = (uint32_t)10; break;
+ case B_ESCAPE: nskey = (uint32_t)'\033'; break;
+ case B_SPACE: nskey = (uint32_t)' '; break;
+ case B_DELETE: nskey = NS_KEY_DELETE_RIGHT; break;
+ /*
+ case B_INSERT: nskey = NS_KEYSYM("insert"); break;
+ */
+ case B_HOME: nskey = NS_KEY_LINE_START; break; // XXX ?
+ case B_END: nskey = NS_KEY_LINE_END; break; // XXX ?
+ case B_PAGE_UP: nskey = NS_KEY_PAGE_UP; break;
+ case B_PAGE_DOWN: nskey = NS_KEY_PAGE_DOWN; break;
+ case B_LEFT_ARROW: nskey = NS_KEY_LEFT; break;
+ case B_RIGHT_ARROW: nskey = NS_KEY_RIGHT; break;
+ case B_UP_ARROW: nskey = NS_KEY_UP; break;
+ case B_DOWN_ARROW: nskey = NS_KEY_DOWN; break;
+ /*
+ case B_FUNCTION_KEY:
+ switch (scancode) {
+ case B_F1_KEY: nskey = KEYSYM("f1"); break;
+ case B_F2_KEY: nskey = KEYSYM("f2"); break;
+ case B_F3_KEY: nskey = KEYSYM("f3"); break;
+ case B_F4_KEY: nskey = KEYSYM("f4"); break;
+ case B_F5_KEY: nskey = KEYSYM("f5"); break;
+ case B_F6_KEY: nskey = KEYSYM("f6"); break;
+ case B_F7_KEY: nskey = KEYSYM("f7"); break;
+ case B_F8_KEY: nskey = KEYSYM("f8"); break;
+ case B_F9_KEY: nskey = KEYSYM("f9"); break;
+ case B_F10_KEY: nskey = KEYSYM("f10"); break;
+ case B_F11_KEY: nskey = KEYSYM("f11"); break;
+ case B_F12_KEY: nskey = KEYSYM("f12"); break;
+ case B_PRINT_KEY: nskey = KEYSYM("print"); break;
+ case B_SCROLL_KEY: nskey = KEYSYM("scroll-lock"); break;
+ case B_PAUSE_KEY: nskey = KEYSYM("pause"); break;
+ }
+ */
+ case 0:
+ nskey = (uint32_t)0;
+ default:
+ nskey = (uint32_t)raw_char;
+ /*if (simple_p)
+ nskey = (uint32_t)0;*/
+ break;
+ }
+ }
+ } else {
+ nskey = utf8_to_ucs4(bytes, numbytes);
+ }
+
+ if(browser_window_key_press(g->bw, nskey))
+ return;
+
+ // Remaining events are for scrolling the page around
+ float hdelta = 0.0f, vdelta = 0.0f;
+ g->view->LockLooper();
+ BRect size = g->view->Bounds();
+ switch (byte) {
+ case B_HOME:
+ g->view->ScrollTo(0.0f, 0.0f);
+ break;
+ case B_END:
+ {
+ // TODO
+ break;
+ }
+ case B_PAGE_UP:
+ vdelta = -size.Height();
+ break;
+ case B_PAGE_DOWN:
+ vdelta = size.Height();
+ break;
+ case B_LEFT_ARROW:
+ hdelta = -10;
+ break;
+ case B_RIGHT_ARROW:
+ hdelta = 10;
+ break;
+ case B_UP_ARROW:
+ vdelta = -10;
+ break;
+ case B_DOWN_ARROW:
+ vdelta = 10;
+ break;
+ }
+
+ g->view->ScrollBy(hdelta, vdelta);
+ g->view->UnlockLooper();
+}
+
+
+void nsbeos_window_resize_event(BView *view, gui_window *g, BMessage *event)
+{
+ //CALLED();
+ int32 width;
+ int32 height;
+
+ // drop this event if we have at least 2 resize pending
+ if (atomic_add(&g->pending_resizes, -1) > 1)
+ return;
+
+ if (event->FindInt32("width", &width) < B_OK)
+ width = -1;
+ if (event->FindInt32("height", &height) < B_OK)
+ height = -1;
+ width++;
+ height++;
+
+ browser_window_schedule_reformat(g->bw);
+
+ return;
+}
+
+
+void nsbeos_window_moved_event(BView *view, gui_window *g, BMessage *event)
+{
+ //CALLED();
+
+#warning XXX: Invalidate ?
+ if (!view || !view->LockLooper())
+ return;
+ //view->Invalidate(view->Bounds());
+ view->UnlockLooper();
+
+ return;
+}
+
+
+void nsbeos_reflow_all_windows(void)
+{
+ for (struct gui_window *g = window_list; g; g = g->next) {
+ browser_window_schedule_reformat(g->bw);
+ }
+}
+
+
+
+/**
+ * callback from core to reformat a window.
+ */
+static void beos_window_reformat(struct gui_window *g)
+{
+ if (g == NULL) {
+ return;
+ }
+
+ NSBrowserFrameView *view = g->view;
+ if (view && view->LockLooper()) {
+ BRect bounds = view->Bounds();
+ view->UnlockLooper();
+#warning XXX why - 1 & - 2 !???
+ browser_window_reformat(g->bw,
+ false,
+ bounds.Width() + 1 /* - 2*/,
+ bounds.Height() + 1);
+ }
+}
+
+void nsbeos_window_destroy_browser(struct gui_window *g)
+{
+ browser_window_destroy(g->bw);
+}
+
+static void gui_window_destroy(struct gui_window *g)
+{
+ if (!g)
+ return;
+
+ if (g->prev)
+ g->prev->next = g->next;
+ else
+ window_list = g->next;
+
+ if (g->next)
+ g->next->prev = g->prev;
+
+
+ LOG("Destroying gui_window %p", g);
+ assert(g != NULL);
+ assert(g->bw != NULL);
+ LOG(" Scaffolding: %p", g->scaffold);
+
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ BLooper *looper = g->view->Looper();
+ /* If we're a top-level gui_window, destroy our scaffold */
+ if (g->toplevel) {
+ g->view->RemoveSelf();
+ delete g->view;
+ nsbeos_scaffolding_destroy(g->scaffold);
+ } else {
+ g->view->RemoveSelf();
+ delete g->view;
+ looper->Unlock();
+ }
+ //XXX
+ //looper->Unlock();
+
+
+ free(g);
+
+}
+
+void nsbeos_redraw_caret(struct gui_window *g)
+{
+ if (g->careth == 0)
+ return;
+
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ nsbeos_current_gc_set(g->view);
+
+ g->view->Invalidate(BRect(g->caretx, g->carety,
+ g->caretx, g->carety + g->careth));
+
+ nsbeos_current_gc_set(NULL);
+ g->view->UnlockLooper();
+}
+
+static void gui_window_redraw_window(struct gui_window *g)
+{
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ nsbeos_current_gc_set(g->view);
+
+ g->view->Invalidate();
+
+ nsbeos_current_gc_set(NULL);
+ g->view->UnlockLooper();
+}
+
+static void gui_window_update_box(struct gui_window *g, const struct rect *rect)
+{
+ if (browser_window_has_content(g->bw) == false)
+ return;
+
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ nsbeos_current_gc_set(g->view);
+
+//XXX +1 ??
+ g->view->Invalidate(BRect(rect->x0, rect->y0,
+ rect->x1 - 1, rect->y1 - 1));
+
+ nsbeos_current_gc_set(NULL);
+ g->view->UnlockLooper();
+}
+
+static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
+{
+ //CALLED();
+ if (g->view == NULL)
+ return false;
+ if (!g->view->LockLooper())
+ return false;
+
+#warning XXX: report to view frame ?
+ if (g->view->ScrollBar(B_HORIZONTAL))
+ *sx = (int)g->view->ScrollBar(B_HORIZONTAL)->Value();
+ if (g->view->ScrollBar(B_VERTICAL))
+ *sy = (int)g->view->ScrollBar(B_VERTICAL)->Value();
+
+ g->view->UnlockLooper();
+ return true;
+}
+
+static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
+{
+ //CALLED();
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+#warning XXX: report to view frame ?
+ if (g->view->ScrollBar(B_HORIZONTAL))
+ g->view->ScrollBar(B_HORIZONTAL)->SetValue(sx);
+ if (g->view->ScrollBar(B_VERTICAL))
+ g->view->ScrollBar(B_VERTICAL)->SetValue(sy);
+
+ g->view->UnlockLooper();
+}
+
+
+static void gui_window_update_extent(struct gui_window *g)
+{
+ nserror err;
+ //CALLED();
+ if (browser_window_has_content(g->bw) == false)
+ return;
+
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ int x_max, y_max;
+
+ err = browser_window_get_extents(g->bw, true, &x_max, &y_max);
+ if (err != NSERROR_OK)
+ return;
+
+ float x_prop = g->view->Bounds().Width() / x_max;
+ float y_prop = g->view->Bounds().Height() / y_max;
+ x_max -= g->view->Bounds().Width() + 1;
+ y_max -= g->view->Bounds().Height() + 1;
+
+ LOG("x_max = %d y_max = %d x_prop = %f y_prop = %f\n",
+ x_max, y_max, x_prop, y_prop);
+
+ if (g->view->ScrollBar(B_HORIZONTAL)) {
+ g->view->ScrollBar(B_HORIZONTAL)->SetRange(0, x_max);
+ g->view->ScrollBar(B_HORIZONTAL)->SetProportion(x_prop);
+ g->view->ScrollBar(B_HORIZONTAL)->SetSteps(10, 50);
+ }
+ if (g->view->ScrollBar(B_VERTICAL)) {
+ g->view->ScrollBar(B_VERTICAL)->SetRange(0, y_max);
+ g->view->ScrollBar(B_VERTICAL)->SetProportion(y_prop);
+ g->view->ScrollBar(B_VERTICAL)->SetSteps(10, 50);
+ }
+
+
+ g->view->UnlockLooper();
+}
+
+/* some cursors like those in Firefox */
+// XXX: move to separate file or resource ?
+
+const uint8 kLinkCursorBits[] = {
+ 16, /* cursor size */
+ 1, /* bits per pixel */
+ 2, /* vertical hot spot */
+ 2, /* horizontal hot spot */
+
+ /* data */
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x24, 0x00, 0x24, 0x00, 0x13, 0xe0, 0x12, 0x5c, 0x09, 0x2a,
+ 0x08, 0x01, 0x3c, 0x21, 0x4c, 0x71, 0x42, 0x71, 0x30, 0xf9, 0x0c, 0xf9, 0x02, 0x02, 0x01, 0x00,
+
+ /* mask */
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x1f, 0xe0, 0x1f, 0xfc, 0x0f, 0xfe,
+ 0x0f, 0xff, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x3f, 0xff, 0x0f, 0xff, 0x03, 0xfc, 0x01, 0xe0
+};
+
+const uint8 kWatchCursorBits[] = {
+ 16, /* cursor size */
+ 1, /* bits per pixel */
+ 0, /* vertical hot spot */
+ 1, /* horizontal hot spot */
+
+ /* data */
+ 0x70, 0x00, 0x48, 0x00, 0x48, 0x00, 0x27, 0xc0, 0x24, 0xb8, 0x12, 0x54, 0x10, 0x02, 0x78, 0x02,
+ 0x98, 0x02, 0x84, 0x02, 0x60, 0x3a, 0x18, 0x46, 0x04, 0x8a, 0x02, 0x92, 0x01, 0x82, 0x00, 0x45,
+
+ /* mask */
+ 0x70, 0x00, 0x78, 0x00, 0x78, 0x00, 0x3f, 0xc0, 0x3f, 0xf8, 0x1f, 0xfc, 0x1f, 0xfe, 0x7f, 0xfe,
+ 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x07, 0xfe, 0x03, 0xfe, 0x01, 0xfe, 0x00, 0x7f
+};
+
+const uint8 kWatch2CursorBits[] = {
+ 16, /* cursor size */
+ 1, /* bits per pixel */
+ 0, /* vertical hot spot */
+ 1, /* horizontal hot spot */
+
+ /* data */
+ 0x70, 0x00, 0x48, 0x00, 0x48, 0x00, 0x27, 0xc0, 0x24, 0xb8, 0x12, 0x54, 0x10, 0x02, 0x78, 0x02,
+ 0x98, 0x02, 0x84, 0x02, 0x60, 0x3a, 0x18, 0x46, 0x04, 0xa2, 0x02, 0x92, 0x01, 0xa2, 0x00, 0x45,
+
+ /* mask */
+ 0x70, 0x00, 0x78, 0x00, 0x78, 0x00, 0x3f, 0xc0, 0x3f, 0xf8, 0x1f, 0xfc, 0x1f, 0xfe, 0x7f, 0xfe,
+ 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x07, 0xfe, 0x03, 0xfe, 0x01, 0xfe, 0x00, 0x7f
+};
+
+
+static void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
+{
+ BCursor *cursor = NULL;
+ bool allocated = false;
+
+ if (g->current_pointer == shape)
+ return;
+
+ g->current_pointer = shape;
+
+ switch (shape) {
+ case GUI_POINTER_POINT:
+ cursor = new BCursor(kLinkCursorBits);
+ allocated = true;
+ break;
+ case GUI_POINTER_CARET:
+ cursor = (BCursor *)B_CURSOR_I_BEAM;
+ break;
+ case GUI_POINTER_WAIT:
+ cursor = new BCursor(kWatchCursorBits);
+ allocated = true;
+ break;
+ case GUI_POINTER_PROGRESS:
+ cursor = new BCursor(kWatch2CursorBits);
+ allocated = true;
+ break;
+ default:
+ cursor = (BCursor *)B_CURSOR_SYSTEM_DEFAULT;
+ allocated = false;
+ }
+
+ if (g->view && g->view->LockLooper()) {
+ g->view->SetViewCursor(cursor);
+ g->view->UnlockLooper();
+ }
+
+ if (allocated)
+ delete cursor;
+}
+
+static void gui_window_place_caret(struct gui_window *g, int x, int y, int height,
+ const struct rect *clip)
+{
+ //CALLED();
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ nsbeos_redraw_caret(g);
+
+ g->caretx = x;
+ g->carety = y + 1;
+ g->careth = height - 2;
+
+ nsbeos_redraw_caret(g);
+ g->view->MakeFocus();
+
+ g->view->UnlockLooper();
+}
+
+static void gui_window_remove_caret(struct gui_window *g)
+{
+ int oh = g->careth;
+
+ if (oh == 0)
+ return;
+
+ g->careth = 0;
+
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ nsbeos_current_gc_set(g->view);
+
+ g->view->Invalidate(BRect(g->caretx, g->carety, g->caretx, g->carety + oh));
+
+ nsbeos_current_gc_set(NULL);
+ g->view->UnlockLooper();
+}
+
+static void gui_window_new_content(struct gui_window *g)
+{
+ if (!g->toplevel)
+ return;
+
+ if (g->view == NULL)
+ return;
+ if (!g->view->LockLooper())
+ return;
+
+ // scroll back to top
+ g->view->ScrollTo(0,0);
+
+ g->view->UnlockLooper();
+}
+
+static void gui_start_selection(struct gui_window *g)
+{
+ if (!g->view->LockLooper())
+ return;
+
+ g->view->MakeFocus();
+
+ g->view->UnlockLooper();
+}
+
+static void gui_get_clipboard(char **buffer, size_t *length)
+{
+ BMessage *clip;
+ *length = 0;
+ *buffer = NULL;
+
+ if (be_clipboard->Lock()) {
+ clip = be_clipboard->Data();
+ if (clip) {
+ const char *text;
+ ssize_t textlen;
+ if (clip->FindData("text/plain", B_MIME_TYPE,
+ (const void **)&text, &textlen) >= B_OK) {
+ *buffer = (char *)malloc(textlen);
+ *length = textlen;
+ memcpy(*buffer, text, textlen);
+ }
+ }
+ be_clipboard->Unlock();
+ }
+}
+
+static void gui_set_clipboard(const char *buffer, size_t length,
+ nsclipboard_styles styles[], int n_styles)
+{
+ BMessage *clip;
+
+ if (be_clipboard->Lock()) {
+ be_clipboard->Clear();
+ clip = be_clipboard->Data();
+ if (clip) {
+ clip->AddData("text/plain", B_MIME_TYPE, buffer, length);
+
+ int arraySize = sizeof(text_run_array) +
+ n_styles * sizeof(text_run);
+ text_run_array *array = (text_run_array *)malloc(arraySize);
+ array->count = n_styles;
+ for (int i = 0; i < n_styles; i++) {
+ BFont font;
+ nsbeos_style_to_font(font, &styles[i].style);
+ array->runs[i].offset = styles[i].start;
+ array->runs[i].font = font;
+ array->runs[i].color =
+ nsbeos_rgb_colour(styles[i].style.foreground);
+ }
+ clip->AddData("application/x-vnd.Be-text_run_array", B_MIME_TYPE,
+ array, arraySize);
+ free(array);
+ be_clipboard->Commit();
+ }
+ be_clipboard->Unlock();
+ }
+}
+
+static struct gui_clipboard_table clipboard_table = {
+ gui_get_clipboard,
+ gui_set_clipboard,
+};
+
+struct gui_clipboard_table *beos_clipboard_table = &clipboard_table;
+
+static void gui_window_get_dimensions(struct gui_window *g, int *width, int *height,
+ bool scaled)
+{
+ if (g->view && g->view->LockLooper()) {
+ *width = g->view->Bounds().Width() + 1;
+ *height = g->view->Bounds().Height() + 1;
+ g->view->UnlockLooper();
+ }
+
+ if (scaled) {
+ *width /= g->scale;
+ *height /= g->scale;
+ }
+}
+
+static struct gui_window_table window_table = {
+ gui_window_create,
+ gui_window_destroy,
+ gui_window_redraw_window,
+ gui_window_update_box,
+ gui_window_get_scroll,
+ gui_window_set_scroll,
+ gui_window_get_dimensions,
+ gui_window_update_extent,
+ beos_window_reformat,
+
+ /* from scaffold */
+ gui_window_set_title,
+ gui_window_set_url,
+ gui_window_set_icon,
+ gui_window_set_status,
+ gui_window_set_pointer,
+ gui_window_place_caret,
+ gui_window_remove_caret,
+ gui_window_start_throbber,
+ gui_window_stop_throbber,
+ NULL, //drag_start
+ NULL, //save_link
+ NULL, //scroll_visible
+ NULL, //scroll_start
+ gui_window_new_content,
+ NULL, //create_form_select_menu
+ NULL, //file_gadget_open
+ NULL, //drag_save_object
+ NULL, //drag_save_selection
+ gui_start_selection
+};
+
+struct gui_window_table *beos_window_table = &window_table;
diff --git a/frontends/beos/window.h b/frontends/beos/window.h
new file mode 100644
index 000000000..928acca22
--- /dev/null
+++ b/frontends/beos/window.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_BEOS_WINDOW_H
+#define NETSURF_BEOS_WINDOW_H 1
+
+#include <View.h>
+#include <Window.h>
+#include <NetPositive.h>
+
+extern struct gui_window_table *beos_window_table;
+extern struct gui_clipboard_table *beos_clipboard_table;
+
+struct gui_window;
+struct browser_window;
+struct beos_scaffolding;
+
+class NSBrowserFrameView : public BView {
+public:
+ NSBrowserFrameView(BRect frame, struct gui_window *gui);
+ virtual ~NSBrowserFrameView();
+
+ virtual void MessageReceived(BMessage *message);
+ virtual void Draw(BRect updateRect);
+
+ //virtual void FrameMoved(BPoint new_location);
+ virtual void FrameResized(float new_width, float new_height);
+
+ virtual void KeyDown(const char *bytes, int32 numBytes);
+ virtual void MouseDown(BPoint where);
+ virtual void MouseUp(BPoint where);
+ virtual void MouseMoved(BPoint where, uint32 transit, const BMessage *msg);
+
+private:
+ struct gui_window *fGuiWindow;
+};
+
+/**
+ * Process beos messages into browser operations.
+ *
+ * \param message The beos message to process.
+ */
+void nsbeos_dispatch_event(BMessage *message);
+
+/**
+ * Cause all windows to be reflowed.
+ */
+void nsbeos_reflow_all_windows(void);
+
+/**
+ * Get containing scaffold of a beos gui window
+ *
+ * \param g gui window to find scaffold of.
+ * \return The containing scaffold.
+ */
+struct beos_scaffolding *nsbeos_get_scaffold(struct gui_window *g);
+
+struct browser_window *nsbeos_get_browser_for_gui(struct gui_window *g);
+
+float nsbeos_get_scale_for_gui(struct gui_window *g);
+
+int nsbeos_gui_window_update_targets(struct gui_window *g);
+
+void nsbeos_window_destroy_browser(struct gui_window *g);
+
+struct browser_window *nsbeos_get_browser_window(struct gui_window *g);
+
+#endif /* NETSURF_BEOS_WINDOW_H */