/* * Copyright 2008 François Revol * Copyright 2006 Daniel Silverstone * 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 extern "C" { #include "desktop/browser.h" #include "desktop/options.h" #include "desktop/textinput.h" #undef NDEBUG #include "utils/log.h" #include "utils/utils.h" } #include "beos/beos_window.h" #include "beos/beos_gui.h" #include "beos/beos_scaffolding.h" #include "beos/beos_plotters.h" //#include "beos/beos_schedule.h" #include #include #include #include #include #include #include #include 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; /* 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 vint32 pending_resizes; // accumulated rects of pending redraws //volatile BMessage *lastRedraw; // UNUSED YET BRect pendingRedraw; #if 0 /* GTK */ /* Within GTK, a gui_window is a scrolled window * with a viewport inside * with a gtkfixed in that * with a drawing area in that * The scrolled window is optional and only chosen * for frames which need it. Otherwise we just use * a viewport. */ GtkScrolledWindow *scrolledwindow; GtkViewport *viewport; GtkFixed *fixed; GtkDrawingArea *drawing_area; #endif /* Keep gui_windows in a list for cleanup later */ struct gui_window *next, *prev; }; static const rgb_color kWhiteColor = {255, 255, 255, 255}; static struct gui_window *window_list = 0; /**< first entry in win list*/ static void nsbeos_gui_window_attach_child(struct gui_window *parent, struct gui_window *child); /* 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); #if 0 /* GTK */ static GdkCursor *nsbeos_create_menu_cursor(void); #endif // #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 /*| B_SUBPIXEL_PRECISE*/), fGuiWindow(gui) { } NSBrowserFrameView::~NSBrowserFrameView() { } void NSBrowserFrameView::MessageReceived(BMessage *message) { switch (message->what) { case B_SIMPLE_DATA: case B_REFS_RECEIVED: message->PrintToStream(); //case B_MOUSE_WHEEL_CHANGED: // messages for top-level case 'back': case 'forw': case 'stop': case 'relo': case 'home': case 'urlc': case 'urle': case 'menu': Window()->DetachCurrentMessage(); nsbeos_pipe_message_top(message, NULL, fGuiWindow->scaffold); break; default: 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); } #if 0 void NSBrowserFrameView::FrameMoved(BPoint new_location) { 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::FrameMoved(new_location); } #endif 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); BView::MouseUp(where); } 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->bw->scale; } /* Create a gui_window */ struct gui_window *gui_create_browser_window(struct browser_window *bw, struct browser_window *clone, bool new_tab) { struct gui_window *g; /**< what we're creating to return */ g = (struct gui_window *)malloc(sizeof(*g)); if (!g) { warn_user("NoMemory", 0); return 0; } LOG(("Creating gui window %p for browser window %p", g, bw)); g->bw = bw; g->current_pointer = GUI_POINTER_DEFAULT; if (clone != NULL) bw->scale = clone->scale; else bw->scale = (float) option_scale / 100; 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; if (bw->parent != NULL) { /* Find our parent's scaffolding */ g->scaffold = bw->parent->window->scaffold; } else { /* Now construct and attach a scaffold */ g->scaffold = nsbeos_new_scaffolding(g); } /* 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); g->view->SetHighColor(kWhiteColor); if (bw->parent != NULL ) { g->toplevel = false; // XXX handle scrollview later //g->scrollview = new BScrollView(g->view); /* Attach ourselves into our parent at the right point */ nsbeos_gui_window_attach_child(bw->parent->window, g); } else { g->toplevel = true; /* Attach our viewport into the scaffold */ nsbeos_attach_toplevel_view(g->scaffold, g->view); } #warning WRITEME #if 0 /* GTK */ GtkPolicyType scrollpolicy; /* Construct our primary elements */ g->fixed = GTK_FIXED(gtk_fixed_new()); g->drawing_area = GTK_DRAWING_AREA(gtk_drawing_area_new()); gtk_fixed_put(g->fixed, GTK_WIDGET(g->drawing_area), 0, 0); gtk_container_set_border_width(GTK_CONTAINER(g->fixed), 0); if (bw->parent != NULL ) { g->scrolledwindow = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); gtk_scrolled_window_add_with_viewport(g->scrolledwindow, GTK_WIDGET(g->fixed)); gtk_scrolled_window_set_shadow_type(g->scrolledwindow, GTK_SHADOW_NONE); g->viewport = GTK_VIEWPORT(gtk_bin_get_child(GTK_BIN(g->scrolledwindow))); /* Attach ourselves into our parent at the right point */ nsbeos_gui_window_attach_child(bw->parent->window, g); } else { g->scrolledwindow = 0; g->viewport = GTK_VIEWPORT(gtk_viewport_new(NULL, NULL)); /* Need to attach adjustments */ gtk_container_add(GTK_CONTAINER(g->viewport), GTK_WIDGET(g->fixed)); /* Attach our viewport into the scaffold */ nsbeos_attach_toplevel_viewport(g->scaffold, g->viewport); } gtk_container_set_border_width(GTK_CONTAINER(g->viewport), 0); gtk_viewport_set_shadow_type(g->viewport, GTK_SHADOW_NONE); if (g->scrolledwindow) gtk_widget_show(GTK_WIDGET(g->scrolledwindow)); /* And enable visibility from our viewport down */ gtk_widget_show(GTK_WIDGET(g->viewport)); gtk_widget_show(GTK_WIDGET(g->fixed)); gtk_widget_show(GTK_WIDGET(g->drawing_area)); switch(bw->scrolling) { case SCROLLING_NO: scrollpolicy = GTK_POLICY_NEVER; break; case SCROLLING_YES: scrollpolicy = GTK_POLICY_ALWAYS; break; case SCROLLING_AUTO: default: scrollpolicy = GTK_POLICY_AUTOMATIC; break; }; switch(bw->browser_window_type) { case BROWSER_WINDOW_FRAMESET: if (g->scrolledwindow) gtk_scrolled_window_set_policy(g->scrolledwindow, GTK_POLICY_NEVER, GTK_POLICY_NEVER); break; case BROWSER_WINDOW_FRAME: if (g->scrolledwindow) gtk_scrolled_window_set_policy(g->scrolledwindow, scrollpolicy, scrollpolicy); break; case BROWSER_WINDOW_NORMAL: if (g->scrolledwindow) gtk_scrolled_window_set_policy(g->scrolledwindow, scrollpolicy, scrollpolicy); break; case BROWSER_WINDOW_IFRAME: if (g->scrolledwindow) gtk_scrolled_window_set_policy(g->scrolledwindow, scrollpolicy, scrollpolicy); break; } /* set the events we're interested in receiving from the browser's * drawing area. */ gtk_widget_add_events(GTK_WIDGET(g->drawing_area), GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); GTK_WIDGET_SET_FLAGS(GTK_WIDGET(g->drawing_area), GTK_CAN_FOCUS); /* set the default background colour of the drawing area to white. */ gtk_widget_modify_bg(GTK_WIDGET(g->drawing_area), GTK_STATE_NORMAL, &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); #define CONNECT(obj, sig, callback, ptr) \ g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) CONNECT(g->drawing_area, "expose_event", nsgtk_window_expose_event, g); CONNECT(g->drawing_area, "motion_notify_event", nsgtk_window_motion_notify_event, g); CONNECT(g->drawing_area, "button_press_event", nsgtk_window_button_press_event, g); CONNECT(g->drawing_area, "key_press_event", nsgtk_window_keypress_event, g); CONNECT(g->viewport, "size_allocate", nsgtk_window_size_allocate_event, g); #endif return g; } static void nsbeos_gui_window_attach_child(struct gui_window *parent, struct gui_window *child) { /* Attach the child gui_window (frame) into the parent. * It will be resized later on. */ if (parent->view == NULL || child->view == NULL) return; if (!parent->view->LockLooper()) return; //if (child->scrollview) // parent->view->AddChild(child->scrollview); //else parent->view->AddChild(child->view); // non-top-level views shouldn't resize automatically (?) child->view->SetResizingMode(B_FOLLOW_NONE); parent->view->UnlockLooper(); #warning WRITEME #if 0 /* GTK */ /* Attach the child gui_window (frame) into the parent. * It will be resized later on. */ GtkFixed *parent_fixed = parent->fixed; GtkWidget *child_widget = GTK_WIDGET(child->scrolledwindow); gtk_fixed_put(parent_fixed, child_widget, 0, 0); #endif } void gui_window_position_frame(struct gui_window *g, int x0, int y0, int x1, int y1) { CALLED(); /* g is a child frame, we need to place it relative to its parent */ #warning XXX: BScrollView ? BView *view = g->view; BView *parent = g->bw->parent->window->view; assert(view); assert(parent); LOG(("%s: %d,%d %dx%d", g->bw->name, x0, y0, x1-x0+2, y1-y0+2)); /* if the window has not changed position or size, do not bother * moving/resising it. */ if (!parent->LockLooper()) return; LOG((" current: %d,%d %dx%d", view->Frame().left, view->Frame().top, view->Frame().Width() + 1, view->Frame().Height() + 1)); if (view->Frame().left != x0 || view->Frame().top != y0 || view->Frame().Width() + 1 != x1 - x0 + 2 || view->Frame().Height() + 1 != y1 - y0 + 2) { LOG((" frame has moved/resized.")); view->MoveTo(x0, y0); view->ResizeTo(x1 - x0 + 2 - 1, y1 - y0 + 2 - 1); } parent->UnlockLooper(); #warning WRITEME #if 0 /* GTK */ /* g is a child frame, we need to place it relative to its parent */ GtkWidget *w = GTK_WIDGET(g->scrolledwindow); GtkFixed *f = g->bw->parent->window->fixed; assert(w); assert(f); LOG(("%s: %d,%d %dx%d", g->bw->name, x0, y0, x1-x0+2, y1-y0+2)); /* if the window has not changed position or size, do not bother * moving/resising it. */ LOG((" current: %d,%d %dx%d", w->allocation.x, w->allocation.y, w->allocation.width, w->allocation.height)); if (w->allocation.x != x0 || w->allocation.y != y0 || w->allocation.width != x1 - x0 + 2 || w->allocation.height != y1 - y0 + 2) { LOG((" frame has moved/resized.")); gtk_fixed_move(f, w, x0, y0); gtk_widget_set_size_request(w, x1 - x0 + 2, y1 - y0 + 2); } #endif } 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")); return; } if (scaffold && (!y || scaffold != y->scaffold)) { LOG(("discarding event for destroyed scaffolding")); return; } //#warning XXX VALIDATE gui_window!!! // messages for top-level if (scaffold) { LOG(("dispatching to top-level")); nsbeos_scaffolding_dispatch_event(scaffold, message); delete message; return; } switch (message->what) { case B_QUIT_REQUESTED: // from the BApplication netsurf_quit = true; break; case _UPDATE_: if (gui && view) nsbeos_window_expose_event(view, gui, message); break; case B_MOUSE_MOVED: { if (gui == NULL) break; BPoint where; // 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; } browser_window_mouse_track(gui->bw, (browser_mouse_state)0, (int)(where.x / gui->bw->scale), (int)(where.y / gui->bw->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; 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; browser_mouse_state button = BROWSER_MOUSE_CLICK_1; if (buttons & B_TERTIARY_MOUSE_BUTTON) /* 3 == middle button on BeOS */ button = BROWSER_MOUSE_CLICK_2; if (buttons & B_SECONDARY_MOUSE_BUTTON) { /* 2 == right button on BeOS */ nsbeos_scaffolding_popup_menu(gui->scaffold, screenWhere); break; } browser_window_mouse_click(gui->bw, button, (int)(where.x / gui->bw->scale), (int)(where.y / gui->bw->scale)); if (view && view->LockLooper()) { view->MakeFocus(); view->UnlockLooper(); } 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: default: break; } delete message; } void nsbeos_window_expose_event(BView *view, gui_window *g, BMessage *message) { BRect updateRect; struct content *c; float scale = g->bw->scale; 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); if (message->FindRect("rect", &updateRect) < B_OK) return; c = g->bw->current_content; if (c == NULL) return; /* HTML rendering handles scale itself */ if (c->type == CONTENT_HTML) scale = 1; if (!view->LockLooper()) return; nsbeos_current_gc_set(view); plot = nsbeos_plotters; nsbeos_plot_set_scale(g->bw->scale); content_redraw(c, 0, 0, (view->Bounds().Width() + 1) * scale, (view->Bounds().Height() + 1) * scale, updateRect.left, updateRect.top, updateRect.right, updateRect.bottom, g->bw->scale, 0xFFFFFF); if (g->careth != 0) nsbeos_plot_caret(g->caretx, g->carety, g->careth); // 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); 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 = KEY_DELETE_LEFT; break; case B_TAB: nskey = 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 = KEY_DELETE_RIGHT; break; /* case B_INSERT: nskey = KEYSYM("insert"); break; */ case B_HOME: nskey = KEY_LINE_START; break; // XXX ? case B_END: nskey = KEY_LINE_END; break; // XXX ? case B_PAGE_UP: nskey = KEY_PAGE_UP; break; case B_PAGE_DOWN: nskey = KEY_PAGE_DOWN; break; case B_LEFT_ARROW: nskey = KEY_LEFT; break; case B_RIGHT_ARROW: nskey = KEY_RIGHT; break; case B_UP_ARROW: nskey = KEY_UP; break; case B_DOWN_ARROW: nskey = 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 { // XXX is raw_char actually UCS ?? nskey = (uint32_t)raw_char; // else use convert_from_utf8() } if (browser_window_key_press(g->bw, nskey)) return; } #warning WRITEME #if 0 /* GTK */ gboolean nsbeos_window_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_window *g = data; uint32_t nskey = gdkkey_to_nskey(event); if (browser_window_key_press(g->bw, nskey)) return TRUE; if (event->state == 0) { double value; GtkAdjustment *vscroll = gtk_viewport_get_vadjustment(g->viewport); GtkAdjustment *hscroll = gtk_viewport_get_hadjustment(g->viewport); GtkAdjustment *scroll; const GtkAllocation *const alloc = >K_WIDGET(g->viewport)->allocation; switch (event->keyval) { default: return TRUE; case GDK_Home: case GDK_KP_Home: scroll = vscroll; value = scroll->lower; break; case GDK_End: case GDK_KP_End: scroll = vscroll; value = scroll->upper - alloc->height; if (value < scroll->lower) value = scroll->lower; break; case GDK_Left: case GDK_KP_Left: scroll = hscroll; value = gtk_adjustment_get_value(scroll) - scroll->step_increment; if (value < scroll->lower) value = scroll->lower; break; case GDK_Up: case GDK_KP_Up: scroll = vscroll; value = gtk_adjustment_get_value(scroll) - scroll->step_increment; if (value < scroll->lower) value = scroll->lower; break; case GDK_Right: case GDK_KP_Right: scroll = hscroll; value = gtk_adjustment_get_value(scroll) + scroll->step_increment; if (value > scroll->upper - alloc->width) value = scroll->upper - alloc->width; break; case GDK_Down: case GDK_KP_Down: scroll = vscroll; value = gtk_adjustment_get_value(scroll) + scroll->step_increment; if (value > scroll->upper - alloc->height) value = scroll->upper - alloc->height; break; case GDK_Page_Up: case GDK_KP_Page_Up: scroll = vscroll; value = gtk_adjustment_get_value(scroll) - scroll->page_increment; if (value < scroll->lower) value = scroll->lower; break; case GDK_Page_Down: case GDK_KP_Page_Down: scroll = vscroll; value = gtk_adjustment_get_value(scroll) + scroll->page_increment; if (value > scroll->upper - alloc->height) value = scroll->upper - alloc->height; break; } gtk_adjustment_set_value(scroll, value); } return TRUE; } #endif 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 1 if (atomic_add(&g->pending_resizes, -1) > 1) return; #endif if (event->FindInt32("width", &width) < B_OK) width = -1; if (event->FindInt32("height", &height) < B_OK) height = -1; width++; height++; #if 0 struct content *content; content = g->bw->current_content; /* reformat or change extent if necessary */ if ((content) && (g->old_width != width || g->old_height != height)) { /* Ctrl-resize of a top-level window scales the content size */ #if 0 if ((g->old_width > 0) && (g->old_width != width) && (!g->bw->parent) && (ro_gui_ctrl_pressed())) new_scale = (g->bw->scale * width) / g->old_width; #endif g->bw->reformat_pending = true; browser_reformat_pending = true; } if (g->update_extent || g->old_width != width || g->old_height != height) { g->old_width = width; g->old_height = height; g->update_extent = false; gui_window_set_extent(g, width, height); } #endif g->bw->reformat_pending = true; browser_reformat_pending = true; 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(); //g->bw->reformat_pending = true; //browser_reformat_pending = true; return; } void nsbeos_reflow_all_windows(void) { for (struct gui_window *g = window_list; g; g = g->next) g->bw->reformat_pending = true; browser_reformat_pending = true; } /** * Process pending reformats */ void nsbeos_window_process_reformats(void) { struct gui_window *g; browser_reformat_pending = false; for (g = window_list; g; g = g->next) { NSBrowserFrameView *view = g->view; if (!g->bw->reformat_pending) continue; if (!view || !view->LockLooper()) continue; g->bw->reformat_pending = false; BRect bounds = view->Bounds(); view->UnlockLooper(); #warning XXX why - 1 & - 2 !??? browser_window_reformat(g->bw, bounds.Width() + 1 - 1 /* - 2*/, bounds.Height() + 1 - 1); } #warning WRITEME #if 0 /* GTK */ for (g = window_list; g; g = g->next) { GtkWidget *widget = GTK_WIDGET(g->viewport); if (!g->bw->reformat_pending) continue; g->bw->reformat_pending = false; browser_window_reformat(g->bw, widget->allocation.width - 2, widget->allocation.height); } #endif } void nsbeos_window_destroy_browser(struct gui_window *g) { browser_window_destroy(g->bw); } void gui_window_destroy(struct gui_window *g) { 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)); LOG((" Window name: %s", g->bw->name)); 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(); #warning FIXME #if 0 /* GTK */ /* If we're a top-level gui_window, destroy our scaffold */ if (g->scrolledwindow == NULL) { gtk_widget_destroy(GTK_WIDGET(g->viewport)); nsgtk_scaffolding_destroy(g->scaffold); } else { gtk_widget_destroy(GTK_WIDGET(g->scrolledwindow)); } #endif free(g); } void nsbeos_redraw_caret(struct gui_window *g) { if (g->careth == 0) return; gui_window_redraw(g, g->caretx, g->carety, g->caretx, g->carety + g->careth); } void gui_window_redraw(struct gui_window *g, int x0, int y0, int x1, int y1) { if (g->view == NULL) return; if (!g->view->LockLooper()) return; nsbeos_current_gc_set(g->view); //XXX +1 ?? g->view->Invalidate(BRect(x0, y0, x1, y1)); nsbeos_current_gc_set(NULL); g->view->UnlockLooper(); } 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(); } void gui_window_update_box(struct gui_window *g, const union content_msg_data *data) { struct content *c = g->bw->current_content; if (c == NULL) return; if (g->view == NULL) return; if (!g->view->LockLooper()) return; nsbeos_current_gc_set(g->view); //XXX +1 ?? g->view->Invalidate(BRect(data->redraw.x, data->redraw.y, data->redraw.x + data->redraw.width - 1, data->redraw.y + data->redraw.height - 1)); nsbeos_current_gc_set(NULL); g->view->UnlockLooper(); } 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(); #warning WRITEME #if 0 /* GTK */ GtkAdjustment *vadj = gtk_viewport_get_vadjustment(g->viewport); GtkAdjustment *hadj = gtk_viewport_get_hadjustment(g->viewport); assert(vadj); assert(hadj); *sy = (int)(gtk_adjustment_get_value(vadj)); *sx = (int)(gtk_adjustment_get_value(hadj)); #endif return true; } 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(); #warning WRITEME #if 0 /* GTK */ GtkAdjustment *vadj = gtk_viewport_get_vadjustment(g->viewport); GtkAdjustment *hadj = gtk_viewport_get_hadjustment(g->viewport); gdouble vlower, vpage, vupper, hlower, hpage, hupper, x = (double)sx, y = (double)sy; assert(vadj); assert(hadj); g_object_get(vadj, "page-size", &vpage, "lower", &vlower, "upper", &vupper, NULL); g_object_get(hadj, "page-size", &hpage, "lower", &hlower, "upper", &hupper, NULL); if (x < hlower) x = hlower; if (x > (hupper - hpage)) x = hupper - hpage; if (y < vlower) y = vlower; if (y > (vupper - vpage)) y = vupper - vpage; gtk_adjustment_set_value(vadj, y); gtk_adjustment_set_value(hadj, x); #endif } /** * Set the scale setting of a window * * \param g gui window * \param scale scale value (1.0 == normal scale) */ void gui_window_set_scale(struct gui_window *g, float scale) { } void gui_window_update_extent(struct gui_window *g) { CALLED(); if (!g->bw->current_content) return; if (g->view == NULL) return; if (!g->view->LockLooper()) return; float x_max = g->bw->current_content->width * g->bw->scale /* - 1*/; float y_max = g->bw->current_content->height * g->bw->scale /* - 1*/; 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; printf("x_max = %f y_max = %f 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); } #if 0 g->view->ResizeTo( g->bw->current_content->width * g->bw->scale /* - 1*/, g->bw->current_content->height * g->bw->scale /* - 1*/); #endif g->view->UnlockLooper(); #warning WRITEME #if 0 /* GTK */ gtk_widget_set_size_request(GTK_WIDGET(g->drawing_area), g->bw->current_content->width * g->bw->scale, g->bw->current_content->height * g->bw->scale); gtk_widget_set_size_request(GTK_WIDGET(g->viewport), 0, 0); #endif } /* 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 }; #if 0 /* GTK */ static GdkCursor *nsbeos_create_menu_cursor(void) { static char menu_cursor_bits[] = { 0x00, 0x00, 0x80, 0x7F, 0x88, 0x40, 0x9E, 0x5E, 0x88, 0x40, 0x80, 0x56, 0x80, 0x40, 0x80, 0x5A, 0x80, 0x40, 0x80, 0x5E, 0x80, 0x40, 0x80, 0x56, 0x80, 0x40, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, }; static char menu_cursor_mask_bits[] = { 0xC0, 0xFF, 0xC8, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xC8, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0x00, 0x00, }; static GdkCursor *r; static GdkColor fg = { 0, 0, 0, 0 }; static GdkColor bg = { 0, 65535, 65535, 65535 }; GdkPixmap *source, *mask; if (r != NULL) return r; source = gdk_bitmap_create_from_data(NULL, menu_cursor_bits, 16, 16); mask = gdk_bitmap_create_from_data (NULL, menu_cursor_mask_bits, 16, 16); r = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 8, 8); gdk_pixmap_unref(source); gdk_pixmap_unref(mask); return r; } #endif 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; #if 0 // it's ugly anyway #ifdef B_ZETA_VERSION cursor = (BCursor *)B_CURSOR_LINK; #endif #endif 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; #if 0 /* GTK */ case GUI_POINTER_UP: cursortype = GDK_TOP_SIDE; break; case GUI_POINTER_DOWN: cursortype = GDK_BOTTOM_SIDE; break; case GUI_POINTER_LEFT: cursortype = GDK_LEFT_SIDE; break; case GUI_POINTER_RIGHT: cursortype = GDK_RIGHT_SIDE; break; case GUI_POINTER_LD: cursortype = GDK_BOTTOM_LEFT_CORNER; break; case GUI_POINTER_RD: cursortype = GDK_BOTTOM_RIGHT_CORNER; break; case GUI_POINTER_LU: cursortype = GDK_TOP_LEFT_CORNER; break; case GUI_POINTER_RU: cursortype = GDK_TOP_RIGHT_CORNER; break; case GUI_POINTER_CROSS: cursortype = GDK_CROSS; break; case GUI_POINTER_MOVE: cursortype = GDK_FLEUR; break; case GUI_POINTER_WAIT: cursortype = GDK_WATCH; break; case GUI_POINTER_HELP: cursortype = GDK_QUESTION_ARROW; break; case GUI_POINTER_MENU: cursor = nsbeos_create_menu_cursor(); nullcursor = true; break; case GUI_POINTER_PROGRESS: /* In reality, this needs to be the funky left_ptr_watch * which we can't do easily yet. */ cursortype = GDK_WATCH; break; /* The following we're not sure about */ case GUI_POINTER_NO_DROP: case GUI_POINTER_NOT_ALLOWED: case GUI_POINTER_DEFAULT: #endif 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; } void gui_window_hide_pointer(struct gui_window *g) { //XXX no BView::HideCursor... use empty one } void gui_window_place_caret(struct gui_window *g, int x, int y, int height) { 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(); } void gui_window_remove_caret(struct gui_window *g) { int oh = g->careth; if (oh == 0) return; g->careth = 0; gui_window_redraw(g, g->caretx, g->carety, g->caretx, g->carety + oh); } 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(); } bool gui_window_scroll_start(struct gui_window *g) { return true; } bool gui_window_box_scroll_start(struct gui_window *g, int x0, int y0, int x1, int y1) { return true; } void gui_drag_save_object(gui_save_type type, struct content *c, struct gui_window *g) { } void gui_drag_save_selection(struct selection *s, struct gui_window *g) { } void gui_start_selection(struct gui_window *g) { } void gui_paste_from_clipboard(struct gui_window *g, int x, int y) { } bool gui_empty_clipboard(void) { return true; } bool gui_add_to_clipboard(const char *text, size_t length, bool space) { return true; } bool gui_commit_clipboard(void) { return true; } bool gui_copy_to_clipboard(struct selection *s) { return true; } 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->bw->scale; *height /= g->bw->scale; } } bool gui_window_frame_resize_start(struct gui_window *g) { return true; }