/* * Copyright 2015 Adrián Arroyo Calle * Copyright 2008 François Revol * Copyright 2006 Rob Kendrick * * 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 . */ #define __STDBOOL_H__ 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__HAIKU__) #include #include "WindowStack.h" #endif #include extern "C" { #include "utils/messages.h" #include "utils/utils.h" #include "utils/log.h" #include "utils/nsurl.h" #include "utils/nsoption.h" #include "netsurf/netsurf.h" #include "netsurf/plotters.h" #include "netsurf/clipboard.h" #include "netsurf/content.h" #include "netsurf/content_type.h" #include "netsurf/browser_window.h" #include "netsurf/form.h" #include "netsurf/keypress.h" #include "desktop/browser_history.h" #include "desktop/version.h" #include "desktop/searchweb.h" #include "desktop/search.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; /** Object under menu, or 0 if no object. */ struct hlcache_handle *current_menu_object; }; 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) { delete info; 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: // 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_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) { NSLOG(netsurf, INFO, "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; NSLOG(netsurf, INFO, "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: NSLOG(netsurf, INFO, "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: if (scaffold->current_menu_object != NULL) { content_invalidate_reuse_data(scaffold->current_menu_object); browser_window_reload(bw, false); scaffold->current_menu_object = NULL; } 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) { NSLOG(netsurf, INFO, "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(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) { NSLOG(netsurf, INFO, "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); recursively_set_menu_items_target(g->popup_menu, view); 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 accelKey(name); accelKey += "Accel"; BString accel(messages_get(accelKey)); if (accel == accelKey) accel = ""; uint32 mods = 0; char key = 0; // try to understand accelerators if (!accel.IsEmpty()) { 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; } if (accel.FindFirst("PRINT") > -1) { accel.RemoveFirst("PRINT"); //mods |= ; // ALT!!! key = B_PRINT_KEY; } /* replace UTF-8 glyphs (arrows...) with API codes */ accel.ReplaceAll("\xE2\x86\x90", (BString()+=B_LEFT_ARROW).String()); accel.ReplaceAll("\xE2\x86\x92", (BString()+=B_RIGHT_ARROW).String()); accel.ReplaceAll("\xE2\x86\x91", (BString()+=B_UP_ARROW).String()); 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)); NSLOG(netsurf, INFO, "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; BMenuItem *item; 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 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; // 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("popup", false, false); #if 0 message = new BMessage(BROWSER_OBJECT_INFO); item = make_menu_item("ObjInfo", message); g->popup_menu->AddItem(item); message = new BMessage(BROWSER_OBJECT_SAVE); item = make_menu_item("ObjSave", message); g->popup_menu->AddItem(item); // XXX: submenu: Sprite ? #endif message = new BMessage(BROWSER_OBJECT_RELOAD); item = make_menu_item("ObjReload", message, true); g->popup_menu->AddItem(item); #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 *scaffold, struct browser_window *bw, BPoint where, BPoint screenWhere) { struct browser_window_features cont; browser_window_get_features(bw, (int)where.x, (int)where.y, &cont); scaffold->current_menu_object = cont.object; bool enabled = !!scaffold->current_menu_object; for (int i = 0; scaffold->popup_menu->ItemAt(i); i++) { scaffold->popup_menu->ItemAt(i)->SetEnabled(enabled); } scaffold->popup_menu->Go(screenWhere, true, false, true); }