netsurf/beos/beos_gui.cpp
François Revel 982dc9e128 Fix BeOS build:
- struct content -> hlcache_handle
- login window (though it won't work yet as the message isn't handled, and since we don't have the window pointer anymore we can't add the alert as subset of the window...),
- rsrc fetcher,
- netsurf_init() args (but the replicant is still broken due to this),
- export the realpath() hack as it's needed elsewhere too.

svn path=/trunk/netsurf/; revision=10677
2010-08-02 23:35:35 +00:00

1234 lines
29 KiB
C++

/*
* 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 <Roster.h>
#include <String.h>
extern "C" {
#include <hubbub/hubbub.h>
#include "content/content.h"
#include "content/content_protected.h"
#include "content/fetch.h"
#include "content/fetchers/fetch_curl.h"
#include "content/urldb.h"
#include "desktop/401login.h"
#include "desktop/browser.h"
#include "desktop/cookies.h"
#include "desktop/gui.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "render/box.h"
#include "render/form.h"
#include "render/html.h"
#include "utils/filename.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utf8.h"
#include "utils/utils.h"
}
#include "beos/beos_gui.h"
#include "beos/beos_options.h"
//#include "beos/beos_completion.h"
#include "beos/beos_window.h"
#include "beos/options.h"
#include "beos/beos_throbber.h"
#include "beos/beos_history.h"
#include "beos/beos_filetype.h"
//#include "beos/beos_download.h"
#include "beos/beos_schedule.h"
#include "beos/beos_fetch_rsrc.h"
#include "beos/beos_scaffolding.h"
static void *myrealloc(void *ptr, size_t len, void *pw);
void gui_init(int argc, char** argv);
/* Where to search for shared resources. Must have trailing / */
#define RESPATH "/boot/apps/netsurf/res/"
//TODO: use resources
// enable using resources instead of files
#define USE_RESOURCES 1
bool gui_in_multitask = false;
bool replicated = false; /**< if we are running as a replicant */
char *default_stylesheet_url;
char *quirks_stylesheet_url;
char *adblock_stylesheet_url;
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 beosWidget *select_menu;
static struct browser_window *select_menu_bw;
static struct form_control *select_menu_control;
static thread_id sBAppThreadID;
static BMessage *gFirstRefsReceived = NULL;
static int sEventPipe[2];
#if 0 /* GTK */
static void nsbeos_create_ssl_verify_window(struct browser_window *bw,
hlcache_handle *c, const struct ssl_cert_info *certs,
unsigned long num);
static void nsbeos_ssl_accept(BButton *w, gpointer data);
static void nsbeos_ssl_reject(BButton *w, gpointer data);
static void nsbeos_select_menu_clicked(BCheckMenuItem *checkmenuitem,
gpointer user_data);
#endif
// #pragma mark - class NSBrowserFrameView
NSBrowserApplication::NSBrowserApplication()
: BApplication("application/x-vnd.NetSurf")
{
}
NSBrowserApplication::~NSBrowserApplication()
{
}
void
NSBrowserApplication::MessageReceived(BMessage *message)
{
switch (message->what) {
case B_REFS_RECEIVED:
// 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 '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)
{
CALLED();
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)
{
CALLED();
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
// XXX doesn't work
#if 0
static char *generate_default_css()
{
BString text;
rgb_color colBg = { 255, 255, 255, 255 };
rgb_color colFg = { 0, 0, 0, 255 };
rgb_color colControlBg = { 255, 255, 255, 255 };
rgb_color colControlFg = { 0, 0, 0, 255 };
const char *url = "file://beosdefault.css";
text << "/*\n";
text << " * This file is part of NetSurf, http://netsurf-browser.org/\n";
text << " */\n";
text << "\n";
text << "/* Load base stylesheet. */\n";
text << "\n";
text << "@import \"default.css\";\n";
text << "\n";
text << "/* Apply BeOS specific rules. */\n";
text << "\n";
text << "\n";
text << "\n";
text << "\n";
text << "input { font-size: 95%; border: medium inset #ddd; }\n";
text << "input[type=button], input[type=reset], input[type=submit], button {\n";
text << " background-color: #ddd; border: medium outset #ddd; }\n";
text << "input[type=checkbox], input[type=radio] { font-size: 105%; }\n";
text << "input[type=file] { background-color: #ddd; border: medium inset #ddd; }\n";
text << "\n";
text << "select { background-color: #ddd; border: medium inset #ddd; font-size: 95%; }\n";
text << "select:after { border-left:4px ridge #ddd; }\n";
text << "\n";
text << "textarea { font-size: 95%; border: medium inset #ddd; }\n";
struct content *c;
c = content_create(url);
if (c == NULL)
return NULL;
const char *params[] = { 0 };
if (!content_set_type(c, CONTENT_CSS, "text/css", params, NULL))
return NULL;
if (!content_process_data(c, text.String(), text.Length()))
return NULL;
content_set_done(c);
return strdup(url);
}
#endif
/* 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.
*
* \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 buf
*
* Search order is: ~/config/settings/NetSurf/, ~/.netsurf/, $NETSURFRES/
* (where NETSURFRES is an environment variable), and finally the path
* specified by the #define at the top of this file.
*/
static char *find_resource(char *buf, const char *filename, const char *def)
{
CALLED();
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;
}
strcpy(t, RESPATH);
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);
realpath(t, buf);
} else if (def[0] == '~') {
snprintf(t, PATH_MAX, "%s%s", getenv("HOME"), def + 1);
realpath(t, buf);
} else {
realpath(def, buf);
}
return buf;
}
/**
* Check that ~/.netsurf/ exists, and if it doesn't, create it.
*/
static void check_homedir(void)
{
CALLED();
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 void gui_init2(int argc, char** argv)
{
CALLED();
const char *addr = NETSURF_HOMEPAGE;
if (option_homepage_url != NULL && option_homepage_url[0] != '\0')
addr = option_homepage_url;
if (argc > 1) addr = argv[1];
if (gFirstRefsReceived) addr = NULL;
browser_window_create(addr, 0, 0, true, false);
if (gFirstRefsReceived) {
// resend the refs we got before having a window to send them to
be_app_messenger.SendMessage(gFirstRefsReceived);
delete gFirstRefsReceived;
gFirstRefsReceived = NULL;
}
}
/** Normal entry point from OS */
int main(int argc, char** argv)
{
char buf[PATH_MAX];
setbuf(stderr, NULL);
BPath options;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &options, true) == B_OK) {
options.Append("x-vnd.NetSurf");
}
find_resource(buf, "messages", "./beos/res/messages");
LOG(("Using '%s' as Messages file", buf));
//messages_load(buf);
/* initialise netsurf */
netsurf_init(&argc, &argv, options.Path(), buf);
gui_init(argc, argv);
gui_init2(argc, argv);
netsurf_main_loop();
netsurf_exit();
return 0;
}
void gui_init(int argc, char** argv)
{
char buf[PATH_MAX];
CALLED();
if (pipe(sEventPipe) < 0)
return;
if (!replicated) {
new NSBrowserApplication;
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;
}
fetch_rsrc_register();
check_homedir();
// make sure the cache dir exists
create_directory(TEMP_FILENAME_PREFIX, 0600);
//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" STROF(n) ".png";
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 0
find_resource(buf, "throbber.gif", "./beos/res/throbber.gif");
nsbeos_throbber_initialise_from_gif(buf);
#endif
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);
options_read(buf);
/* check what the font settings are, setting them to a default font
* if they're not set - stops Pango whinging
*/
#define SETFONTDEFAULT(x,y) (x) = ((x) != NULL) ? (x) : 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(option_font_sans, family);
SETFONTDEFAULT(option_font_serif, family);
SETFONTDEFAULT(option_font_mono, family);
SETFONTDEFAULT(option_font_cursive, family);
SETFONTDEFAULT(option_font_fantasy, family);
*/
#ifdef __HAIKU__
SETFONTDEFAULT(option_font_sans, "DejaVu Sans");
SETFONTDEFAULT(option_font_serif, "DejaVu Serif");
SETFONTDEFAULT(option_font_mono, "DejaVu Mono");
SETFONTDEFAULT(option_font_cursive, "DejaVu Sans");
SETFONTDEFAULT(option_font_fantasy, "DejaVu Sans");
#else
SETFONTDEFAULT(option_font_sans, "Bitstream Vera Sans");
SETFONTDEFAULT(option_font_serif, "Bitstream Vera Serif");
SETFONTDEFAULT(option_font_mono, "Bitstream Vera Sans Mono");
SETFONTDEFAULT(option_font_cursive, "Bitstream Vera Serif");
SETFONTDEFAULT(option_font_fantasy, "Bitstream Vera Serif");
#if 0
SETFONTDEFAULT(option_font_sans, "Swis721 BT");
SETFONTDEFAULT(option_font_serif, "Dutch801 Rm BT");
//SETFONTDEFAULT(option_font_mono, "Monospac821 BT");
SETFONTDEFAULT(option_font_mono, "Courier10 BT");
SETFONTDEFAULT(option_font_cursive, "Swis721 BT");
SETFONTDEFAULT(option_font_fantasy, "Swis721 BT");
#endif
#endif
nsbeos_options_init();
if (!option_cookie_file) {
find_resource(buf, "Cookies", "%/Cookies");
LOG(("Using '%s' as Cookies file", buf));
option_cookie_file = strdup(buf);
}
if (!option_cookie_jar) {
find_resource(buf, "Cookies", "%/Cookies");
LOG(("Using '%s' as Cookie Jar file", buf));
option_cookie_jar = strdup(buf);
}
if (!option_cookie_file || !option_cookie_jar)
die("Failed initialising cookie options");
if (!option_url_file) {
find_resource(buf, "URLs", "%/URLs");
LOG(("Using '%s' as URL file", buf));
option_url_file = strdup(buf);
}
if (!option_ca_path) {
find_resource(buf, "certs", "/etc/ssl/certs");
LOG(("Using '%s' as certificate path", buf));
option_ca_path = strdup(buf);
}
//find_resource(buf, "mime.types", "/etc/mime.types");
beos_fetch_filetype_init();
/* set up stylesheet urls */
#ifdef USE_RESOURCES
default_stylesheet_url = strdup("rsrc:/beosdefault.css,text/css");
#else
find_resource(buf, "beosdefault.css", "./beos/res/beosdefault.css");
default_stylesheet_url = path_to_url(buf);
#endif
//default_stylesheet_url = generate_default_css();
LOG(("Using '%s' as Default CSS URL", default_stylesheet_url));
#ifdef USE_RESOURCES
quirks_stylesheet_url = strdup("rsrc:/quirks.css,text/css");
#else
find_resource(buf, "quirks.css", "./beos/res/quirks.css");
default_stylesheet_url = path_to_url(buf);
#endif
#ifdef USE_RESOURCES
adblock_stylesheet_url = strdup("rsrc:/adblock.css,text/css");
#else
find_resource(buf, "adblock.css", "./beos/res/adblock.css");
adblock_stylesheet_url = path_to_url(buf);
#endif
LOG(("Using '%s' as AdBlock CSS URL", adblock_stylesheet_url));
find_resource(buf, "Aliases", "./beos/res/Aliases");
LOG(("Using '%s' as aliases file", buf));
if(hubbub_initialise(buf,myrealloc,NULL) != HUBBUB_OK)
{
die(messages_get("NoMemory"));
}
urldb_load(option_url_file);
urldb_load_cookies(option_cookie_file);
nsbeos_history_init();
//nsbeos_download_initialise();
if (!replicated)
be_app->Unlock();
#if 0 /* GTK */
wndAbout = beos_WINDOW(glade_xml_get_widget(gladeWindows, "wndAbout"));
beos_label_set_text(beos_LABEL(
glade_xml_get_widget(gladeWindows, "labelVersion")),
netsurf_version);
beos_image_set_from_file(beos_IMAGE(
glade_xml_get_widget(gladeWindows, "imageLogo")),
find_resource(buf, "netsurf-logo.png", "netsurf-logo.png"));
fontdesc = pango_font_description_from_string("Monospace 8");
beos_widget_modify_font(beos_WIDGET(
glade_xml_get_widget(gladeWindows, "textviewGPL")), fontdesc);
wndWarning = beos_WINDOW(glade_xml_get_widget(gladeWindows, "wndWarning"));
wndOpenFile = beos_DIALOG(glade_xml_get_widget(gladeWindows, "wndOpenFile"));
#endif
}
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);
int len = write(sEventPipe[1], &message, sizeof(void *));
//LOG(("nsbeos_pipe_message: %d written", len));
//printf("nsbeos_pipe_message: %d written\n", len);
}
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);
int len = write(sEventPipe[1], &message, sizeof(void *));
//LOG(("nsbeos_pipe_message: %d written", len));
//printf("nsbeos_pipe_message: %d written\n", len);
}
void gui_poll(bool active)
{
CALLED();
CURLMcode code;
fd_set read_fd_set, write_fd_set, exc_fd_set;
int max_fd = 0;
struct timeval timeout;
unsigned int fd_count = 0;
bool block = true;
if (browser_reformat_pending)
block = false;
FD_ZERO(&read_fd_set);
FD_ZERO(&write_fd_set);
FD_ZERO(&exc_fd_set);
if (active) {
fetch_poll();
code = curl_multi_fdset(fetch_curl_multi,
&read_fd_set,
&write_fd_set,
&exc_fd_set,
&max_fd);
assert(code == CURLM_OK);
}
// our own event pipe
FD_SET(sEventPipe[0], &read_fd_set);
max_fd = MAX(max_fd, sEventPipe[0] + 1);
bigtime_t next_schedule = earliest_callback_timeout - system_time();
if (!block)
next_schedule = 0LL; // now
if (block && earliest_callback_timeout != B_INFINITE_TIMEOUT)
block = false;
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,
block ? NULL : &timeout);
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 *))
nsbeos_dispatch_event(message);
}
schedule_run();
if (browser_reformat_pending)
nsbeos_window_process_reformats();
}
void gui_multitask(void)
{
gui_in_multitask = true;
#if 0 /* GTK */
while (beos_events_pending())
beos_main_iteration();
#endif
gui_in_multitask = false;
}
void gui_quit(void)
{
CALLED();
urldb_save_cookies(option_cookie_jar);
urldb_save(option_url_file);
hubbub_finalise(myrealloc,NULL);
//options_save_tree(hotlist,option_hotlist_file,messages_get("TreeHotlist"));
free(default_stylesheet_url);
free(quirks_stylesheet_url);
free(adblock_stylesheet_url);
free(option_cookie_file);
free(option_cookie_jar);
beos_fetch_filetype_fin();
fetch_rsrc_unregister();
}
struct gui_download_window *gui_download_window_create(download_context *ctx,
struct gui_window *gui)
{
return NULL;
}
nserror gui_download_window_data(struct gui_download_window *dw,
const char *data, unsigned int size)
{
return NSERROR_OK;
}
void gui_download_window_error(struct gui_download_window *dw,
const char *error_msg)
{
}
void gui_download_window_done(struct gui_download_window *dw)
{
}
#if 0 /* GTK */
static void nsbeos_select_menu_clicked(BCheckMenuItem *checkmenuitem,
gpointer user_data)
{
form_select_process_selection(select_menu_bw->current_content,
select_menu_control, (intptr_t)user_data);
}
#endif
void gui_create_form_select_menu(struct browser_window *bw,
struct form_control *control)
{
CALLED();
#if 0 /* GTK */
intptr_t i;
struct form_option *option;
beosWidget *menu_item;
/* control->data.select.multiple is true if multiple selections
* are allowable. We ignore this, as the core handles it for us.
* Yay. \o/
*/
if (select_menu != NULL)
beos_widget_destroy(select_menu);
select_menu = beos_menu_new();
select_menu_bw = bw;
select_menu_control = control;
for (i = 0, option = control->data.select.items; option;
i++, option = option->next) {
menu_item = beos_check_menu_item_new_with_label(option->text);
if (option->selected)
beos_check_menu_item_set_active(
beos_CHECK_MENU_ITEM(menu_item), TRUE);
g_signal_connect(menu_item, "toggled",
G_CALLBACK(nsbeos_select_menu_clicked), (gpointer)i);
beos_menu_shell_append(beos_MENU_SHELL(select_menu), menu_item);
}
beos_widget_show_all(select_menu);
beos_menu_popup(beos_MENU(select_menu), NULL, NULL, NULL,
NULL /* data */, 0, beos_get_current_event_time());
#endif
}
void
gui_window_save_link(struct gui_window *g, const char *url, const char *title)
{
}
/**
* Send the source of a content to a text editor.
*/
void nsbeos_gui_view_source(struct hlcache_handle *content, struct selection *selection)
{
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) {
warn_user("MiscError", "No document source");
return;
}
/* try to load local files directly. */
temp_name = url_to_path(content_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) {
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) {
warn_user("IOError", strerror(err));
return;
}
err = file.Write(source, size);
if (err < B_OK) {
warn_user("IOError", strerror(err));
return;
}
const char *mime = content_get_mime_type(content);
if (mime)
file.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0LL,
mime, strlen(mime) + 1);
}
entry_ref ref;
if (get_ref_for_path(path.Path(), &ref) < B_OK)
return;
BMessage m(B_REFS_RECEIVED);
m.AddRef("refs", &ref);
#if 0
if (selection && selection->defined) {
int32 line = -1;
if (content_get_type(content) == CONTENT_HTML) {
// XXX: use selection, find line in source code
}
if (content_get_type(content) == CONTENT_TEXTPLAIN) {
line = MAKELINE_FROM_IDX(start_idx);
}
// not CSS!
if (line > -1)
message.AddInt32("be:line", line);
}
#endif
// 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.
*/
void gui_launch_url(const char *url)
{
status_t status;
// try to open it as an URI
BString mimeType = "application/x-vnd.Be.URL.";
BString arg(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;
char *args[2] = { (char *)url, NULL };
status = be_roster->Launch(mimeType.String(), 1, args);
if (status < B_OK)
warn_user("Cannot launch url", strerror(status));
}
bool gui_search_term_highlighted(struct gui_window *g,
unsigned start_offset, unsigned end_offset,
unsigned *start_idx, unsigned *end_idx)
{
return false;
}
/**
* Display a warning for a serious problem (eg memory exhaustion).
*
* \param warning message key for warning message
* \param detail additional message, or 0
*/
void 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;
#if 0
alert = new BAlert("NetSurf Warning", text.String(), "Ok", NULL, NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->Go();
#else
alert = new BAlert("NetSurf Warning", text.String(), "Debug", "Ok", NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
if (alert->Go() < 1)
debugger("warn_user");
#endif
}
void die(const char * const error)
{
fprintf(stderr, "%s", error);
BAlert *alert;
BString text("Cannot continue:\n");
text << error;
#if 0
alert = new BAlert("NetSurf Error", text.String(), "Ok", NULL, NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT);
alert->Go();
#else
alert = new BAlert("NetSurf Error", text.String(), "Debug", "Ok", NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT);
if (alert->Go() < 1)
debugger("die");
#endif
exit(EXIT_FAILURE);
}
void hotlist_visited(hlcache_handle *content)
{
}
void gui_cert_verify(const char *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
CALLED();
#if 0 /* GTK */
nsbeos_create_ssl_verify_window(bw, c, certs, num);
#endif
}
static void nsbeos_create_ssl_verify_window(struct browser_window *bw,
hlcache_handle *c, const struct ssl_cert_info *certs,
unsigned long num)
{
CALLED();
#if 0 /* GTK */
GladeXML *x = glade_xml_new(glade_file_location, NULL, NULL);
beosWindow *wnd = beos_WINDOW(glade_xml_get_widget(x, "wndSSLProblem"));
beosButton *accept, *reject;
void **session = calloc(sizeof(void *), 4);
session[0] = bw;
session[1] = strdup(c->url);
session[2] = x;
session[3] = wnd;
accept = beos_BUTTON(glade_xml_get_widget(x, "sslaccept"));
reject = beos_BUTTON(glade_xml_get_widget(x, "sslreject"));
g_signal_connect(G_OBJECT(accept), "clicked",
G_CALLBACK(nsbeos_ssl_accept), (gpointer)session);
g_signal_connect(G_OBJECT(reject), "clicked",
G_CALLBACK(nsbeos_ssl_reject), (gpointer)session);
beos_widget_show(beos_WIDGET(wnd));
#endif
}
#if 0 /* GTK */
static void nsbeos_ssl_accept(beosButton *w, gpointer data)
{
void **session = data;
struct browser_window *bw = session[0];
char *url = session[1];
GladeXML *x = session[2];
beosWindow *wnd = session[3];
urldb_set_cert_permissions(url, true);
browser_window_go(bw, url, 0, true);
beos_widget_destroy(beos_WIDGET(wnd));
g_object_unref(G_OBJECT(x));
free(url);
free(session);
}
static void nsbeos_ssl_reject(beosButton *w, gpointer data)
{
void **session = data;
GladeXML *x = session[2];
beosWindow *wnd = session[3];
beos_widget_destroy(beos_WIDGET(wnd));
g_object_unref(G_OBJECT(x));
free(session[1]);
free(session);
}
#endif
utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len,
char **result)
{
assert(string && result);
if (len == 0)
len = strlen(string);
*result = strndup(string, len);
if (!(*result))
return UTF8_CONVERT_NOMEM;
return UTF8_CONVERT_OK;
}
utf8_convert_ret utf8_from_local_encoding(const char *string, size_t len,
char **result)
{
assert(string && result);
if (len == 0)
len = strlen(string);
*result = strndup(string, len);
if (!(*result))
return UTF8_CONVERT_NOMEM;
return UTF8_CONVERT_OK;
}
char *path_to_url(const char *path)
{
char *r = (char *)malloc(strlen(path) + FILE_SCHEME_PREFIX_LEN + 1);
strcpy(r, FILE_SCHEME_PREFIX);
strcat(r, path);
return r;
}
char *url_to_path(const char *url)
{
return strdup(url + FILE_SCHEME_PREFIX_LEN);
}
bool cookies_update(const char *domain, const struct cookie_data *data)
{
return true;
}
static void *myrealloc(void *ptr, size_t len, void *pw)
{
if (len == 0) {
free(ptr);
return NULL;
}
return realloc(ptr, len);
}
/**
* Return the filename part of a full path
*
* \param path full path and filename
* \return filename (will be freed with free())
*/
char *filename_from_path(char *path)
{
char *leafname;
leafname = strrchr(path, '/');
if (!leafname)
leafname = path;
else
leafname += 1;
return strdup(leafname);
}
/**
* Add a path component/filename to an existing path
*
* \param path buffer containing path + free space
* \param length length of buffer "path"
* \param newpart string containing path component to add to path
* \return true on success
*/
bool path_add_part(char *path, int length, const char *newpart)
{
if(path[strlen(path) - 1] != '/')
strncat(path, "/", length);
strncat(path, newpart, length);
return true;
}