summaryrefslogtreecommitdiff
path: root/frontends/beos/window.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/beos/window.cpp')
-rw-r--r--frontends/beos/window.cpp1382
1 files changed, 1382 insertions, 0 deletions
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;